Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

780 lines
18 KiB

  1. /******************************************************************************
  2. * usearch.cpp *
  3. *-------------*
  4. * I/O library functions for extended speech files (vapi format)
  5. *------------------------------------------------------------------------------
  6. * Copyright (C) 1997 Entropic Research Laboratory, Inc.
  7. * Copyright (C) 1998 Entropic, Inc.
  8. * Copyright (C) 2000 Microsoft Corporation Date: 03/21/00
  9. * All Rights Reserved
  10. *
  11. ********************************************************************* PACOG ***/
  12. #include "backend.h"
  13. #include "beVersion.h"
  14. #include "getopt.h"
  15. #include <ctype.h>
  16. #include <math.h>
  17. #include <malloc.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #include <assert.h>
  21. #define SYNTAX fprintf(stderr,\
  22. "Usage:\nusearch [-f f0wght] [-d durwght] [-r rmswght] [-l lklwght] [-c contwght]\n\
  23. \t[-m SameSegWght] [-s (dynsearch)] [-b (blend)] [-g (gain)] \n\
  24. \t[-t (targetF0)] [-x cros_ref] [-S script_file] table_file \n\
  25. \t[ifile] [ofile]\n")
  26. #define MAX_LINE 128
  27. #define MAX_SENT_PHONES 500
  28. #define CHUNK_ALLOC_INCR 1000
  29. enum {
  30. GOT_F0_WEIGHT=1,
  31. GOT_RMS_WEIGHT=2,
  32. GOT_DUR_WEIGHT=4,
  33. GOT_LKLH_WEIGHT=8,
  34. GOT_CONT_WEIGHT=16,
  35. GOT_SAME_WEIGHT=32
  36. };
  37. /*
  38. *
  39. */
  40. struct NamePair {
  41. char in[_MAX_PATH+1];
  42. char out[_MAX_PATH+1];
  43. };
  44. class Crf
  45. {
  46. public:
  47. Crf();
  48. ~Crf();
  49. int Load (const char* fileName);
  50. const char* FileName(int i);
  51. double Offset (int i);
  52. private:
  53. struct CrfInfo {
  54. char* fileName;
  55. double offset;
  56. } *m_pChunks;
  57. int m_iNumChunks;
  58. int m_iNumAlloc;
  59. };
  60. struct InputInfo {
  61. char tableFile[_MAX_PATH+1];
  62. char crfFile[_MAX_PATH+1];
  63. char scriptFile[_MAX_PATH+1];
  64. char input[_MAX_PATH+1];
  65. char output[_MAX_PATH+1];
  66. int slmOptions;
  67. float f0Wt;
  68. float durWt;
  69. float rmsWt;
  70. float lklWt;
  71. float contWt;
  72. float sameSeg;
  73. int setWeights;
  74. };
  75. /*
  76. *
  77. */
  78. static int ProcessCommandLine (int argc, char *argv[], InputInfo* inInfo);
  79. static int GetIoNames (InputInfo* inInfo, NamePair** names, int* nNames);
  80. static int ReadScriptLine (FILE* script, char* inFile, char* outFile);
  81. static int OpenInputFile (const char* fileName, FILE** fp, double *time);
  82. static int OpenOutputFile (const char* fileName, double startTime, FILE** fp);
  83. static int GetInputPhone (FILE* fp, double* time, char* phone, short* f0, int* sentenceEnd);
  84. /*****************************************************************************
  85. * main *
  86. *------*
  87. * Description:
  88. *
  89. ******************************************************************* PACOG ***/
  90. int main (int argc, char *argv[])
  91. {
  92. InputInfo inInfo;
  93. CSlm* slm = 0;
  94. Crf crf;
  95. NamePair* fileNames = 0;
  96. int nFiles = 0;
  97. int fileCount;
  98. FILE *fin;
  99. FILE *fout;
  100. Phone phList[MAX_SENT_PHONES];
  101. int nPh;
  102. ChkDescript* newChunk = 0;
  103. int nNewChunks = 0;
  104. double startTime;
  105. double fTo;
  106. double fFrom;
  107. int sentenceEnd;
  108. const char* fName;
  109. int i;
  110. if (!ProcessCommandLine (argc, argv, &inInfo))
  111. {
  112. SYNTAX;
  113. return 1;
  114. }
  115. if (!GetIoNames (&inInfo, &fileNames, &nFiles))
  116. {
  117. fprintf (stderr, "Error loading input and output file names\n");
  118. return 1;
  119. }
  120. if ( (slm = CSlm::ClassFactory(inInfo.slmOptions)) == 0)
  121. {
  122. return 1;
  123. }
  124. if (!slm->Load(inInfo.tableFile, 1))
  125. {
  126. fprintf(stderr, "Error loading speaker info %s\n", inInfo.tableFile);
  127. return 1;
  128. }
  129. if (inInfo.setWeights & GOT_F0_WEIGHT)
  130. {
  131. slm->SetF0Weight( inInfo.f0Wt );
  132. }
  133. if (inInfo.setWeights & GOT_DUR_WEIGHT)
  134. {
  135. slm->SetDurWeight( inInfo.durWt );
  136. }
  137. if (inInfo.setWeights & GOT_RMS_WEIGHT)
  138. {
  139. slm->SetRmsWeight( inInfo.rmsWt );
  140. }
  141. if (inInfo.setWeights & GOT_LKLH_WEIGHT)
  142. {
  143. slm->SetLklWeight( inInfo.lklWt );
  144. }
  145. if (inInfo.setWeights & GOT_CONT_WEIGHT)
  146. {
  147. slm->SetContWeight( inInfo.contWt );
  148. }
  149. if (inInfo.setWeights & GOT_SAME_WEIGHT)
  150. {
  151. slm->SetSameSegWeight( inInfo.sameSeg );
  152. }
  153. /*
  154. * If we override the weights, we need to
  155. * precompute the distances again
  156. * (done by default within Slm_Load())
  157. */
  158. if (inInfo.setWeights)
  159. {
  160. slm->PreComputeDist();
  161. }
  162. /* if (Slm_GetFileName(slm, 0) == 0 && inInfo.crfFile[0]=='\0')
  163. {
  164. fprintf(stderr, "Error: Either use a table with file names or provide cross_ref file\n");
  165. return 1;
  166. }
  167. */
  168. if ( inInfo.crfFile[0] && !crf.Load(inInfo.crfFile) )
  169. {
  170. printf("Error opening CRF file %s\n", inInfo.crfFile);
  171. return 1;
  172. }
  173. for (fileCount = 0; fileCount < nFiles; fileCount ++)
  174. {
  175. fprintf (stdout, "%s %s\n", fileNames[fileCount].in, fileNames[fileCount].out);
  176. fflush (stdout);
  177. if (!OpenInputFile(fileNames[fileCount].in, &fin, &startTime))
  178. {
  179. printf("Error opening input file %s\n", fileNames[fileCount].in);
  180. return 1;
  181. }
  182. if (!OpenOutputFile(fileNames[fileCount].out, startTime, &fout))
  183. {
  184. printf("Error opening output file %s\n", fileNames[fileCount].out);
  185. return 1;
  186. }
  187. nPh = 0;
  188. while (GetInputPhone(fin, &phList[nPh].end, phList[nPh].phone, &phList[nPh].f0, &sentenceEnd))
  189. {
  190. nPh++;
  191. if ( sentenceEnd && (nPh>1))
  192. {
  193. if ((nNewChunks = slm->Process (phList, nPh, startTime)) == 0)
  194. {
  195. fprintf (stderr, "Slm error while processing %s\n", fileNames[fileCount].in);
  196. break;
  197. }
  198. startTime = phList[nPh-1].end;
  199. // Print results of slm Search
  200. for (i=0; i<nNewChunks; i++)
  201. {
  202. newChunk = slm->GetChunk(i);
  203. fFrom = newChunk->from;
  204. fTo = newChunk->to;
  205. if (newChunk->isFileName)
  206. {
  207. fName = newChunk->chunk.fileName;
  208. }
  209. else
  210. {
  211. fName = crf.FileName(newChunk->chunk.chunkIdx);
  212. fFrom += crf.Offset(newChunk->chunk.chunkIdx);
  213. fTo += crf.Offset(newChunk->chunk.chunkIdx);
  214. }
  215. fprintf(fout,"%f %s %s %lf %lf %f\n",
  216. newChunk->end, newChunk->name, fName, fFrom, fTo, newChunk->gain);
  217. }
  218. nPh=0;
  219. }
  220. }
  221. fclose(fin);
  222. fclose(fout);
  223. }
  224. if (fileNames)
  225. {
  226. free (fileNames);
  227. }
  228. delete slm;
  229. return 0;
  230. }
  231. /*****************************************************************************
  232. * Crf::Crf *
  233. *----------*
  234. * Description:
  235. *
  236. ******************************************************************* PACOG ***/
  237. Crf::Crf ()
  238. {
  239. m_pChunks = 0;
  240. m_iNumChunks = 0;
  241. m_iNumAlloc = 0;
  242. }
  243. /*****************************************************************************
  244. * Crf::~Crf *
  245. *-----------*
  246. * Description:
  247. *
  248. ******************************************************************* PACOG ***/
  249. Crf::~Crf ()
  250. {
  251. if (m_pChunks)
  252. {
  253. for (int i=0; i<m_iNumChunks; i++)
  254. {
  255. if (m_pChunks[i].fileName)
  256. {
  257. free (m_pChunks[i].fileName);
  258. }
  259. }
  260. free (m_pChunks);
  261. }
  262. }
  263. /*****************************************************************************
  264. * Crf::FileName *
  265. *---------------*
  266. * Description:
  267. *
  268. ******************************************************************* PACOG ***/
  269. const char* Crf::FileName(int i)
  270. {
  271. return m_pChunks[i].fileName;
  272. }
  273. /*****************************************************************************
  274. * Crf::Offset *
  275. *-------------*
  276. * Description:
  277. *
  278. ******************************************************************* PACOG ***/
  279. double Crf::Offset (int i)
  280. {
  281. return m_pChunks[i].offset;
  282. }
  283. /*****************************************************************************
  284. * Crf::Load *
  285. *-----------*
  286. * Description:
  287. * Load the cross reference file into the chunk cross reference structure
  288. ******************************************************************* PACOG ***/
  289. int Crf::Load (const char *fileName)
  290. {
  291. BendVersion bev;
  292. FILE* fp;
  293. int chunkIdx;
  294. char file[_MAX_PATH+1];
  295. double offset;
  296. if ((fp = fopen (fileName,"r")) == 0)
  297. {
  298. fprintf(stderr,"Can not open file %s\n", fileName);
  299. return 0;
  300. }
  301. if (!bev.CheckVersionString (fp))
  302. {
  303. fprintf (stderr, "Incompatible cross-reference file\n");
  304. return 0;
  305. }
  306. while (fscanf(fp,"%d %s %lf",&chunkIdx, file ,&offset)==3)
  307. {
  308. if (chunkIdx != m_iNumChunks)
  309. {
  310. fprintf(stderr, "Error loading chunk list from cross ref file\n");
  311. return 0;
  312. }
  313. if (m_iNumChunks == m_iNumAlloc)
  314. {
  315. if (m_pChunks)
  316. {
  317. m_pChunks = (CrfInfo* )realloc (m_pChunks, (m_iNumAlloc + CHUNK_ALLOC_INCR) * sizeof (*m_pChunks));
  318. }
  319. else
  320. {
  321. m_pChunks = (CrfInfo* )malloc (CHUNK_ALLOC_INCR * sizeof (*m_pChunks));
  322. }
  323. if (m_pChunks == 0)
  324. {
  325. fprintf(stderr,"Out of Memory\n");
  326. return 0;
  327. }
  328. m_iNumAlloc += CHUNK_ALLOC_INCR;
  329. }
  330. if ( (m_pChunks[m_iNumChunks].fileName = strdup (file)) == 0)
  331. {
  332. fprintf(stderr,"Out of Memory\n");
  333. return 0;
  334. }
  335. m_pChunks[m_iNumChunks].offset = offset;
  336. m_iNumChunks++;
  337. }
  338. fclose(fp);
  339. return 1;
  340. }
  341. /*****************************************************************************
  342. * OpenOutputFile *
  343. *----------------*
  344. * Description:
  345. *
  346. ******************************************************************* PACOG ***/
  347. int OpenOutputFile (const char* fileName, double startTime, FILE** fp)
  348. {
  349. char str[40];
  350. assert (fp);
  351. if (fileName)
  352. {
  353. if (strcmp(fileName,"-")==0)
  354. {
  355. *fp = stdout;
  356. }
  357. else
  358. {
  359. *fp = fopen (fileName, "w");
  360. if (*fp==0)
  361. {
  362. return 0;
  363. }
  364. }
  365. }
  366. else
  367. {
  368. *fp = 0;
  369. }
  370. sprintf (str, "#%f\n", startTime);
  371. if (*fp)
  372. {
  373. fprintf (*fp, str);
  374. }
  375. else
  376. {
  377. printf("%s\n",str);
  378. }
  379. return 1;
  380. }
  381. /*****************************************************************************
  382. * OpenInputFile *
  383. *---------------*
  384. * Description:
  385. *
  386. ******************************************************************* PACOG ***/
  387. int OpenInputFile (const char* fileName, FILE** fp, double *time)
  388. {
  389. char line[MAX_LINE+1];
  390. char *ptr;
  391. assert (fileName);
  392. assert (fp);
  393. assert (time);
  394. *fp = fopen (fileName, "r");
  395. if (*fp==0)
  396. {
  397. return 0;
  398. }
  399. // Jump over the header
  400. do
  401. {
  402. if (!fgets(line, MAX_LINE, *fp))
  403. {
  404. return 0;
  405. }
  406. ptr= line;
  407. while (*ptr==' ' || *ptr=='\t')
  408. {
  409. ptr++;
  410. }
  411. }
  412. while (*ptr!='#');
  413. if ( sscanf(ptr+1, "%lf", time)!= 1)
  414. {
  415. *time = 0.0;
  416. }
  417. return 1;
  418. }
  419. /*****************************************************************************
  420. * GetInputPhone *
  421. *----------------*
  422. * Description:
  423. * sentenceEnd is used to judge sentence final in cmdl slm
  424. ******************************************************************* PACOG ***/
  425. int GetInputPhone (FILE* fp, double* time, char* phone, short* f0, int* sentenceEnd)
  426. {
  427. char line[MAX_LINE+1];
  428. char *ptr;
  429. double mark;
  430. assert (fp);
  431. assert (time);
  432. assert (phone);
  433. assert (f0);
  434. while (fgets(line, MAX_LINE, fp))
  435. {
  436. ptr = line;
  437. while (*ptr && isspace (*ptr))
  438. {
  439. ptr++;
  440. }
  441. if (!*ptr || *ptr=='#') {
  442. /*
  443. * Allows for embeded comments
  444. */
  445. continue;
  446. }
  447. mark = -1.0;
  448. if (sscanf (ptr, "%lf %*s %s %d %lf", time, phone, f0, &mark)!=4)
  449. {
  450. if (sscanf (ptr, "%lf %*s %s %d", time, phone, f0)!=3)
  451. {
  452. printf("Error in line %s\n",line);
  453. return 0;
  454. }
  455. }
  456. if (phone[strlen(phone)-1] == ';')
  457. {
  458. phone[strlen(phone)-1] = '\0';
  459. }
  460. if (strcmp(phone, "sp")==0 || strcmp(phone, "SIL") == 0)
  461. {
  462. strcpy(phone,"sil");
  463. }
  464. *sentenceEnd = (mark == 0.0);
  465. return 1;
  466. }
  467. return 0;
  468. }
  469. /*****************************************************************************
  470. * ReadScriptLine *
  471. *----------------*
  472. * Description:
  473. * read Input/output from a script file
  474. ******************************************************************* PACOG ***/
  475. int ReadScriptLine (FILE* script, char* inFile, char* outFile)
  476. {
  477. char line[MAX_LINE+1];
  478. char *ptr;
  479. assert (script);
  480. while (fgets(line, MAX_LINE, script))
  481. {
  482. if (ptr = strchr (line, '#'))
  483. {
  484. *ptr = '\0';
  485. }
  486. ptr = line;
  487. while (*ptr && isspace (*ptr))
  488. {
  489. ptr++;
  490. }
  491. if (!*ptr )
  492. {
  493. continue;
  494. }
  495. if (sscanf (ptr, "%s %s", inFile, outFile) != 2)
  496. {
  497. fprintf(stderr,"Error: reading script file at \n\t %s\n",ptr);
  498. return 0;
  499. }
  500. return 1;
  501. }
  502. return 0;
  503. }
  504. /*****************************************************************************
  505. * GetIoNames *
  506. *------------*
  507. * Description:
  508. *
  509. ******************************************************************* PACOG ***/
  510. int GetIoNames (InputInfo* inInfo, NamePair** names, int* nNames)
  511. {
  512. FILE *script;
  513. assert (inInfo);
  514. assert (names);
  515. assert (nNames);
  516. if (inInfo->scriptFile[0])
  517. {
  518. if ((script = fopen(inInfo->scriptFile,"r")) == 0 )
  519. {
  520. fprintf(stderr, "Error: Could not open scriptFile %s\n", inInfo->scriptFile);
  521. return 1;
  522. }
  523. else
  524. {
  525. while (ReadScriptLine(script, inInfo->input, inInfo->output))
  526. {
  527. if (*names)
  528. {
  529. *names = (NamePair*)realloc (*names, (*nNames + 1) * sizeof(**names));
  530. }
  531. else
  532. {
  533. *names = (NamePair*)malloc (sizeof(**names));
  534. }
  535. if (*names == 0)
  536. {
  537. return 0;
  538. }
  539. strcpy((*names)[*nNames].in, inInfo->input);
  540. strcpy((*names)[*nNames].out, inInfo->output);
  541. (*nNames)++;
  542. }
  543. }
  544. }
  545. else
  546. {
  547. if ((*names = (NamePair*)malloc (sizeof(**names))) == 0)
  548. {
  549. return 0;
  550. }
  551. strcpy((*names)[0].in, inInfo->input);
  552. strcpy((*names)[0].out, inInfo->output);
  553. *nNames = 1;
  554. }
  555. return 1;
  556. }
  557. /*****************************************************************************
  558. * ProcessCommandLine *
  559. *--------------------*
  560. * Description:
  561. *
  562. ******************************************************************* PACOG ***/
  563. int ProcessCommandLine (int argc, char *argv[], InputInfo* inInfo)
  564. {
  565. CGetOpt getOpt;
  566. int optIdx;
  567. int ch;
  568. assert (argv);
  569. assert (argc>0);
  570. assert (inInfo);
  571. memset (inInfo, 0, sizeof(*inInfo));
  572. getOpt.Init (argc, argv, "bstgf:d:r:l:c:x:m:S:");
  573. while ((ch = getOpt.NextOption()) != EOF)
  574. {
  575. switch (ch)
  576. {
  577. case 'b':
  578. inInfo->slmOptions |= CSlm::Blend;
  579. break;
  580. case 's':
  581. inInfo->slmOptions |= CSlm::DynSearch;
  582. break;
  583. case 't':
  584. inInfo->slmOptions |= CSlm::UseTargetF0;
  585. break;
  586. case 'g':
  587. inInfo->slmOptions |= CSlm::UseGain;
  588. break;
  589. case 'f':
  590. inInfo->f0Wt = (float) atof (getOpt.OptArg());
  591. inInfo->setWeights |= GOT_F0_WEIGHT;
  592. break;
  593. case 'd':
  594. inInfo->durWt = (float) atof (getOpt.OptArg());
  595. inInfo->setWeights |= GOT_DUR_WEIGHT;
  596. break;
  597. case 'r':
  598. inInfo->rmsWt = (float) atof (getOpt.OptArg());
  599. inInfo->setWeights |= GOT_RMS_WEIGHT;
  600. break;
  601. case 'l':
  602. inInfo->lklWt = (float) atof (getOpt.OptArg());
  603. inInfo->setWeights |= GOT_LKLH_WEIGHT;
  604. break;
  605. case 'm':
  606. inInfo->sameSeg = (float) atof (getOpt.OptArg());
  607. inInfo->setWeights |= GOT_SAME_WEIGHT;
  608. break;
  609. case 'c':
  610. inInfo->contWt = (float) atof (getOpt.OptArg());
  611. inInfo->setWeights |= GOT_CONT_WEIGHT;
  612. break;
  613. case 'x':
  614. strncpy (inInfo->crfFile, getOpt.OptArg(), _MAX_PATH);
  615. break;
  616. case 'S':
  617. strncpy (inInfo->scriptFile, getOpt.OptArg(), _MAX_PATH);
  618. break;
  619. default:
  620. return 0;
  621. }
  622. }
  623. optIdx = getOpt.OptInd();
  624. if ((argc - optIdx) < 1)
  625. {
  626. return 0;
  627. }
  628. else
  629. {
  630. strcpy(inInfo->tableFile,argv[optIdx++]);
  631. }
  632. if (inInfo->scriptFile[0])
  633. {
  634. if (argc-optIdx)
  635. {
  636. printf("Using script file for I/O and ignoring the input file argument\n");
  637. return 1;
  638. }
  639. else
  640. {
  641. return 1;
  642. }
  643. }
  644. if (argc-optIdx)
  645. {
  646. strcpy(inInfo->input,argv[optIdx++]);
  647. }
  648. if (argc-optIdx)
  649. {
  650. strcpy(inInfo->output,argv[optIdx++]);
  651. if (argc-optIdx)
  652. {
  653. return 0;
  654. }
  655. }
  656. else
  657. {
  658. strcpy(inInfo->output,"-");
  659. }
  660. return 1;
  661. }