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.

1511 lines
38 KiB

  1. /******************************************************************************
  2. * vapiIo.cpp *
  3. *------------*
  4. * I/O library functions for extended speech files (vapi format)
  5. *------------------------------------------------------------------------------
  6. * Copyright (C) 2000 Microsoft Corporation Date: 03/02/00
  7. * All Rights Reserved
  8. *
  9. ********************************************************************* PACOG ***/
  10. #include "vapiIoInt.h"
  11. #include <mmsystem.h>
  12. #include <mmreg.h>
  13. #include <assert.h>
  14. #include <stdio.h>
  15. typedef struct {
  16. int code;
  17. char* message;
  18. } ErrorMsg;
  19. class VapiFile : VapiIO
  20. {
  21. public:
  22. VapiFile();
  23. ~VapiFile();
  24. int OpenFile ( const char* pszFileName, int iMode );
  25. int OpenFile ( const WCHAR* wcsFileName, int iMode );
  26. void CloseFile ( );
  27. int CreateChunk ( const char* pszName );
  28. int CloseChunk ( );
  29. int WriteToChunk (const char* pszData, int iSize);
  30. int GetDataSize (long* lDataSize);
  31. int Format (int* piSampFreq, int* piFormat, WAVEFORMATEX* pWaveFormatEx = NULL);
  32. int WriteFormat (int iSampFreq, int iFormat);
  33. int ReadSamples (double dFrom, double dTo, void** ppvSamples, int* piNumSamples, bool bClosedInterval);
  34. int WriteSamples (void* pvSamples, int iNumSamples);
  35. int ReadF0SampFreq (int* piSampFreq);
  36. int WriteF0SampFreq (int iSampFreq);
  37. int ReadFeature (char* pszName, float** ppfSamples, int* piNumSamples);
  38. int WriteFeature (char* pszName, float* pfSamples, int iNumSamples);
  39. int ReadEpochs (Epoch** ppEpochs, int* iNumEpochs);
  40. int WriteEpochs (Epoch* pEpochs, int iNumEpochs);
  41. int ReadLabels (char* pszName, Label** ppLabels, int* piNumLabels);
  42. int WriteLabels (char* pszName, Label* pLabels, int iNumLabels);
  43. char* ErrMessage (int iErrCode);
  44. private:
  45. HMMIO m_HWav;
  46. MMCKINFO m_ParentInfo;
  47. MMCKINFO m_SubchunkInfo;
  48. int m_iSampFormat;
  49. int m_iSampFreq;
  50. static ErrorMsg m_ErrorMsg[];
  51. static int m_iNumErrorMsg;
  52. };
  53. ErrorMsg VapiFile::m_ErrorMsg[] = {
  54. {VAPI_IOERR_NOERROR, 0},
  55. {VAPI_IOERR_MODE, "Wrong opening mode."},
  56. {VAPI_IOERR_MEMORY, "Memory error."},
  57. {VAPI_IOERR_CANTOPEN, "Error opening file."},
  58. {VAPI_IOERR_NOWAV, "Not RIFF-WAVE format."},
  59. {VAPI_IOERR_NOFORMAT, "Can't find data format."},
  60. {VAPI_IOERR_STEREO, "File is stereo\n"},
  61. {VAPI_IOERR_FORMAT, "Unknown data format."},
  62. {VAPI_IOERR_NOCHUNK, "Error accessing data chunk."},
  63. {VAPI_IOERR_DATAACCESS, "Error accessing input data."},
  64. {VAPI_IOERR_WRITEWAV, "Error creating RIFF-WAVE chunk."},
  65. {VAPI_IOERR_CREATECHUNK, "Error creating new subchunk."},
  66. {VAPI_IOERR_WRITECHUNK, "Error writing data in new subchunk."}
  67. };
  68. int VapiFile::m_iNumErrorMsg = sizeof (VapiFile::m_ErrorMsg) / sizeof (VapiFile::m_ErrorMsg[0]);
  69. /*****************************************************************************
  70. * VapiIO::ClassFactory *
  71. *----------------------*
  72. * Description:
  73. * Class Factory, creates an object of the VapiIO implementation class.
  74. ******************************************************************* PACOG ***/
  75. VapiIO* VapiIO::ClassFactory ()
  76. {
  77. return new VapiFile();
  78. }
  79. /*****************************************************************************
  80. * VapiIO::SizeOf *
  81. *----------------*
  82. * Description:
  83. *
  84. ******************************************************************* PACOG ***/
  85. int VapiIO::SizeOf (int iType)
  86. {
  87. switch (iType)
  88. {
  89. case VAPI_PCM8:
  90. case VAPI_ALAW:
  91. case VAPI_ULAW:
  92. return 1;
  93. case VAPI_PCM16:
  94. return 2;
  95. default:
  96. return 0;
  97. }
  98. return 0;
  99. }
  100. /*****************************************************************************
  101. * VapiIO::TypeOf *
  102. *----------------*
  103. * Description:
  104. *
  105. ******************************************************************* PACOG ***/
  106. int VapiIO::TypeOf (WAVEFORMATEX *pWavFormat)
  107. {
  108. int iSampFormat;
  109. if (pWavFormat->wFormatTag == WAVE_FORMAT_PCM)
  110. {
  111. switch (pWavFormat->nBlockAlign/pWavFormat->nChannels)
  112. {
  113. case 1:
  114. iSampFormat = VAPI_PCM8;
  115. break;
  116. case 2:
  117. iSampFormat = VAPI_PCM16;
  118. break;
  119. default:
  120. iSampFormat = -1;
  121. break;
  122. }
  123. }
  124. else if (pWavFormat->wFormatTag == WAVE_FORMAT_ALAW)
  125. {
  126. iSampFormat = VAPI_ALAW;
  127. }
  128. else if (pWavFormat->wFormatTag == WAVE_FORMAT_MULAW)
  129. {
  130. iSampFormat = VAPI_ULAW;
  131. }
  132. else
  133. {
  134. iSampFormat = -1;
  135. }
  136. return iSampFormat;
  137. }
  138. /*****************************************************************************
  139. * VapiIO::DataFormatConversion *
  140. *------------------------------*
  141. * Description:
  142. *
  143. ******************************************************************* PACOG ***/
  144. int VapiIO::DataFormatConversion (char* pcInput, int iInType,
  145. char* pcOutput, int iOutType, int iNumSamples)
  146. {
  147. int i;
  148. assert (pcInput);
  149. assert (pcOutput);
  150. assert (iNumSamples>0);
  151. // Check that these are valid types
  152. if (!SizeOf(iInType) || !SizeOf(iOutType))
  153. {
  154. return 0;
  155. }
  156. // If same type, just copy samples
  157. if (iInType == iOutType)
  158. {
  159. memcpy( pcOutput, pcInput, iNumSamples * SizeOf(iInType));
  160. return 1;
  161. }
  162. // Ok, need to convert
  163. switch (iInType)
  164. {
  165. case VAPI_PCM16:
  166. switch (iOutType)
  167. {
  168. case VAPI_PCM8:
  169. for (i=0; i<iNumSamples; i++)
  170. {
  171. pcOutput[i] = ((int)((short*)pcInput)[i] + 32768) >> 8;
  172. }
  173. break;
  174. case VAPI_ALAW:
  175. for (i=0; i<iNumSamples; i++)
  176. {
  177. pcOutput[i] = Linear2Alaw (((short*)pcInput)[i]);
  178. }
  179. break;
  180. case VAPI_ULAW:
  181. for (i=0; i<iNumSamples; i++)
  182. {
  183. pcOutput[i] = Linear2Ulaw (((short*)pcInput)[i]);
  184. }
  185. break;
  186. }
  187. break;
  188. case VAPI_PCM8:
  189. switch (iOutType)
  190. {
  191. case VAPI_PCM16:
  192. for (i=0; i<iNumSamples; i++)
  193. {
  194. ((short*)pcOutput)[i] = (((int)((char*)pcInput)[i])<<8) - 32768;
  195. }
  196. break;
  197. case VAPI_ALAW:
  198. for (i=0; i<iNumSamples; i++)
  199. {
  200. pcOutput[i] = Linear2Alaw ((short)((((int)((char*)pcInput)[i])<<8) - 32768));
  201. }
  202. break;
  203. case VAPI_ULAW:
  204. for (i=0; i<iNumSamples; i++)
  205. {
  206. pcOutput[i] = Linear2Ulaw ((short)((((int)((char*)pcInput)[i])<<8) - 32768));
  207. }
  208. break;
  209. }
  210. break;
  211. case VAPI_ALAW:
  212. switch (iOutType)
  213. {
  214. case VAPI_PCM16:
  215. for (i=0; i<iNumSamples; i++)
  216. {
  217. ((short*)pcOutput)[i] = (short) Alaw2Linear(((char*)pcInput)[i]);
  218. }
  219. break;
  220. case VAPI_PCM8:
  221. for (i=0; i<iNumSamples; i++)
  222. {
  223. pcOutput[i] = ((int)Alaw2Linear(((char*)pcInput)[i]) + 32768) >> 8;
  224. }
  225. break;
  226. case VAPI_ULAW:
  227. for (i=0; i<iNumSamples; i++)
  228. {
  229. pcOutput[i] = Alaw2Ulaw(((char*)pcInput)[i]);
  230. }
  231. break;
  232. }
  233. break;
  234. case VAPI_ULAW:
  235. switch (iOutType)
  236. {
  237. case VAPI_PCM16:
  238. for (i=0; i<iNumSamples; i++)
  239. {
  240. ((short*)pcOutput)[i] = (short) Ulaw2Linear(((char*)pcInput)[i]);
  241. }
  242. break;
  243. case VAPI_PCM8:
  244. for (i=0; i<iNumSamples; i++)
  245. {
  246. pcOutput[i] = ((int)Ulaw2Linear(((char*)pcInput)[i]) + 32768)>>8;
  247. }
  248. break;
  249. case VAPI_ALAW:
  250. for (i=0; i<iNumSamples; i++)
  251. {
  252. pcOutput[i] = Ulaw2Alaw(((char*)pcInput)[i]);
  253. }
  254. break;
  255. }
  256. break;
  257. }
  258. return 1;
  259. }
  260. /*****************************************************************************
  261. * VapiFile::ErrMessage *
  262. *----------------------*
  263. * Description:
  264. *
  265. ******************************************************************* PACOG ***/
  266. char* VapiFile::ErrMessage (int errCode)
  267. {
  268. for (int i=0; i< m_iNumErrorMsg; i++)
  269. {
  270. if (errCode == m_ErrorMsg[i].code)
  271. {
  272. return m_ErrorMsg[i].message;
  273. }
  274. }
  275. return 0;
  276. }
  277. /*****************************************************************************
  278. * VapiFile::VapiFile *
  279. *--------------------*
  280. * Description:
  281. *
  282. ******************************************************************* PACOG ***/
  283. VapiFile::VapiFile()
  284. {
  285. m_HWav = 0;
  286. memset (&m_ParentInfo, 0, sizeof(m_ParentInfo));
  287. memset (&m_SubchunkInfo, 0, sizeof(m_SubchunkInfo));
  288. m_iSampFormat = 0;
  289. m_iSampFreq = 0;
  290. }
  291. /*****************************************************************************
  292. * VapiFile::~VapiFile *
  293. *---------------------*
  294. * Description:
  295. *
  296. ******************************************************************* PACOG ***/
  297. VapiFile::~VapiFile()
  298. {
  299. CloseFile();
  300. }
  301. /*****************************************************************************
  302. * VapiFile::OpenFile *
  303. *--------------------*
  304. * Description:
  305. *
  306. ******************************************************************* PACOG ***/
  307. int VapiFile::OpenFile (const char* pszFileName, int iMode)
  308. {
  309. int iErrCode = VAPI_IOERR_NOERROR;
  310. assert (pszFileName);
  311. switch (iMode)
  312. {
  313. case VAPI_IO_READ:
  314. iMode = MMIO_READ;
  315. break;
  316. case VAPI_IO_WRITE:
  317. iMode = MMIO_WRITE|MMIO_CREATE;
  318. break;
  319. case VAPI_IO_READWRITE:
  320. iMode = MMIO_READWRITE;
  321. break;
  322. default:
  323. return VAPI_IOERR_MODE;
  324. }
  325. if ((m_HWav = mmioOpen ((char *)pszFileName, NULL, iMode)) == NULL)
  326. {
  327. iErrCode = VAPI_IOERR_CANTOPEN;
  328. goto error;
  329. }
  330. if (iMode == MMIO_READ)
  331. {
  332. m_ParentInfo.fccType = mmioFOURCC ('W', 'A', 'V', 'E');
  333. if (mmioDescend (m_HWav, &m_ParentInfo, 0, MMIO_FINDRIFF))
  334. {
  335. iErrCode = VAPI_IOERR_NOWAV;
  336. goto error;
  337. }
  338. }
  339. else
  340. {
  341. m_ParentInfo.fccType = mmioFOURCC ('W', 'A', 'V', 'E');
  342. if (mmioCreateChunk (m_HWav, &m_ParentInfo, MMIO_CREATERIFF))
  343. {
  344. iErrCode = VAPI_IOERR_WRITEWAV;
  345. goto error;
  346. }
  347. }
  348. return VAPI_IOERR_NOERROR;
  349. error:
  350. CloseFile ();
  351. return iErrCode;
  352. }
  353. /*****************************************************************************
  354. * VapiFile::OpenFile *
  355. *--------------------*
  356. * Description: Same as previous OpenFile, but takes WCHAR* as arg
  357. *
  358. ******************************************************************* JOEM ****/
  359. int VapiFile::OpenFile (const WCHAR* wcsFileName, int iMode)
  360. {
  361. int iErrCode = VAPI_IOERR_NOERROR;
  362. assert (wcsFileName);
  363. switch (iMode)
  364. {
  365. case VAPI_IO_READ:
  366. iMode = MMIO_READ;
  367. break;
  368. case VAPI_IO_WRITE:
  369. iMode = MMIO_WRITE|MMIO_CREATE;
  370. break;
  371. case VAPI_IO_READWRITE:
  372. iMode = MMIO_READWRITE;
  373. break;
  374. default:
  375. return VAPI_IOERR_MODE;
  376. }
  377. if ((m_HWav = mmioOpenW ((WCHAR *)wcsFileName, NULL, iMode)) == NULL)
  378. {
  379. iErrCode = VAPI_IOERR_CANTOPEN;
  380. goto error;
  381. }
  382. if (iMode == MMIO_READ)
  383. {
  384. m_ParentInfo.fccType = mmioFOURCC ('W', 'A', 'V', 'E');
  385. if (mmioDescend (m_HWav, &m_ParentInfo, 0, MMIO_FINDRIFF))
  386. {
  387. iErrCode = VAPI_IOERR_NOWAV;
  388. goto error;
  389. }
  390. }
  391. else
  392. {
  393. m_ParentInfo.fccType = mmioFOURCC ('W', 'A', 'V', 'E');
  394. if (mmioCreateChunk (m_HWav, &m_ParentInfo, MMIO_CREATERIFF))
  395. {
  396. iErrCode = VAPI_IOERR_WRITEWAV;
  397. goto error;
  398. }
  399. }
  400. return VAPI_IOERR_NOERROR;
  401. error:
  402. CloseFile ();
  403. return iErrCode;
  404. }
  405. /*****************************************************************************
  406. * VapiFile::CloseFile *
  407. *---------------------*
  408. * Description:
  409. *
  410. ******************************************************************* PACOG ***/
  411. void VapiFile::CloseFile ()
  412. {
  413. if (m_HWav)
  414. {
  415. mmioAscend (m_HWav, &m_ParentInfo, 0);
  416. mmioClose (m_HWav, 0);
  417. memset (&m_ParentInfo, 0, sizeof(m_ParentInfo));
  418. m_HWav = 0;
  419. }
  420. }
  421. /*****************************************************************************
  422. * VapiFile::Format *
  423. *------------------*
  424. * Description:
  425. *
  426. ******************************************************************* PACOG ***/
  427. int VapiFile::Format (int* piSampFreq, int* piFormat, WAVEFORMATEX* pWaveFormatEx)
  428. {
  429. WAVEFORMATEX* WavFormat = NULL;
  430. WAVEFORMATEX LocalWaveFormat;
  431. MMCKINFO SubchunkInfo;
  432. int iErrCode = VAPI_IOERR_NOERROR;
  433. assert (m_HWav);
  434. memset((void*)&LocalWaveFormat, 0, sizeof(WAVEFORMATEX));
  435. if ( pWaveFormatEx )
  436. {
  437. memset((void*)pWaveFormatEx, 0, sizeof(WAVEFORMATEX));
  438. WavFormat = pWaveFormatEx;
  439. }
  440. else
  441. {
  442. WavFormat = &LocalWaveFormat;
  443. }
  444. mmioSeek (m_HWav, m_ParentInfo.dwDataOffset+4, SEEK_SET);
  445. SubchunkInfo.ckid = mmioFOURCC ('f', 'm', 't', ' ');
  446. if (mmioDescend (m_HWav, &SubchunkInfo, &m_ParentInfo, MMIO_FINDCHUNK) )
  447. {
  448. iErrCode = VAPI_IOERR_NOFORMAT;
  449. goto error;
  450. }
  451. if (mmioRead (m_HWav, (char *)WavFormat, SubchunkInfo.cksize)!= (int)SubchunkInfo.cksize)
  452. {
  453. iErrCode = VAPI_IOERR_NOFORMAT;
  454. goto error;
  455. }
  456. mmioAscend (m_HWav, &SubchunkInfo, 0);
  457. /*
  458. * Process header info.
  459. * Files must be mono, and in one of these formats
  460. */
  461. if (WavFormat->nChannels >1 )
  462. {
  463. iErrCode = VAPI_IOERR_STEREO;
  464. goto error;
  465. }
  466. m_iSampFormat = TypeOf (WavFormat);
  467. if (m_iSampFormat < 0)
  468. {
  469. iErrCode = VAPI_IOERR_FORMAT;
  470. goto error;
  471. }
  472. m_iSampFreq = WavFormat->nSamplesPerSec;
  473. if (piFormat)
  474. {
  475. *piFormat = m_iSampFormat;
  476. }
  477. if (piSampFreq)
  478. {
  479. *piSampFreq = m_iSampFreq;
  480. }
  481. error:
  482. return iErrCode;
  483. }
  484. /*****************************************************************************
  485. * VapiFile::GetDataSize *
  486. *------------------*
  487. * Description:
  488. *
  489. ******************************************************************* PACOG ***/
  490. int VapiFile::GetDataSize (long* lDataSize)
  491. {
  492. MMCKINFO SubchunkInfo;
  493. int iErrCode = VAPI_IOERR_NOERROR;
  494. /*
  495. * Go for the data
  496. */
  497. mmioSeek (m_HWav, m_ParentInfo.dwDataOffset+4, SEEK_SET);
  498. SubchunkInfo.ckid = mmioFOURCC ('d', 'a', 't', 'a');
  499. if (mmioDescend (m_HWav, &SubchunkInfo, &m_ParentInfo, MMIO_FINDCHUNK))
  500. {
  501. iErrCode = VAPI_IOERR_NOCHUNK;
  502. goto error;
  503. }
  504. *lDataSize = SubchunkInfo.cksize;
  505. mmioAscend (m_HWav, &SubchunkInfo, 0);
  506. error:
  507. return iErrCode;
  508. }
  509. /*****************************************************************************
  510. * VapiFile::WriteFormat *
  511. *-----------------------*
  512. * Description:
  513. *
  514. ******************************************************************* PACOG ***/
  515. int VapiFile::WriteFormat (int iSampFreq, int iFormat)
  516. {
  517. WAVEFORMATEX WavFormat;
  518. MMCKINFO SubchunkInfo;
  519. int iErrCode = VAPI_IOERR_NOERROR;
  520. assert (m_HWav);
  521. assert (iSampFreq>0);
  522. switch (iFormat)
  523. {
  524. case VAPI_PCM8:
  525. WavFormat.wFormatTag = WAVE_FORMAT_PCM;
  526. WavFormat.wBitsPerSample = 8;
  527. break;
  528. case VAPI_ALAW:
  529. WavFormat.wFormatTag = WAVE_FORMAT_ALAW;
  530. WavFormat.wBitsPerSample = 8;
  531. break;
  532. case VAPI_ULAW:
  533. WavFormat.wFormatTag = WAVE_FORMAT_MULAW;
  534. WavFormat.wBitsPerSample = 8;
  535. break;
  536. case VAPI_PCM16:
  537. WavFormat.wFormatTag = WAVE_FORMAT_PCM;
  538. WavFormat.wBitsPerSample = 16;
  539. break;
  540. default:
  541. iErrCode = VAPI_IOERR_FORMAT;
  542. goto error;
  543. }
  544. WavFormat.nChannels = 1;
  545. WavFormat.nSamplesPerSec = iSampFreq;
  546. WavFormat.nBlockAlign = (WavFormat.wBitsPerSample / 8) ;
  547. WavFormat.nAvgBytesPerSec = WavFormat.nBlockAlign * WavFormat.nSamplesPerSec;
  548. WavFormat.cbSize = 0;
  549. SubchunkInfo.ckid = mmioFOURCC ('f', 'm', 't', ' ');
  550. if (mmioCreateChunk (m_HWav, &SubchunkInfo, 0) )
  551. {
  552. iErrCode = VAPI_IOERR_CREATECHUNK;
  553. goto error;
  554. }
  555. if (mmioWrite(m_HWav, (char *)&WavFormat, sizeof(WavFormat)) != (int)sizeof(WavFormat))
  556. {
  557. iErrCode = VAPI_IOERR_WRITECHUNK;
  558. goto error;
  559. }
  560. mmioAscend (m_HWav, &SubchunkInfo, 0);
  561. m_iSampFreq = iSampFreq;
  562. m_iSampFormat = iFormat;
  563. error:
  564. return iErrCode;
  565. }
  566. /*****************************************************************************
  567. * VapiFile::CreateChunk *
  568. *-----------------------*
  569. * Description:
  570. *
  571. ******************************************************************* PACOG ***/
  572. int VapiFile::CreateChunk (const char* pszName)
  573. {
  574. assert (pszName);
  575. m_SubchunkInfo.ckid = mmioStringToFOURCC (pszName, 0);
  576. if (mmioCreateChunk (m_HWav, &m_SubchunkInfo, 0))
  577. {
  578. return VAPI_IOERR_CREATECHUNK;
  579. }
  580. return VAPI_IOERR_NOERROR;
  581. }
  582. /*****************************************************************************
  583. * VapiFile::WriteToChunk *
  584. *------------------------*
  585. * Description:
  586. *
  587. ******************************************************************* PACOG ***/
  588. int VapiFile::WriteToChunk (const char* pcData, int iSize)
  589. {
  590. assert (pcData);
  591. assert (iSize>0);
  592. if ( mmioWrite (m_HWav, pcData, iSize) != iSize )
  593. {
  594. return VAPI_IOERR_WRITECHUNK;
  595. }
  596. return VAPI_IOERR_NOERROR;
  597. }
  598. /*****************************************************************************
  599. * VapiFile::CloseChunk *
  600. *----------------------*
  601. * Description:
  602. *
  603. ******************************************************************* PACOG ***/
  604. int VapiFile::CloseChunk ( )
  605. {
  606. assert (m_HWav);
  607. mmioAscend (m_HWav, &m_SubchunkInfo, 0);
  608. return VAPI_IOERR_NOERROR;
  609. }
  610. /*****************************************************************************
  611. * VapiFile::ReadSamples *
  612. *-----------------------*
  613. * Description:
  614. *
  615. ******************************************************************* PACOG ***/
  616. int VapiFile::ReadSamples (double dFrom, double dTo,
  617. void** ppvSamples, int* piNumSamples, bool bClosedInterval)
  618. {
  619. MMCKINFO SubchunkInfo;
  620. int iErrCode = VAPI_IOERR_NOERROR;
  621. void* pvBuffer = NULL;
  622. int iBuffLen;
  623. int iBuffLenInFile;
  624. int iSkipBytes;
  625. long lRead;
  626. double dEndOfData;
  627. assert (m_HWav);
  628. assert (ppvSamples);
  629. assert (piNumSamples);
  630. assert (dFrom>=0.0);
  631. assert (dTo == -1.0 || dTo>=dFrom);
  632. /*
  633. * Go for the data
  634. */
  635. mmioSeek (m_HWav, m_ParentInfo.dwDataOffset+4, SEEK_SET);
  636. SubchunkInfo.ckid = mmioFOURCC ('d', 'a', 't', 'a');
  637. if (mmioDescend (m_HWav, &SubchunkInfo, &m_ParentInfo, MMIO_FINDCHUNK))
  638. {
  639. iErrCode = VAPI_IOERR_NOCHUNK;
  640. goto error;
  641. }
  642. iBuffLenInFile = SubchunkInfo.cksize;
  643. dEndOfData = ((double)iBuffLenInFile) / SizeOf(m_iSampFormat) / m_iSampFreq;
  644. if ( dFrom > dEndOfData )
  645. {
  646. // nothing to read
  647. iErrCode = VAPI_IOERR_NOCHUNK;
  648. goto error;
  649. }
  650. if ( dTo != -1.0 && dFrom >= dTo )
  651. {
  652. // nothing to read
  653. iErrCode = VAPI_IOERR_NOCHUNK;
  654. goto error;
  655. }
  656. /*
  657. * Read only the desired region
  658. */
  659. if (dFrom < 0.0)
  660. {
  661. dFrom = 0.0;
  662. }
  663. iSkipBytes = (int)(dFrom * m_iSampFreq + 0.5) * SizeOf(m_iSampFormat);
  664. if (dTo == -1.0)
  665. {
  666. iBuffLen = iBuffLenInFile;
  667. }
  668. else
  669. {
  670. iBuffLen = (int)(dTo * m_iSampFreq + 0.5) * SizeOf(m_iSampFormat);
  671. if (iBuffLen>=iBuffLenInFile)
  672. {
  673. dTo = -1.0;
  674. iBuffLen = iBuffLenInFile;
  675. }
  676. }
  677. iBuffLen -= iSkipBytes;
  678. if (bClosedInterval && dTo != -1.0)
  679. {
  680. iBuffLen += SizeOf (m_iSampFormat);
  681. }
  682. if (iSkipBytes>0 && mmioSeek (m_HWav, iSkipBytes, SEEK_CUR) == -1)
  683. {
  684. iErrCode = VAPI_IOERR_DATAACCESS;
  685. goto error;
  686. }
  687. if ((pvBuffer = new char[iBuffLen]) == NULL)
  688. {
  689. iErrCode = VAPI_IOERR_MEMORY;
  690. goto error;
  691. }
  692. lRead = mmioRead (m_HWav, (char *)pvBuffer, iBuffLen);
  693. if ( lRead != (int)iBuffLen)
  694. {
  695. iErrCode = VAPI_IOERR_DATAACCESS;
  696. goto error;
  697. }
  698. mmioAscend (m_HWav, &SubchunkInfo, 0);
  699. *ppvSamples = pvBuffer;
  700. *piNumSamples = iBuffLen/SizeOf(m_iSampFormat);
  701. return VAPI_IOERR_NOERROR;
  702. error:
  703. if (pvBuffer)
  704. {
  705. delete[] pvBuffer;
  706. }
  707. return iErrCode;
  708. }
  709. /*****************************************************************************
  710. * VapiFile::WriteSamples *
  711. *------------------------*
  712. * Description:
  713. *
  714. ******************************************************************* PACOG ***/
  715. int VapiFile::WriteSamples (void* pvSamples, int iNumSamples)
  716. {
  717. MMCKINFO subchunkInfo;
  718. int iErrCode = VAPI_IOERR_NOERROR;
  719. int iBuffLen;
  720. assert (m_HWav);
  721. assert (pvSamples);
  722. assert (iNumSamples>0);
  723. subchunkInfo.ckid = mmioFOURCC ('d', 'a', 't', 'a');
  724. if (mmioCreateChunk (m_HWav, &subchunkInfo, 0) )
  725. {
  726. iErrCode = VAPI_IOERR_CREATECHUNK;
  727. goto error;
  728. }
  729. iBuffLen = iNumSamples * SizeOf (m_iSampFormat);
  730. if (mmioWrite(m_HWav, (char *)pvSamples, iBuffLen) != iBuffLen)
  731. {
  732. iErrCode = VAPI_IOERR_WRITECHUNK;
  733. goto error;
  734. }
  735. mmioAscend (m_HWav, &subchunkInfo, 0);
  736. error:
  737. return iErrCode;
  738. }
  739. /*****************************************************************************
  740. * VapiFile::ReadF0SampFreq *
  741. *--------------------------*
  742. * Description:
  743. *
  744. ******************************************************************* PACOG ***/
  745. int VapiFile::ReadF0SampFreq (int* piSampFreq)
  746. {
  747. MMCKINFO SubchunkInfo;
  748. int iErrCode = VAPI_IOERR_NOERROR;
  749. assert (m_HWav);
  750. assert (piSampFreq);
  751. mmioSeek (m_HWav, m_ParentInfo.dwDataOffset+4, SEEK_SET);
  752. SubchunkInfo.ckid = mmioFOURCC ('f', '0', 's', 'f') ;
  753. if (mmioDescend (m_HWav, &SubchunkInfo, &m_ParentInfo, MMIO_FINDCHUNK) == MMIOERR_CHUNKNOTFOUND)
  754. {
  755. iErrCode = VAPI_IOERR_NOCHUNK;
  756. }
  757. else
  758. {
  759. if (mmioRead (m_HWav, (char *)piSampFreq, SubchunkInfo.cksize) != (int)SubchunkInfo.cksize)
  760. {
  761. iErrCode = VAPI_IOERR_F0SFACCESS;
  762. goto error;
  763. }
  764. mmioAscend (m_HWav, &SubchunkInfo, 0);
  765. }
  766. error:
  767. return iErrCode;
  768. }
  769. /*****************************************************************************
  770. * VapiFile::WriteF0SampFreq *
  771. *---------------------------*
  772. * Description:
  773. *
  774. ******************************************************************* PACOG ***/
  775. int VapiFile::WriteF0SampFreq (int iSampFreq)
  776. {
  777. MMCKINFO SubchunkInfo;
  778. int iErrCode = VAPI_IOERR_NOERROR;
  779. assert (m_HWav);
  780. assert (iSampFreq>0);
  781. SubchunkInfo.ckid = mmioFOURCC ('f', '0', 's', 'f') ;
  782. if (mmioCreateChunk (m_HWav, &SubchunkInfo, 0) )
  783. {
  784. iErrCode = VAPI_IOERR_CREATECHUNK;
  785. goto error;
  786. }
  787. if (mmioWrite(m_HWav, (char *)&iSampFreq, sizeof(iSampFreq)) != sizeof(iSampFreq))
  788. {
  789. iErrCode = VAPI_IOERR_WRITECHUNK;
  790. goto error;
  791. }
  792. mmioAscend (m_HWav, &SubchunkInfo, 0);
  793. error:
  794. return iErrCode;
  795. }
  796. /*****************************************************************************
  797. * VapiFile::ReadFeature *
  798. *-----------------------*
  799. * Description:
  800. *
  801. ******************************************************************* PACOG ***/
  802. int VapiFile::ReadFeature (char* pszName, float** ppfSamples, int* piNumSamples)
  803. {
  804. MMCKINFO SubchunkInfo;
  805. int iErrCode = VAPI_IOERR_NOERROR;
  806. assert (m_HWav);
  807. assert (pszName);
  808. assert (ppfSamples);
  809. assert (piNumSamples);
  810. mmioSeek (m_HWav, m_ParentInfo.dwDataOffset+4, SEEK_SET);
  811. SubchunkInfo.ckid = mmioStringToFOURCC (pszName, 0);
  812. if (mmioDescend (m_HWav, &SubchunkInfo, &m_ParentInfo, MMIO_FINDCHUNK) == MMIOERR_CHUNKNOTFOUND)
  813. {
  814. iErrCode = VAPI_IOERR_NOCHUNK;
  815. }
  816. else
  817. {
  818. *piNumSamples = SubchunkInfo.cksize/ sizeof(**ppfSamples);
  819. if ((*ppfSamples = new float[SubchunkInfo.cksize/sizeof(float)]) == NULL )
  820. {
  821. iErrCode = VAPI_IOERR_MEMORY;
  822. goto error;
  823. }
  824. if (mmioRead (m_HWav, (char *)*ppfSamples, SubchunkInfo.cksize) != (int)SubchunkInfo.cksize)
  825. {
  826. iErrCode = VAPI_IOERR_FEATACCESS;
  827. goto error;
  828. }
  829. mmioAscend (m_HWav, &SubchunkInfo, 0);
  830. }
  831. error:
  832. return iErrCode;
  833. }
  834. /*****************************************************************************
  835. * VapiFile::WriteFeature *
  836. *------------------------*
  837. * Description:
  838. *
  839. ******************************************************************* PACOG ***/
  840. int VapiFile::WriteFeature (char* pszName, float* pfSamples, int iNumSamples)
  841. {
  842. MMCKINFO SubchunkInfo;
  843. int iErrCode = VAPI_IOERR_NOERROR;
  844. int iBuffLen;
  845. assert (m_HWav);
  846. assert (pszName);
  847. assert (pfSamples);
  848. assert (iNumSamples>0);
  849. SubchunkInfo.ckid = mmioStringToFOURCC (pszName, 0);
  850. if (mmioCreateChunk (m_HWav, &SubchunkInfo, 0) )
  851. {
  852. iErrCode = VAPI_IOERR_CREATECHUNK;
  853. goto error;
  854. }
  855. iBuffLen = iNumSamples * sizeof(*pfSamples);
  856. if (mmioWrite(m_HWav, (char *)pfSamples, iBuffLen) != iBuffLen)
  857. {
  858. iErrCode = VAPI_IOERR_WRITECHUNK;
  859. goto error;
  860. }
  861. mmioAscend (m_HWav, &SubchunkInfo, 0);
  862. error:
  863. return iErrCode;
  864. }
  865. /*****************************************************************************
  866. * VapiFile::ReadEpochs *
  867. *----------------------*
  868. * Description:
  869. *
  870. ******************************************************************* PACOG ***/
  871. int VapiFile::ReadEpochs (Epoch** ppEpochs, int* piNumEpochs)
  872. {
  873. MMCKINFO SubchunkInfo;
  874. int iErrCode = VAPI_IOERR_NOERROR;
  875. assert (m_HWav);
  876. assert (ppEpochs);
  877. assert (piNumEpochs);
  878. mmioSeek (m_HWav, m_ParentInfo.dwDataOffset+4, SEEK_SET);
  879. SubchunkInfo.ckid = mmioFOURCC ('e', 'p', 'o', 'c');
  880. if (mmioDescend (m_HWav, &SubchunkInfo, &m_ParentInfo, MMIO_FINDCHUNK) == MMIOERR_CHUNKNOTFOUND)
  881. {
  882. iErrCode = VAPI_IOERR_NOCHUNK;
  883. goto error;
  884. }
  885. else
  886. {
  887. *piNumEpochs = SubchunkInfo.cksize / sizeof(**ppEpochs);
  888. if ((*ppEpochs = new Epoch[SubchunkInfo.cksize/sizeof(Epoch)]) == NULL )
  889. {
  890. iErrCode = VAPI_IOERR_MEMORY;
  891. goto error;
  892. }
  893. if (mmioRead (m_HWav, (char *)*ppEpochs, SubchunkInfo.cksize) != (int)SubchunkInfo.cksize)
  894. {
  895. iErrCode = VAPI_IOERR_EPOCHACCESS;
  896. goto error;
  897. }
  898. mmioAscend (m_HWav, &SubchunkInfo, 0);
  899. }
  900. error:
  901. return iErrCode;
  902. }
  903. /*****************************************************************************
  904. * VapiFile::WriteEpochs *
  905. *-----------------------*
  906. * Description:
  907. *
  908. ******************************************************************* PACOG ***/
  909. int VapiFile::WriteEpochs (Epoch* pEpochs, int iNumEpochs)
  910. {
  911. MMCKINFO SubchunkInfo;
  912. int iErrCode = VAPI_IOERR_NOERROR;
  913. int iBuffLen;
  914. assert (m_HWav);
  915. assert (pEpochs);
  916. assert (iNumEpochs>0);
  917. SubchunkInfo.ckid = mmioFOURCC ('e', 'p', 'o', 'c');
  918. if (mmioCreateChunk (m_HWav, &SubchunkInfo, 0) )
  919. {
  920. iErrCode = VAPI_IOERR_CREATECHUNK;
  921. goto error;
  922. }
  923. iBuffLen = iNumEpochs * sizeof(*pEpochs);
  924. if (mmioWrite(m_HWav, (char *)pEpochs, iBuffLen) != iBuffLen)
  925. {
  926. iErrCode = VAPI_IOERR_WRITECHUNK;
  927. goto error;
  928. }
  929. mmioAscend (m_HWav, &SubchunkInfo, 0);
  930. error:
  931. return iErrCode;
  932. }
  933. /*****************************************************************************
  934. * VapiFile::ReadLabels *
  935. *----------------------*
  936. * Description:
  937. *
  938. ******************************************************************* PACOG ***/
  939. int VapiFile::ReadLabels (char* pszName, Label** ppLabels, int* piNumLabels)
  940. {
  941. MMCKINFO SubchunkInfo;
  942. int iErrCode = VAPI_IOERR_NOERROR;
  943. assert (m_HWav);
  944. assert (pszName);
  945. assert (ppLabels);
  946. assert (piNumLabels);
  947. mmioSeek (m_HWav, m_ParentInfo.dwDataOffset+4, SEEK_SET);
  948. SubchunkInfo.ckid = mmioStringToFOURCC (pszName, 0);
  949. if (mmioDescend (m_HWav, &SubchunkInfo, &m_ParentInfo, MMIO_FINDCHUNK) == MMIOERR_CHUNKNOTFOUND)
  950. {
  951. iErrCode = VAPI_IOERR_NOCHUNK;
  952. }
  953. else
  954. {
  955. *piNumLabels = SubchunkInfo.cksize/ sizeof(**ppLabels);
  956. if ((*ppLabels = new Label[SubchunkInfo.cksize/sizeof(Label)]) == NULL )
  957. {
  958. iErrCode = VAPI_IOERR_MEMORY;
  959. goto error;
  960. }
  961. if (mmioRead (m_HWav, (char *)*ppLabels, SubchunkInfo.cksize) != (int)SubchunkInfo.cksize)
  962. {
  963. iErrCode = VAPI_IOERR_LABELACCESS;
  964. goto error;
  965. }
  966. mmioAscend (m_HWav, &SubchunkInfo, 0);
  967. }
  968. error:
  969. return iErrCode;
  970. }
  971. /*****************************************************************************
  972. * VapiFile::WriteLabels *
  973. *-----------------------*
  974. * Description:
  975. *
  976. ******************************************************************* PACOG ***/
  977. int VapiFile::WriteLabels (char* pszName, Label* pLabels, int iNumLabels)
  978. {
  979. MMCKINFO SubchunkInfo;
  980. int iErrCode = VAPI_IOERR_NOERROR;
  981. int iBuffLen;
  982. assert (m_HWav);
  983. assert (pszName);
  984. assert (pLabels);
  985. assert (iNumLabels>0);
  986. SubchunkInfo.ckid = mmioStringToFOURCC (pszName, 0);
  987. if (mmioCreateChunk (m_HWav, &SubchunkInfo, 0) )
  988. {
  989. iErrCode = VAPI_IOERR_CREATECHUNK;
  990. goto error;
  991. }
  992. iBuffLen = iNumLabels * sizeof(*pLabels);
  993. if (mmioWrite(m_HWav, (char *)pLabels, iBuffLen) != iBuffLen)
  994. {
  995. iErrCode = VAPI_IOERR_WRITECHUNK;
  996. goto error;
  997. }
  998. mmioAscend (m_HWav, &SubchunkInfo, 0);
  999. error:
  1000. return iErrCode;
  1001. }
  1002. /*****************************************************************************
  1003. * VapiIO::ReadVapiFile *
  1004. *----------------------*
  1005. * Description:
  1006. *
  1007. ******************************************************************* PACOG ***/
  1008. int VapiIO::ReadVapiFile (const char* pszFileName, short** ppnSamples, int* piNumSamples,
  1009. int* piSampFreq, int* piSampFormat, int* piF0SampFreq,
  1010. float** ppfF0, int* piNumF0, float** ppfRms, int* piNumRms,
  1011. Epoch** ppEpochs, int* piNumEpochs,
  1012. Label** ppPhones, int* piNumPhones, Label** ppWords, int* piNumWords)
  1013. {
  1014. VapiIO* pViof = 0;
  1015. void* pvBuffer = NULL;
  1016. int iErrCode = VAPI_IOERR_NOERROR;
  1017. int iRetVal;
  1018. assert (pszFileName);
  1019. if (( pViof = VapiIO::ClassFactory()) == 0)
  1020. {
  1021. iErrCode = VAPI_IOERR_MEMORY;
  1022. goto error;
  1023. }
  1024. if ( (iRetVal = pViof->OpenFile (pszFileName, VAPI_IO_READ)) != VAPI_IOERR_NOERROR)
  1025. {
  1026. iErrCode = iRetVal;
  1027. goto error;
  1028. }
  1029. if (ppnSamples && piNumSamples)
  1030. {
  1031. int sFreq;
  1032. int sType;
  1033. iRetVal = pViof->Format (&sFreq, &sType);
  1034. switch (iRetVal)
  1035. {
  1036. case VAPI_IOERR_NOERROR:
  1037. break;
  1038. case VAPI_IOERR_NOCHUNK:
  1039. sFreq = 0;
  1040. break;
  1041. default:
  1042. iErrCode = iRetVal;
  1043. goto error;
  1044. }
  1045. if (piSampFreq)
  1046. {
  1047. *piSampFreq = sFreq;
  1048. }
  1049. if (piSampFormat)
  1050. {
  1051. *piSampFormat = sType;
  1052. }
  1053. /*
  1054. * Read samples
  1055. */
  1056. iRetVal = pViof->ReadSamples (0.0, -1.0, &pvBuffer, piNumSamples, 0);
  1057. switch (iRetVal)
  1058. {
  1059. case VAPI_IOERR_NOERROR:
  1060. break;
  1061. case VAPI_IOERR_NOCHUNK:
  1062. *ppnSamples = NULL;
  1063. *piNumSamples = 0;
  1064. break;
  1065. default:
  1066. iErrCode = iRetVal;
  1067. goto error;
  1068. }
  1069. /*
  1070. * Convert samples to PCM16
  1071. */
  1072. if ( (*ppnSamples = new short[*piNumSamples]) == 0)
  1073. {
  1074. iErrCode = VAPI_IOERR_MEMORY;
  1075. goto error;
  1076. }
  1077. DataFormatConversion ((char *)pvBuffer, sType, (char*)*ppnSamples, VAPI_PCM16, *piNumSamples);
  1078. delete[] pvBuffer;
  1079. }
  1080. if (piF0SampFreq)
  1081. {
  1082. iRetVal = pViof->ReadF0SampFreq (piF0SampFreq);
  1083. switch (iRetVal)
  1084. {
  1085. case VAPI_IOERR_NOERROR:
  1086. break;
  1087. case VAPI_IOERR_NOCHUNK:
  1088. *piF0SampFreq = 0;
  1089. break;
  1090. default:
  1091. iErrCode = iRetVal;
  1092. goto error;
  1093. }
  1094. }
  1095. if (ppEpochs && piNumEpochs)
  1096. {
  1097. iRetVal = pViof->ReadEpochs(ppEpochs, piNumEpochs);
  1098. switch (iRetVal)
  1099. {
  1100. case VAPI_IOERR_NOERROR:
  1101. break;
  1102. case VAPI_IOERR_NOCHUNK:
  1103. *ppEpochs = NULL;
  1104. *piNumEpochs = 0;
  1105. break;
  1106. default:
  1107. iErrCode = iRetVal;
  1108. goto error;
  1109. }
  1110. }
  1111. if (ppfF0 && piNumF0)
  1112. {
  1113. iRetVal = pViof->ReadFeature ("f0", ppfF0, piNumF0);
  1114. switch (iRetVal)
  1115. {
  1116. case VAPI_IOERR_NOERROR:
  1117. break;
  1118. case VAPI_IOERR_NOCHUNK:
  1119. *ppfF0 = NULL;
  1120. *piNumF0 = 0;
  1121. break;
  1122. default:
  1123. iErrCode = iRetVal;
  1124. goto error;
  1125. }
  1126. }
  1127. if (ppfRms && piNumRms)
  1128. {
  1129. iRetVal = pViof->ReadFeature ("rms", ppfRms, piNumRms);
  1130. switch (iRetVal)
  1131. {
  1132. case VAPI_IOERR_NOERROR:
  1133. break;
  1134. case VAPI_IOERR_NOCHUNK:
  1135. *ppfRms = NULL;
  1136. *piNumRms = 0;
  1137. break;
  1138. default:
  1139. iErrCode = iRetVal;
  1140. goto error;
  1141. }
  1142. }
  1143. if (ppPhones && piNumPhones)
  1144. {
  1145. iRetVal = pViof->ReadLabels ("phon", ppPhones, piNumPhones);
  1146. switch (iRetVal)
  1147. {
  1148. case VAPI_IOERR_NOERROR:
  1149. break;
  1150. case VAPI_IOERR_NOCHUNK:
  1151. *ppPhones = NULL;
  1152. *piNumPhones = 0;
  1153. break;
  1154. default:
  1155. iErrCode = iRetVal;
  1156. goto error;
  1157. }
  1158. }
  1159. if (ppWords && piNumWords)
  1160. {
  1161. iRetVal = pViof->ReadLabels ("word", ppWords, piNumWords);
  1162. switch (iRetVal)
  1163. {
  1164. case VAPI_IOERR_NOERROR:
  1165. break;
  1166. case VAPI_IOERR_NOCHUNK:
  1167. *ppWords = NULL;
  1168. *piNumWords = 0;
  1169. break;
  1170. default:
  1171. iErrCode = iRetVal;
  1172. goto error;
  1173. }
  1174. }
  1175. error:
  1176. if (pViof)
  1177. {
  1178. pViof->CloseFile();
  1179. delete pViof;
  1180. }
  1181. return iErrCode;
  1182. }
  1183. /*****************************************************************************
  1184. * VapiIO::WriteVapiFile *
  1185. *-----------------------*
  1186. * Description:
  1187. *
  1188. ******************************************************************* PACOG ***/
  1189. int VapiIO::WriteVapiFile (const char* pszFileName, short* pnSamples, int iNumSamples, int iFormat,
  1190. int iSampFreq, int iF0SampFreq, float* pfF0, int iNumF0,
  1191. float* pfRms, int iNumRms, Epoch* pEpochs, int iNumEpochs,
  1192. Label* pPhones, int iNumPhones, Label* pWords, int iNumWords)
  1193. {
  1194. VapiIO* pViof = 0;
  1195. void* pvBuffer = 0;
  1196. int iErrCode = VAPI_IOERR_NOERROR;
  1197. int iRetVal;
  1198. assert (pszFileName);
  1199. if (( pViof = VapiIO::ClassFactory()) == 0)
  1200. {
  1201. iErrCode = VAPI_IOERR_MEMORY;
  1202. goto error;
  1203. }
  1204. if ( (iRetVal = pViof->OpenFile (pszFileName, VAPI_IO_WRITE)) != VAPI_IOERR_NOERROR)
  1205. {
  1206. iErrCode = iRetVal;
  1207. goto error;
  1208. }
  1209. if (pnSamples && iNumSamples)
  1210. {
  1211. if ((iRetVal = pViof->WriteFormat (iSampFreq, iFormat)) != VAPI_IOERR_NOERROR)
  1212. {
  1213. iErrCode = iRetVal;
  1214. goto error;
  1215. }
  1216. /*
  1217. * Convert samples to output format
  1218. */
  1219. if ( (pvBuffer = new char[iNumSamples * SizeOf(iFormat)]) == NULL)
  1220. {
  1221. iErrCode = VAPI_IOERR_MEMORY;
  1222. goto error;
  1223. }
  1224. DataFormatConversion ((char*)pnSamples, VAPI_PCM16, (char *)pvBuffer, iFormat, iNumSamples);
  1225. /*
  1226. * Write samples
  1227. */
  1228. if ((iRetVal = pViof->WriteSamples (pvBuffer, iNumSamples)) != VAPI_IOERR_NOERROR)
  1229. {
  1230. iErrCode = iRetVal;
  1231. goto error;
  1232. }
  1233. delete[] pvBuffer;
  1234. }
  1235. if (iF0SampFreq)
  1236. {
  1237. if ((iRetVal = pViof->WriteF0SampFreq (iF0SampFreq)) != VAPI_IOERR_NOERROR)
  1238. {
  1239. iErrCode = iRetVal;
  1240. goto error;
  1241. }
  1242. }
  1243. if (pEpochs && iNumEpochs)
  1244. {
  1245. if ((iRetVal = pViof->WriteEpochs (pEpochs, iNumEpochs)) != VAPI_IOERR_NOERROR)
  1246. {
  1247. iErrCode = iRetVal;
  1248. goto error;
  1249. }
  1250. }
  1251. if (pfF0 && iNumF0)
  1252. {
  1253. if ((iRetVal = pViof->WriteFeature ("f0", pfF0, iNumF0)) != VAPI_IOERR_NOERROR)
  1254. {
  1255. iErrCode = iRetVal;
  1256. goto error;
  1257. }
  1258. }
  1259. if (pfRms && iNumRms)
  1260. {
  1261. if ((iRetVal = pViof->WriteFeature ("rms", pfRms, iNumRms)) != VAPI_IOERR_NOERROR)
  1262. {
  1263. iErrCode = iRetVal;
  1264. goto error;
  1265. }
  1266. }
  1267. if (pPhones && iNumPhones)
  1268. {
  1269. if ((iRetVal = pViof->WriteLabels ("phon", pPhones, iNumPhones))!= VAPI_IOERR_NOERROR)
  1270. {
  1271. iErrCode = iRetVal;
  1272. goto error;
  1273. }
  1274. }
  1275. if (pWords && iNumWords)
  1276. {
  1277. if ((iRetVal = pViof->WriteLabels ("word", pWords, iNumWords)) != VAPI_IOERR_NOERROR)
  1278. {
  1279. iErrCode = iRetVal;
  1280. goto error;
  1281. }
  1282. }
  1283. error:
  1284. if (pViof)
  1285. {
  1286. pViof->CloseFile ();
  1287. delete pViof;
  1288. }
  1289. return iErrCode;
  1290. }