libcm is a C development framework with an emphasis on audio signal processing applications.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

cmAudioFile.c 45KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmFloatTypes.h"
  4. #include "cmRpt.h"
  5. #include "cmErr.h"
  6. #include "cmCtx.h"
  7. #include "cmMem.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmAudioFile.h"
  10. #include "cmMath.h"
  11. #include "cmFileSys.h"
  12. // #define _24to32_aif( p ) ((int)( ((p[0]>127?255:0) << 24) + (((int)p[0]) << 16) + (((int)p[1]) <<8) + p[2])) // no-swap equivalent
  13. // See note in:_cmAudioFileReadAiffHeader()
  14. // Note that this code byte swaps as it converts - this is to counter the byte swap that occurs in cmAudioFileReadInt().
  15. #define _24to32_aif( p ) ((int)( ((p[0]>127?255:0) << 0) + (((int)p[2]) << 24) + (((int)p[1]) <<16) + (((int)p[0]) << 8)))
  16. #define _24to32_wav( p ) ((int)( ((p[2]>127?255:0) << 24) + (((int)p[2]) << 16) + (((int)p[1]) <<8) + p[0]))
  17. #ifdef cmBIG_ENDIAN
  18. #define _cmAfSwap16(v) (v)
  19. #define _cmAfSwap32(v) (v)
  20. #define _cmAifSwapFl (0)
  21. #define _cmWavSwapFl (1)
  22. #else
  23. #define _cmAfSwap16(v) cmSwap16(v)
  24. #define _cmAfSwap32(v) cmSwap32(v)
  25. #define _cmAifSwapFl (1)
  26. #define _cmWavSwapFl (0)
  27. #endif
  28. enum
  29. {
  30. kAiffFileId = 'FORM',
  31. kAiffChkId = 'AIFF',
  32. kAifcChkId = 'AIFC',
  33. kSowtCompId = 'sowt',
  34. kNoneCompId = 'NONE',
  35. kWavFileId = 'FFIR',
  36. kWavChkId = 'EVAW',
  37. };
  38. enum { kWriteAudioGutsFl=0x01 };
  39. typedef struct
  40. {
  41. unsigned rc;
  42. const char* msg;
  43. } cmAudioErrRecd;
  44. typedef struct
  45. {
  46. cmErr_t err;
  47. FILE* fp; // file handle
  48. cmAudioFileInfo_t info; // audio file details
  49. unsigned curFrmIdx; // current frame offset
  50. unsigned fileByteCnt; // file byte cnt
  51. unsigned smpByteOffs; // byte offset of the first sample
  52. cmAudioFileMarker_t* markArray;
  53. unsigned flags;
  54. cmChar_t* fn;
  55. } cmAudioFileGuts;
  56. cmAudioErrRecd _cmAudioFileErrArray[] =
  57. {
  58. { kOkAfRC, "No Error." },
  59. { kOpenFailAfRC, "Audio file open failed."},
  60. { kReadFailAfRC, "Audio file read failed."},
  61. { kWriteFailAfRC, "Audio file write failed."},
  62. { kSeekFailAfRC, "Audio file seek failed."},
  63. { kCloseFailAfRC, "Audio file close failed."},
  64. { kNotAiffAfRC, "Not an audio file."},
  65. { kInvalidBitWidthAfRC, "Invalid audio file bit width."},
  66. { kInvalidFileModeAfRC, "Invalid audio file mode."},
  67. { kInvalidHandleAfRC, "Invalid audio file handle."},
  68. { kInvalidChCountAfRC, "Invalid channel index or count."},
  69. { kUnknownErrAfRC, "Uknown audio file error."}
  70. };
  71. cmAudioFileH_t cmNullAudioFileH = { NULL };
  72. cmAudioFileGuts* _cmAudioFileGutsPtr( cmAudioFileH_t h )
  73. {
  74. cmAudioFileGuts* p = (cmAudioFileGuts*)h.h;
  75. if( p == NULL )
  76. assert(p!=NULL);
  77. return p;
  78. }
  79. cmRC_t _cmAudioFileError( cmAudioFileGuts* p, cmRC_t rc )
  80. {
  81. if( rc > kUnknownErrAfRC )
  82. rc = kUnknownErrAfRC;
  83. cmErrMsg(&p->err,rc,"%s Error:%s",cmStringNullGuard(p->fn),_cmAudioFileErrArray[rc].msg);
  84. return rc;
  85. }
  86. cmAudioFileGuts* _cmAudioFileValidate( cmAudioFileH_t h, cmRC_t* rcPtr, bool writeFl )
  87. {
  88. *rcPtr = kOkAfRC;
  89. cmAudioFileGuts* p = _cmAudioFileGutsPtr(h);
  90. if( p == NULL )
  91. *rcPtr = kInvalidHandleAfRC;
  92. else
  93. if( cmIsFlag(p->flags,kWriteAudioGutsFl) != writeFl )
  94. *rcPtr = _cmAudioFileError( p, kInvalidFileModeAfRC );
  95. return *rcPtr == kOkAfRC ? p : NULL;
  96. }
  97. cmAudioFileGuts* _cmAudioFileReadGutsPtr( cmAudioFileH_t h, cmRC_t* rcPtr )
  98. { return _cmAudioFileValidate( h, rcPtr, false ); }
  99. cmAudioFileGuts* _cmAudioFileWriteGutsPtr( cmAudioFileH_t h, cmRC_t* rcPtr )
  100. { return _cmAudioFileValidate( h, rcPtr, true ); }
  101. cmRC_t _cmAudioFileSeek( cmAudioFileGuts* p, long byteOffset, int origin )
  102. {
  103. if( fseek(p->fp,byteOffset,origin) != 0 )
  104. return _cmAudioFileError(p,kSeekFailAfRC);
  105. return kOkAfRC;
  106. }
  107. cmRC_t _cmAudioFileRead( cmAudioFileGuts* p, void* eleBuf, unsigned bytesPerEle, unsigned eleCnt )
  108. {
  109. if( fread(eleBuf,bytesPerEle,eleCnt,p->fp) != eleCnt )
  110. return _cmAudioFileError(p,kReadFailAfRC);
  111. return kOkAfRC;
  112. }
  113. cmRC_t _cmAudioFileReadUInt32( cmAudioFileGuts* p, cmUInt32_t* valuePtr )
  114. {
  115. cmRC_t rc;
  116. if(( rc = _cmAudioFileRead(p, valuePtr, sizeof(*valuePtr), 1 )) != kOkAfRC )
  117. return rc;
  118. if( cmIsFlag(p->info.flags,kSwapAfFl) )
  119. *valuePtr = _cmAfSwap32(*valuePtr);
  120. return rc;
  121. }
  122. cmRC_t _cmAudioFileReadUInt16( cmAudioFileGuts* p, cmUInt16_t* valuePtr )
  123. {
  124. cmRC_t rc;
  125. if(( rc = _cmAudioFileRead(p, valuePtr, sizeof(*valuePtr), 1 )) != kOkAfRC )
  126. return rc;
  127. if( cmIsFlag(p->info.flags,kSwapAfFl) )
  128. *valuePtr = _cmAfSwap16(*valuePtr);
  129. return rc;
  130. }
  131. cmRC_t _cmAudioFileReadPascalString( cmAudioFileGuts* p, char s[kAudioFileLabelCharCnt] )
  132. {
  133. cmRC_t rc;
  134. unsigned char n;
  135. if((rc = _cmAudioFileRead(p,&n,sizeof(n),1)) != kOkAfRC )
  136. return rc;
  137. if((rc = _cmAudioFileRead(p,s,n,1)) != kOkAfRC )
  138. return rc;
  139. s[n] = '\0';
  140. if( n % 2 == 0 )
  141. rc = _cmAudioFileSeek(p,1,SEEK_CUR);
  142. return rc;
  143. }
  144. cmRC_t _cmAudioFileReadString( cmAudioFileGuts* p, char* s, unsigned sn )
  145. {
  146. cmRC_t rc;
  147. if((rc = _cmAudioFileRead(p,s,sn,1)) != kOkAfRC )
  148. return rc;
  149. return kOkAfRC;
  150. }
  151. cmRC_t _cmAudioFileReadX80( cmAudioFileGuts* p, double* x80Ptr )
  152. {
  153. unsigned char s[10];
  154. cmRC_t rc = kOkAfRC;
  155. if((rc = _cmAudioFileRead(p,s,10,1)) != kOkAfRC )
  156. return rc;
  157. *x80Ptr = cmX80ToDouble(s);
  158. return kOkAfRC;
  159. }
  160. cmRC_t _cmAudioFileReadChunkHdr( cmAudioFileGuts* p, cmUInt32_t* chkIdPtr, unsigned* chkByteCntPtr )
  161. {
  162. cmRC_t rc = kOkAfRC;
  163. *chkIdPtr = 0;
  164. *chkByteCntPtr = 0;
  165. if((rc = _cmAudioFileReadUInt32(p,chkIdPtr)) != kOkAfRC )
  166. return rc;
  167. if((rc = _cmAudioFileReadUInt32(p,chkByteCntPtr)) != kOkAfRC )
  168. return rc;
  169. // the actual on disk chunk size is always incrmented up to the next even integer
  170. *chkByteCntPtr += (*chkByteCntPtr) % 2;
  171. return rc;
  172. }
  173. cmRC_t _cmAudioFileReadAiffHeader( cmAudioFileGuts* p, unsigned constFormId, unsigned constAifId, bool swapFl )
  174. {
  175. cmRC_t rc = kOkAfRC;
  176. cmUInt32_t formId = 0;
  177. cmUInt32_t aifId = 0;
  178. unsigned chkByteCnt = 0;
  179. p->info.flags = 0;
  180. p->curFrmIdx = 0;
  181. p->fileByteCnt = 0;
  182. if((rc = _cmAudioFileSeek(p,0,SEEK_SET)) != kOkAfRC )
  183. return rc;
  184. // set the swap flags
  185. p->info.flags = cmEnaFlag(p->info.flags,kSwapAfFl, swapFl);
  186. p->info.flags = cmEnaFlag(p->info.flags,kSwapSamplesAfFl,swapFl);
  187. if((rc = _cmAudioFileReadChunkHdr(p,&formId,&p->fileByteCnt)) != kOkAfRC )
  188. return rc;
  189. //
  190. // use -Wno-multichar on GCC cmd line to disable the multi-char warning
  191. //
  192. // check the FORM/RIFF id
  193. if( formId != constFormId )
  194. return kNotAiffAfRC;
  195. // read the AIFF/WAVE id
  196. if((rc = _cmAudioFileReadChunkHdr(p,&aifId,&chkByteCnt)) != kOkAfRC )
  197. return rc;
  198. // check for the AIFC
  199. if( formId == kAiffFileId && aifId != constAifId )
  200. {
  201. if( aifId == kAifcChkId )
  202. p->info.flags = cmSetFlag(p->info.flags,kAifcAfFl);
  203. else
  204. return kNotAiffAfRC;
  205. }
  206. // set the audio file type flag
  207. if( aifId==kAiffChkId || aifId==kAifcChkId )
  208. p->info.flags = cmSetFlag(p->info.flags,kAiffAfFl);
  209. if( aifId==kWavChkId )
  210. p->info.flags = cmSetFlag(p->info.flags,kWavAfFl);
  211. return rc;
  212. }
  213. cmRC_t _cmAudioFileReadCommChunk( cmAudioFileGuts* p )
  214. {
  215. cmRC_t rc = kOkAfRC;
  216. cmUInt16_t ui16;
  217. cmUInt32_t ui32;
  218. if((rc = _cmAudioFileReadUInt16(p,&ui16)) != kOkAfRC )
  219. return rc;
  220. p->info.chCnt = ui16;
  221. if((rc = _cmAudioFileReadUInt32(p,&ui32)) != kOkAfRC )
  222. return rc;
  223. p->info.frameCnt = ui32;
  224. if((rc = _cmAudioFileReadUInt16(p,&ui16)) != kOkAfRC )
  225. return rc;
  226. p->info.bits = ui16;
  227. if((rc = _cmAudioFileReadX80(p,&p->info.srate)) != kOkAfRC )
  228. return rc;
  229. // if this is an AIFC format file ...
  230. if( cmIsFlag(p->info.flags,kAifcAfFl) )
  231. {
  232. if((rc = _cmAudioFileReadUInt32(p,&ui32)) != kOkAfRC )
  233. return rc;
  234. switch( ui32 )
  235. {
  236. case kNoneCompId:
  237. break;
  238. case kSowtCompId:
  239. // If the compression type is set to 'swot'
  240. // then the samples are written in little-endian (Intel) format
  241. // rather than the default big-endian format.
  242. p->info.flags = cmTogFlag(p->info.flags,kSwapSamplesAfFl);
  243. break;
  244. default:
  245. rc = _cmAudioFileError(p,kNotAiffAfRC );
  246. }
  247. }
  248. return rc;
  249. }
  250. cmRC_t _cmAudioFileReadSsndChunk( cmAudioFileGuts* p )
  251. {
  252. cmRC_t rc = kOkAfRC;
  253. cmUInt32_t smpOffs=0, smpBlkSize=0;
  254. if((rc = _cmAudioFileReadUInt32(p,&smpOffs)) != kOkAfRC )
  255. return rc;
  256. if((rc = _cmAudioFileReadUInt32(p,&smpBlkSize)) != kOkAfRC )
  257. return rc;
  258. if((rc = _cmAudioFileSeek(p,smpOffs, SEEK_CUR)) != kOkAfRC )
  259. return rc;
  260. p->smpByteOffs = ftell(p->fp);
  261. return rc;
  262. }
  263. cmRC_t _cmAudioFileReadMarkerChunk( cmAudioFileGuts* p )
  264. {
  265. cmRC_t rc = kOkAfRC;
  266. cmUInt16_t ui16;
  267. cmUInt32_t ui32;
  268. unsigned i;
  269. if((rc = _cmAudioFileReadUInt16(p,&ui16)) != kOkAfRC )
  270. return rc;
  271. p->info.markerCnt = ui16;
  272. assert(p->markArray == NULL);
  273. cmAudioFileMarker_t* m = cmMemAllocZ(cmAudioFileMarker_t,p->info.markerCnt);
  274. p->info.markerArray = m;
  275. for(i=0; i<p->info.markerCnt; ++i)
  276. {
  277. if((rc = _cmAudioFileReadUInt16(p,&ui16)) != kOkAfRC )
  278. return rc;
  279. m[i].id = ui16;
  280. if((rc = _cmAudioFileReadUInt32(p,&ui32)) != kOkAfRC )
  281. return rc;
  282. m[i].frameIdx = ui32;
  283. if((rc = _cmAudioFileReadPascalString(p,m[i].label)) != kOkAfRC )
  284. return rc;
  285. }
  286. return rc;
  287. }
  288. cmRC_t _cmAudioFileReadFmtChunk( cmAudioFileGuts* p )
  289. {
  290. cmRC_t rc = kOkAfRC;
  291. unsigned short fmtId, chCnt, blockAlign, bits;
  292. unsigned srate, bytesPerSec;
  293. if((rc = _cmAudioFileReadUInt16(p,&fmtId)) != kOkAfRC )
  294. return rc;
  295. if((rc = _cmAudioFileReadUInt16(p,&chCnt)) != kOkAfRC )
  296. return rc;
  297. if((rc = _cmAudioFileReadUInt32(p,&srate)) != kOkAfRC )
  298. return rc;
  299. if((rc = _cmAudioFileReadUInt32(p,&bytesPerSec)) != kOkAfRC )
  300. return rc;
  301. if((rc = _cmAudioFileReadUInt16(p,&blockAlign)) != kOkAfRC )
  302. return rc;
  303. if((rc = _cmAudioFileReadUInt16(p,&bits)) != kOkAfRC )
  304. return rc;
  305. p->info.chCnt = chCnt;
  306. p->info.bits = bits;
  307. p->info.srate = srate;
  308. // if the 'data' chunk was read before the 'fmt' chunk then info.frameCnt
  309. // holds the number of bytes in the data chunk
  310. if( p->info.frameCnt != 0 )
  311. p->info.frameCnt = p->info.frameCnt / (p->info.chCnt * p->info.bits/8);
  312. return rc;
  313. }
  314. cmRC_t _cmAudioFileReadDatcmhunk( cmAudioFileGuts* p, unsigned chkByteCnt )
  315. {
  316. // if the 'fmt' chunk was read before the 'data' chunk then info.chCnt is non-zero
  317. if( p->info.chCnt != 0 )
  318. p->info.frameCnt = chkByteCnt / (p->info.chCnt * p->info.bits/8);
  319. else
  320. p->info.frameCnt = chkByteCnt;
  321. p->smpByteOffs = ftell(p->fp);
  322. return kOkAfRC;
  323. }
  324. cmRC_t _cmAudioFileReadBextChunk( cmAudioFileGuts* p)
  325. {
  326. cmRC_t rc = kOkAfRC;
  327. if((rc = _cmAudioFileReadString(p,p->info.bextRecd.desc,kAfBextDescN)) != kOkAfRC )
  328. return rc;
  329. if((rc = _cmAudioFileReadString(p,p->info.bextRecd.origin,kAfBextOriginN)) != kOkAfRC )
  330. return rc;
  331. if((rc = _cmAudioFileReadString(p,p->info.bextRecd.originRef,kAfBextOriginRefN)) != kOkAfRC )
  332. return rc;
  333. if((rc = _cmAudioFileReadString(p,p->info.bextRecd.originDate,kAfBextOriginDateN)) != kOkAfRC )
  334. return rc;
  335. if((rc = _cmAudioFileReadString(p,p->info.bextRecd.originTime,kAfBextOriginTimeN)) != kOkAfRC )
  336. return rc;
  337. if((rc = _cmAudioFileReadUInt32(p,&p->info.bextRecd.timeRefLow)) != kOkAfRC )
  338. return rc;
  339. if((rc = _cmAudioFileReadUInt32(p,&p->info.bextRecd.timeRefHigh)) != kOkAfRC )
  340. return rc;
  341. return rc;
  342. }
  343. cmAudioFileH_t cmAudioFileNewOpen( const cmChar_t* fn, cmAudioFileInfo_t* afInfoPtr, cmRC_t* rcPtr, cmRpt_t* rpt )
  344. {
  345. cmAudioFileH_t h;
  346. cmRC_t rc = kOkAfRC;
  347. h.h = cmMemAllocZ( cmAudioFileGuts, 1 );
  348. cmErrSetup(&((cmAudioFileGuts*)h.h)->err,rpt,"Audio File");
  349. if( fn != NULL )
  350. if((rc = cmAudioFileOpen(h,fn,afInfoPtr)) != kOkAfRC )
  351. {
  352. if( rcPtr != NULL )
  353. *rcPtr = rc;
  354. cmAudioFileDelete(&h);
  355. }
  356. if( rcPtr != NULL )
  357. *rcPtr = rc;
  358. return h;
  359. }
  360. cmAudioFileH_t cmAudioFileNewCreate( const cmChar_t* fn, double srate, unsigned bits, unsigned chCnt, cmRC_t* rcPtr, cmRpt_t* rpt )
  361. {
  362. cmAudioFileH_t h;
  363. cmRC_t rc = kOkAfRC;
  364. h.h = cmMemAllocZ(cmAudioFileGuts,1);
  365. cmErrSetup(&((cmAudioFileGuts*)h.h)->err,rpt,"Audio File");
  366. if( fn != NULL )
  367. if((rc = cmAudioFileCreate(h,fn,srate,bits,chCnt)) != kOkAfRC )
  368. {
  369. if( rcPtr != NULL )
  370. *rcPtr = rc;
  371. cmAudioFileDelete(&h);
  372. }
  373. if( rcPtr != NULL )
  374. *rcPtr = rc;
  375. return h;
  376. }
  377. cmRC_t cmAudioFileOpen( cmAudioFileH_t h, const cmChar_t* fn, cmAudioFileInfo_t* infoPtr )
  378. {
  379. cmRC_t rc = kOkAfRC;
  380. cmAudioFileGuts* p = _cmAudioFileGutsPtr(h);
  381. // verify the file is closed before opening
  382. if( cmAudioFileIsOpen(h) )
  383. if((rc = cmAudioFileClose(&h)) != kOkAfRC )
  384. return rc;
  385. // zero the info record
  386. memset(&p->info,0,sizeof(p->info));
  387. // open the file
  388. if((p->fp = fopen(fn,"rb")) == NULL )
  389. {
  390. p->fn = (cmChar_t*)fn; // set the file name so that the error msg can use it
  391. rc = _cmAudioFileError(p,kOpenFailAfRC);
  392. p->fn = NULL;
  393. goto errLabel;
  394. }
  395. // read the file header
  396. if((rc = _cmAudioFileReadAiffHeader(p,kAiffFileId,kAiffChkId,_cmAifSwapFl)) != kOkAfRC )
  397. if((rc = _cmAudioFileReadAiffHeader(p,kWavFileId,kWavChkId,_cmWavSwapFl)) != kOkAfRC )
  398. goto errLabel;
  399. // seek past the file header
  400. if((rc = _cmAudioFileSeek(p,12,SEEK_SET)) != kOkAfRC )
  401. goto errLabel;
  402. // zero chCnt and frameCnt to allow the order of the 'data' and 'fmt' chunks to be noticed
  403. p->info.chCnt = 0;
  404. p->info.frameCnt = 0;
  405. while( ftell(p->fp ) < p->fileByteCnt )
  406. {
  407. unsigned chkId, chkByteCnt;
  408. if((rc = _cmAudioFileReadChunkHdr(p,&chkId,&chkByteCnt)) != kOkAfRC )
  409. goto errLabel;
  410. unsigned offs = ftell(p->fp);
  411. if( cmIsFlag(p->info.flags,kAiffAfFl) )
  412. switch(chkId)
  413. {
  414. case 'COMM':
  415. if((rc = _cmAudioFileReadCommChunk(p)) != kOkAfRC )
  416. goto errLabel;
  417. break;
  418. case 'SSND':
  419. if((rc = _cmAudioFileReadSsndChunk(p)) != kOkAfRC )
  420. goto errLabel;
  421. break;
  422. case 'MARK':
  423. if((rc = _cmAudioFileReadMarkerChunk(p)) != kOkAfRC )
  424. goto errLabel;
  425. break;
  426. }
  427. else
  428. switch(chkId)
  429. {
  430. case ' tmf':
  431. if((rc = _cmAudioFileReadFmtChunk(p)) != kOkAfRC )
  432. goto errLabel;
  433. break;
  434. case 'atad':
  435. if((rc = _cmAudioFileReadDatcmhunk(p,chkByteCnt)) != kOkAfRC )
  436. goto errLabel;
  437. break;
  438. case 'txeb':
  439. if((rc = _cmAudioFileReadBextChunk(p)) != kOkAfRC )
  440. goto errLabel;
  441. break;
  442. }
  443. // seek to the end of this chunk
  444. if((rc = _cmAudioFileSeek(p,offs+chkByteCnt,SEEK_SET)) != kOkAfRC )
  445. goto errLabel;
  446. }
  447. // seek to the first sample offset
  448. if((rc = _cmAudioFileSeek(p,p->smpByteOffs,SEEK_SET)) != kOkAfRC )
  449. goto errLabel;
  450. p->fn = cmMemResize( char, p->fn, strlen(fn)+1 );
  451. strcpy(p->fn,fn);
  452. if( infoPtr != NULL)
  453. memcpy(infoPtr,&p->info,sizeof(*infoPtr));
  454. return rc;
  455. errLabel:
  456. cmAudioFileClose(&h);
  457. return rc;
  458. }
  459. cmRC_t _cmAudioFileWriteBytes( cmAudioFileGuts* p, const void* b, unsigned bn )
  460. {
  461. cmRC_t rc = kOkAfRC;
  462. if( fwrite( b, bn, 1, p->fp ) != 1 )
  463. return _cmAudioFileError(p,kWriteFailAfRC);
  464. return rc;
  465. }
  466. cmRC_t _cmAudioFileWriteId( cmAudioFileGuts* p, const char* s )
  467. { return _cmAudioFileWriteBytes( p, s, strlen(s)) ; }
  468. cmRC_t _cmAudioFileWriteUInt32( cmAudioFileGuts* p, unsigned v )
  469. {
  470. v = _cmAfSwap32(v);
  471. return _cmAudioFileWriteBytes( p, &v, sizeof(v)) ;
  472. }
  473. cmRC_t _cmAudioFileWriteUInt16( cmAudioFileGuts* p, unsigned short v )
  474. {
  475. v = _cmAfSwap16(v);
  476. return _cmAudioFileWriteBytes( p, &v, sizeof(v)) ;
  477. }
  478. cmRC_t _cmAudioFileWriteHdr( cmAudioFileGuts* p )
  479. {
  480. cmRC_t rc = kOkAfRC;
  481. unsigned char srateX80[10];
  482. cmDoubleToX80( p->info.srate, srateX80 );
  483. unsigned hdrByteCnt = 54;
  484. unsigned ssndByteCnt = 8 + (p->info.chCnt * p->info.frameCnt * (p->info.bits/8));
  485. unsigned formByteCnt = hdrByteCnt + ssndByteCnt - 8;
  486. unsigned commByteCnt = 18;
  487. unsigned ssndSmpOffs = 0;
  488. unsigned ssndBlkSize = 0;
  489. if( cmIsOddU( ssndByteCnt ) )
  490. {
  491. formByteCnt++;
  492. }
  493. if(( rc = _cmAudioFileSeek( p, 0, SEEK_SET )) != kOkAfRC )
  494. return rc;
  495. if(( rc = _cmAudioFileWriteId( p, "FORM")) != kOkAfRC ) return rc;
  496. if(( rc = _cmAudioFileWriteUInt32( p, formByteCnt)) != kOkAfRC ) return rc;
  497. if(( rc = _cmAudioFileWriteId( p, "AIFF")) != kOkAfRC ) return rc;
  498. if(( rc = _cmAudioFileWriteId( p, "COMM")) != kOkAfRC ) return rc;
  499. if(( rc = _cmAudioFileWriteUInt32( p, commByteCnt)) != kOkAfRC ) return rc;
  500. if(( rc = _cmAudioFileWriteUInt16( p, p->info.chCnt)) != kOkAfRC ) return rc;
  501. if(( rc = _cmAudioFileWriteUInt32( p, p->info.frameCnt)) != kOkAfRC ) return rc;
  502. if(( rc = _cmAudioFileWriteUInt16( p, p->info.bits)) != kOkAfRC ) return rc;
  503. if(( rc = _cmAudioFileWriteBytes( p, &srateX80,10)) != kOkAfRC ) return rc;
  504. if(( rc = _cmAudioFileWriteId( p, "SSND")) != kOkAfRC ) return rc;
  505. if(( rc = _cmAudioFileWriteUInt32( p, ssndByteCnt)) != kOkAfRC ) return rc;
  506. if(( rc = _cmAudioFileWriteUInt32( p, ssndSmpOffs)) != kOkAfRC ) return rc;
  507. if(( rc = _cmAudioFileWriteUInt32( p, ssndBlkSize)) != kOkAfRC ) return rc;
  508. return rc;
  509. }
  510. cmRC_t cmAudioFileCreate( cmAudioFileH_t h, const cmChar_t* fn, double srate, unsigned bits, unsigned chCnt )
  511. {
  512. cmRC_t rc = kOkAfRC;
  513. cmAudioFileGuts* p = _cmAudioFileGutsPtr(h);
  514. cmFileSysPathPart_t* pp = NULL;
  515. // verify the file is closed before opening
  516. if( cmAudioFileIsOpen(h) )
  517. if((rc = cmAudioFileClose(&h)) != kOkAfRC )
  518. return rc;
  519. // all audio files are written as AIF's - if the file name is given some other extension then issue a warning
  520. if( fn!=NULL && strlen(fn) && ((pp = cmFsPathParts(fn)) != NULL) )
  521. {
  522. unsigned i;
  523. unsigned n = pp->extStr==NULL ? 0 : strlen(pp->extStr);
  524. cmChar_t ext[n+1];
  525. if( pp->extStr != NULL )
  526. {
  527. strcpy(ext,pp->extStr);
  528. // convert the extension to upper case
  529. for(i=0; i<n; ++i)
  530. ext[i] = toupper(ext[i]);
  531. }
  532. if( pp->extStr==NULL || (strcmp(ext,"AIF") && strcmp(ext,"AIFF")) )
  533. cmRptPrintf(p->err.rpt,"The AIF audio file '%s' is being written with a file extension other than 'AIF' or 'AIFF'.",cmStringNullGuard(fn));
  534. cmFsFreePathParts(pp);
  535. }
  536. // open the file
  537. if((p->fp = fopen(fn,"wb")) == NULL )
  538. {
  539. p->fn = (cmChar_t*)fn; // set the file name so that the error msg can use it
  540. rc = _cmAudioFileError(p,kOpenFailAfRC);
  541. p->fn = NULL;
  542. goto errLabel;
  543. }
  544. p->fn = cmMemResize( char, p->fn, strlen(fn)+1 );
  545. p->info.srate = srate;
  546. p->info.bits = bits;
  547. p->info.chCnt = chCnt;
  548. p->info.frameCnt = 0;
  549. p->flags = kWriteAudioGutsFl;
  550. strcpy(p->fn,fn);
  551. if((rc = _cmAudioFileWriteHdr( p )) != kOkAfRC )
  552. goto errLabel;
  553. return rc;
  554. errLabel:
  555. cmAudioFileClose(&h);
  556. return rc;
  557. }
  558. cmRC_t cmAudioFileClose( cmAudioFileH_t* h )
  559. {
  560. assert( h != NULL);
  561. cmAudioFileGuts* p = _cmAudioFileGutsPtr(*h);
  562. cmRC_t rc = kOkAfRC;
  563. if( p->fp == NULL )
  564. return kOkAfRC;
  565. if( cmIsFlag( p->flags, kWriteAudioGutsFl ) )
  566. if((rc = _cmAudioFileWriteHdr(p)) != kOkAfRC )
  567. return rc;
  568. if( fclose(p->fp) != 0 )
  569. rc = _cmAudioFileError(p,kCloseFailAfRC);
  570. else
  571. {
  572. p->fp = NULL;
  573. cmMemPtrFree( &(p->info.markerArray));
  574. memset(&p->info,0,sizeof(p->info));
  575. }
  576. return rc;
  577. }
  578. cmRC_t cmAudioFileDelete( cmAudioFileH_t* h)
  579. {
  580. assert(h!=NULL);
  581. cmRC_t rc = kOkAfRC;
  582. // prevent double deletes
  583. if( h->h == NULL )
  584. return kOkAfRC;
  585. cmAudioFileGuts* p = _cmAudioFileGutsPtr(*h);
  586. if( p->fp != NULL )
  587. rc = cmAudioFileClose(h);
  588. cmMemPtrFree(&p->fn);
  589. cmMemPtrFree(&(h->h));
  590. return rc;
  591. }
  592. bool cmAudioFileIsValid( cmAudioFileH_t h )
  593. { return h.h != NULL; }
  594. bool cmAudioFileIsOpen( cmAudioFileH_t h )
  595. {
  596. if( !cmAudioFileIsValid(h) )
  597. return false;
  598. return _cmAudioFileGutsPtr(h)->fp != NULL;
  599. }
  600. bool cmAudioFileIsEOF( cmAudioFileH_t h )
  601. {
  602. cmRC_t rc = kOkAfRC;
  603. cmAudioFileGuts* p = _cmAudioFileReadGutsPtr(h,&rc);
  604. return (rc != kOkAfRC) || (p==NULL) || (p->curFrmIdx >= p->info.frameCnt) || (p->fp==NULL) || feof(p->fp) ? true : false;
  605. }
  606. unsigned cmAudioFileTell( cmAudioFileH_t h )
  607. {
  608. cmRC_t rc = kOkAfRC;
  609. cmAudioFileGuts* p = _cmAudioFileReadGutsPtr(h,&rc);
  610. return (rc==kOkAfRC && p!=NULL) ? p->curFrmIdx : cmInvalidIdx;
  611. }
  612. cmRC_t cmAudioFileSeek( cmAudioFileH_t h, unsigned frmIdx )
  613. {
  614. cmRC_t rc = kOkAfRC;
  615. cmAudioFileGuts* p = _cmAudioFileReadGutsPtr(h,&rc);
  616. if( rc != kOkAfRC )
  617. return rc;
  618. if((rc = _cmAudioFileSeek(p,p->smpByteOffs + (frmIdx * p->info.chCnt * (p->info.bits/8)), SEEK_SET)) != kOkAfRC )
  619. return rc;
  620. p->curFrmIdx = frmIdx;
  621. return rc;
  622. }
  623. cmRC_t _cmAudioFileReadInt( cmAudioFileH_t h, unsigned totalFrmCnt, unsigned chIdx, unsigned chCnt, int* buf[], unsigned* actualFrmCntPtr, bool sumFl )
  624. {
  625. cmRC_t rc = kOkAfRC;
  626. cmAudioFileGuts* p = _cmAudioFileReadGutsPtr(h,&rc);
  627. if( rc != kOkAfRC )
  628. return rc;
  629. if( chIdx+chCnt > p->info.chCnt )
  630. return _cmAudioFileError(p,kInvalidChCountAfRC);
  631. if( actualFrmCntPtr != NULL )
  632. *actualFrmCntPtr = 0;
  633. unsigned bps = p->info.bits / 8; // bytes per sample
  634. unsigned bpf = bps * p->info.chCnt; // bytes per file frame
  635. unsigned bufFrmCnt = cmMin(totalFrmCnt,cmAudioFile_MAX_FRAME_READ_CNT);
  636. unsigned bytesPerBuf = bufFrmCnt * bpf;
  637. unsigned char fbuf[ bytesPerBuf ]; // raw bytes buffer
  638. unsigned ci;
  639. unsigned frmCnt = 0;
  640. unsigned totalReadFrmCnt;
  641. int* ptrBuf[ chCnt ];
  642. for(ci=0; ci<chCnt; ++ci)
  643. ptrBuf[ci] = buf[ci];
  644. for(totalReadFrmCnt=0; totalReadFrmCnt<totalFrmCnt; totalReadFrmCnt+=frmCnt )
  645. {
  646. // don't read past the end of the file or past the end of the buffer
  647. frmCnt = cmMin( p->info.frameCnt - p->curFrmIdx, cmMin( totalFrmCnt-totalReadFrmCnt, bufFrmCnt ));
  648. // read the file frmCnt sample
  649. if((rc = _cmAudioFileRead(p,fbuf,frmCnt*bpf,1)) != kOkAfRC )
  650. return rc;
  651. if( actualFrmCntPtr != NULL )
  652. *actualFrmCntPtr += frmCnt;
  653. assert( chIdx+chCnt <= p->info.chCnt );
  654. for(ci=0; ci<chCnt; ++ci)
  655. {
  656. unsigned char* sp = fbuf + (ci+chIdx)*bps;
  657. int* dp = ptrBuf[ci];
  658. int* ep = dp + frmCnt;
  659. if( !sumFl )
  660. memset(dp,0,frmCnt*sizeof(int));
  661. // 8 bit AIF files use 'signed char' and WAV files use 'unsigned char' for the sample data type.
  662. if( p->info.bits == 8 )
  663. {
  664. if( cmIsFlag(p->info.flags,kAiffAfFl) )
  665. {
  666. for(; dp<ep; sp+=bpf,++dp)
  667. *dp += *(char*)sp;
  668. }
  669. else
  670. {
  671. for(; dp<ep; sp+=bpf,++dp)
  672. {
  673. int v = *(unsigned char*)sp;
  674. *dp += v -= 128;
  675. }
  676. }
  677. }
  678. // handle non-8 bit files here
  679. if( cmIsFlag(p->info.flags,kSwapSamplesAfFl) )
  680. {
  681. switch( p->info.bits )
  682. {
  683. case 8:
  684. break;
  685. case 16:
  686. for(; dp<ep; sp+=bpf,++dp)
  687. *dp += (short)_cmAfSwap16(*(short*)sp);
  688. break;
  689. case 24:
  690. if( cmIsFlag(p->info.flags,kAiffAfFl) )
  691. {
  692. for(; dp<ep; sp+=bpf,++dp)
  693. *dp += (int)(_cmAfSwap32(_24to32_aif(sp)));
  694. }
  695. else
  696. {
  697. for(; dp<ep; sp+=bpf,++dp)
  698. *dp += (int)(_cmAfSwap32(_24to32_wav(sp)));
  699. }
  700. break;
  701. case 32:
  702. for(; dp<ep; sp+=bpf,++dp)
  703. *dp += (int)_cmAfSwap32(*(int*)sp );
  704. break;
  705. }
  706. }
  707. else
  708. {
  709. switch(p->info.bits)
  710. {
  711. case 8:
  712. break;
  713. case 16:
  714. for(; dp<ep; sp+=bpf,++dp)
  715. *dp += *(short*)sp;
  716. break;
  717. case 24:
  718. if( cmIsFlag(p->info.flags,kAiffAfFl) )
  719. {
  720. for(; dp<ep; sp+=bpf,++dp)
  721. *dp += _24to32_aif(sp);
  722. }
  723. else
  724. {
  725. for(; dp<ep; sp+=bpf,++dp)
  726. *dp += _24to32_wav(sp);
  727. }
  728. break;
  729. case 32:
  730. for(; dp<ep; sp+=bpf,++dp)
  731. *dp += *(int*)sp;
  732. break;
  733. }
  734. ptrBuf[ci] = dp;
  735. assert( dp <= buf[ci] + totalFrmCnt );
  736. }
  737. /*
  738. dp = ptrBuf[ci];
  739. ep = dp + frmCnt;
  740. while(dp<ep)
  741. sum += (double)*dp++;
  742. */
  743. }
  744. p->curFrmIdx += frmCnt;
  745. }
  746. if( totalReadFrmCnt < totalFrmCnt )
  747. {
  748. for(ci=0; ci<chCnt; ++ci)
  749. memset(buf[ci] + frmCnt,0,(totalFrmCnt-totalReadFrmCnt)*sizeof(int));
  750. }
  751. //if( actualFrmCntPtr != NULL )
  752. // *actualFrmCntPtr = totalReadFrmCnt;
  753. //printf("SUM: %f %f swap:%i\n", sum, sum/(totalFrmCnt*chCnt), cmIsFlag(p->info.flags,kSwapAfFl));
  754. return rc;
  755. }
  756. cmRC_t _cmAudioFileReadRealSamples( cmAudioFileH_t h, unsigned totalFrmCnt, unsigned chIdx, unsigned chCnt, float** fbuf, double** dbuf, unsigned* actualFrmCntPtr, bool sumFl )
  757. {
  758. cmRC_t rc = kOkAfRC;
  759. cmAudioFileGuts* p = _cmAudioFileReadGutsPtr(h,&rc);
  760. if( rc != kOkAfRC )
  761. return rc;
  762. if( actualFrmCntPtr != NULL )
  763. *actualFrmCntPtr = 0;
  764. unsigned totalReadCnt = 0;
  765. unsigned bufFrmCnt = cmMin( totalFrmCnt, cmAudioFile_MAX_FRAME_READ_CNT );
  766. unsigned bufSmpCnt = bufFrmCnt * chCnt;
  767. float fltMaxSmpVal = 0;
  768. int buf[ bufSmpCnt ];
  769. int* ptrBuf[ chCnt ];
  770. float* fPtrBuf[ chCnt ];
  771. double* dPtrBuf[ chCnt ];
  772. unsigned i;
  773. unsigned frmCnt = 0;
  774. switch( p->info.bits )
  775. {
  776. case 8: fltMaxSmpVal = 0x80; break;
  777. case 16: fltMaxSmpVal = 0x8000; break;
  778. case 24: fltMaxSmpVal = 0x800000; break;
  779. case 32: fltMaxSmpVal = 0x80000000; break;
  780. default:
  781. return _cmAudioFileError(p,kInvalidBitWidthAfRC);
  782. }
  783. double dblMaxSmpVal = fltMaxSmpVal;
  784. // initialize the audio ptr buffers
  785. for(i=0; i<chCnt; ++i)
  786. {
  787. ptrBuf[i] = buf + (i*bufFrmCnt);
  788. if( dbuf != NULL )
  789. dPtrBuf[i] = dbuf[i];
  790. if( fbuf != NULL )
  791. fPtrBuf[i] = fbuf[i];
  792. }
  793. //
  794. for(totalReadCnt=0; totalReadCnt<totalFrmCnt && p->curFrmIdx < p->info.frameCnt; totalReadCnt+=frmCnt)
  795. {
  796. unsigned actualReadFrmCnt = 0;
  797. frmCnt = cmMin( p->info.frameCnt - p->curFrmIdx, cmMin( totalFrmCnt-totalReadCnt, bufFrmCnt ) );
  798. // fill the integer audio buffer from the file
  799. if((rc = _cmAudioFileReadInt( h, frmCnt, chIdx, chCnt, ptrBuf, &actualReadFrmCnt, false )) != kOkAfRC )
  800. return rc;
  801. if( actualFrmCntPtr != NULL )
  802. *actualFrmCntPtr += actualReadFrmCnt;
  803. // convert the integer buffer to floating point
  804. for(i=0; i<chCnt; ++i)
  805. {
  806. int* sp = ptrBuf[i];
  807. if( fbuf != NULL )
  808. {
  809. float* dp = fPtrBuf[i];
  810. float* ep = dp + frmCnt;
  811. if( sumFl )
  812. {
  813. for(; dp<ep; ++dp,++sp)
  814. *dp += ((float)*sp) / fltMaxSmpVal;
  815. }
  816. else
  817. {
  818. for(; dp<ep; ++dp,++sp)
  819. *dp = ((float)*sp) / fltMaxSmpVal;
  820. }
  821. assert( dp <= fbuf[i] + totalFrmCnt );
  822. fPtrBuf[i] = dp;
  823. }
  824. else
  825. {
  826. double* dp = dPtrBuf[i];
  827. double* ep = dp + frmCnt;
  828. if( sumFl )
  829. {
  830. for(; dp<ep; ++dp,++sp)
  831. *dp += ((double)*sp) / dblMaxSmpVal;
  832. }
  833. else
  834. {
  835. for(; dp<ep; ++dp,++sp)
  836. *dp = ((double)*sp) / dblMaxSmpVal;
  837. }
  838. assert( dp <= dbuf[i] + totalFrmCnt );
  839. dPtrBuf[i] = dp;
  840. }
  841. }
  842. }
  843. return rc;
  844. }
  845. cmRC_t _cmAudioFileReadFloat( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, bool sumFl )
  846. {
  847. return _cmAudioFileReadRealSamples(h,frmCnt,chIdx,chCnt,buf, NULL, actualFrmCntPtr, sumFl );
  848. }
  849. cmRC_t _cmAudioFileReadDouble( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, bool sumFl )
  850. {
  851. return _cmAudioFileReadRealSamples(h,frmCnt,chIdx,chCnt,NULL, buf, actualFrmCntPtr, sumFl );
  852. }
  853. cmRC_t cmAudioFileReadInt( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr )
  854. { return _cmAudioFileReadInt( h, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, false ); }
  855. cmRC_t cmAudioFileReadFloat( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr )
  856. { return _cmAudioFileReadFloat( h, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, false ); }
  857. cmRC_t cmAudioFileReadDouble( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr )
  858. { return _cmAudioFileReadDouble( h, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, false ); }
  859. cmRC_t cmAudioFileReadSumInt( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr )
  860. { return _cmAudioFileReadInt( h, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, true ); }
  861. cmRC_t cmAudioFileReadSumFloat( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr )
  862. { return _cmAudioFileReadFloat( h, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, true ); }
  863. cmRC_t cmAudioFileReadSumDouble( cmAudioFileH_t h, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr )
  864. { return _cmAudioFileReadDouble( h, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, true ); }
  865. cmRC_t _cmAudioFileGet( const char* fn, unsigned begFrmIdx, cmAudioFileH_t* hp, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt )
  866. {
  867. cmRC_t rc = kOkAfRC;
  868. *hp = cmAudioFileNewOpen( fn, afInfoPtr, &rc, rpt );
  869. if( (cmAudioFileIsValid(*hp)==false) || (rc!=kOkAfRC) )
  870. return rc;
  871. if( begFrmIdx > 0 )
  872. if((rc = cmAudioFileSeek( *hp, begFrmIdx )) != kOkAfRC )
  873. cmAudioFileDelete(hp);
  874. return rc;
  875. }
  876. cmRC_t _cmAudioFileGetInt( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, bool sumFl, cmRpt_t* rpt )
  877. {
  878. cmRC_t rc0,rc1;
  879. cmAudioFileH_t h;
  880. if((rc0 = _cmAudioFileGet(fn,begFrmIdx,&h,afInfoPtr,rpt)) != kOkAfRC )
  881. return rc0;
  882. rc0 = _cmAudioFileReadInt(h, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, sumFl );
  883. if((rc1=cmAudioFileDelete(&h)) != kOkAfRC && rc0==kOkAfRC )
  884. rc0 = rc1;
  885. return rc0;
  886. }
  887. cmRC_t _cmAudioFileGetFloat( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, bool sumFl, cmRpt_t* rpt )
  888. {
  889. cmRC_t rc0,rc1;
  890. cmAudioFileH_t h;
  891. if((rc0 = _cmAudioFileGet(fn,begFrmIdx,&h,afInfoPtr,rpt)) != kOkAfRC )
  892. return rc0;
  893. rc0 = _cmAudioFileReadFloat(h, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, sumFl );
  894. if((rc1=cmAudioFileDelete(&h)) != kOkAfRC && rc0==kOkAfRC )
  895. rc0 = rc1;
  896. return rc0;
  897. }
  898. cmRC_t _cmAudioFileGetDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, bool sumFl, cmRpt_t* rpt )
  899. {
  900. cmRC_t rc0,rc1;
  901. cmAudioFileH_t h;
  902. if((rc0 = _cmAudioFileGet(fn,begFrmIdx,&h,afInfoPtr,rpt)) != kOkAfRC )
  903. return rc0;
  904. rc0 = _cmAudioFileReadDouble(h, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, sumFl );
  905. if((rc1=cmAudioFileDelete(&h)) != kOkAfRC && rc0==kOkAfRC )
  906. rc0 = rc1;
  907. return rc0;
  908. }
  909. cmRC_t cmAudioFileGetInt( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt )
  910. { return _cmAudioFileGetInt( fn, begFrmIdx, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, afInfoPtr, false, rpt ); }
  911. cmRC_t cmAudioFileGetFloat( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt )
  912. { return _cmAudioFileGetFloat( fn, begFrmIdx, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, afInfoPtr, false, rpt ); }
  913. cmRC_t cmAudioFileGetDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt )
  914. { return _cmAudioFileGetDouble( fn, begFrmIdx, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, afInfoPtr, false, rpt); }
  915. cmRC_t cmAudioFileGetSumInt( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, int** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt )
  916. { return _cmAudioFileGetInt( fn, begFrmIdx, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, afInfoPtr, true, rpt ); }
  917. cmRC_t cmAudioFileGetSumFloat( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt )
  918. { return _cmAudioFileGetFloat( fn, begFrmIdx, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, afInfoPtr, true, rpt ); }
  919. cmRC_t cmAudioFileGetSumDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, cmAudioFileInfo_t* afInfoPtr, cmRpt_t* rpt )
  920. { return _cmAudioFileGetDouble( fn, begFrmIdx, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, afInfoPtr, true, rpt); }
  921. cmRC_t cmAudioFileWriteInt( cmAudioFileH_t h, unsigned frmCnt, unsigned chCnt, int** srcPtrPtr )
  922. {
  923. cmRC_t rc = kOkAfRC;
  924. cmAudioFileGuts* p = _cmAudioFileWriteGutsPtr(h,&rc );
  925. if( rc != kOkAfRC )
  926. return rc;
  927. unsigned bytesPerSmp = p->info.bits / 8;
  928. unsigned bufFrmCnt = 1024;
  929. unsigned bufByteCnt = bufFrmCnt * bytesPerSmp;
  930. unsigned ci;
  931. unsigned wrFrmCnt = 0;
  932. char buf[ bufByteCnt * chCnt ];
  933. while( wrFrmCnt < frmCnt )
  934. {
  935. unsigned n = cmMin( frmCnt-wrFrmCnt, bufFrmCnt );
  936. for(ci=0; ci<chCnt; ++ci)
  937. {
  938. const int* sbp = srcPtrPtr[ci] + wrFrmCnt;
  939. const int* sep = sbp + n;
  940. switch( p->info.bits )
  941. {
  942. case 8:
  943. {
  944. char* dbp = buf + ci;
  945. for(; sbp < sep; dbp+=chCnt )
  946. *dbp = (char)*sbp++;
  947. }
  948. break;
  949. case 16:
  950. {
  951. short* dbp = (short*)buf;
  952. for(dbp+=ci; sbp < sep; dbp+=chCnt, ++sbp )
  953. *dbp = _cmAfSwap16((short)*sbp);
  954. }
  955. break;
  956. case 24:
  957. {
  958. unsigned char* dbp = (unsigned char*)buf;
  959. for( dbp+=(ci*3); sbp < sep; dbp+=(3*chCnt), ++sbp)
  960. {
  961. unsigned char* s = (unsigned char*)sbp;
  962. dbp[0] = s[2];
  963. dbp[1] = s[1];
  964. dbp[2] = s[0];
  965. }
  966. }
  967. break;
  968. case 32:
  969. {
  970. int* dbp = (int*)buf;
  971. for(dbp+=ci; sbp < sep; dbp+=chCnt, ++sbp )
  972. *dbp = _cmAfSwap32(*sbp);
  973. }
  974. break;
  975. default:
  976. { assert(0);}
  977. }
  978. }
  979. wrFrmCnt+=n;
  980. if( fwrite( buf, n*bytesPerSmp*chCnt, 1, p->fp ) != 1)
  981. {
  982. rc = _cmAudioFileError(p,kWriteFailAfRC);
  983. break;
  984. }
  985. }
  986. p->info.frameCnt += wrFrmCnt;
  987. return rc;
  988. }
  989. cmRC_t _cmAudioFileWriteRealSamples( cmAudioFileH_t h, unsigned frmCnt, unsigned chCnt, const void* srcPtrPtr, unsigned realSmpByteCnt )
  990. {
  991. cmRC_t rc = kOkAfRC;
  992. cmAudioFileGuts* p = _cmAudioFileWriteGutsPtr(h,&rc );
  993. if( rc != kOkAfRC )
  994. return rc;
  995. unsigned bufFrmCnt = 1024;
  996. unsigned wrFrmCnt = 0;
  997. unsigned i = 0;
  998. int maxSmpVal = 0;
  999. int buf[ chCnt * bufFrmCnt ];
  1000. int* srcCh[ chCnt ];
  1001. for(i=0; i<chCnt; ++i)
  1002. srcCh[i] = buf + (i*bufFrmCnt);
  1003. switch( p->info.bits )
  1004. {
  1005. case 8: maxSmpVal = 0x7f; break;
  1006. case 16: maxSmpVal = 0x7fff; break;
  1007. case 24: maxSmpVal = 0x7fffff; break;
  1008. case 32: maxSmpVal = 0x7fffffb0; break; // Note: the full range is not used for 32 bit numbers
  1009. default: // because it was found to cause difficult to detect overflows
  1010. { assert(0); } // when the signal approached full scale.
  1011. }
  1012. // duplicate the audio buffer ptr array - this will allow the buffer ptr's to be changed
  1013. // during the float to int conversion without changing the ptrs passed in from the client
  1014. const void* ptrArray[ chCnt ];
  1015. memcpy(ptrArray,srcPtrPtr,sizeof(ptrArray));
  1016. const float** sfpp = (const float**)ptrArray;
  1017. const double** sdpp = (const double**)ptrArray;
  1018. while( wrFrmCnt < frmCnt )
  1019. {
  1020. unsigned n = cmMin( frmCnt - wrFrmCnt, bufFrmCnt );
  1021. for(i=0; i<chCnt; ++i)
  1022. {
  1023. int* obp = srcCh[i];
  1024. switch( realSmpByteCnt )
  1025. {
  1026. case 4:
  1027. {
  1028. const float* sbp = sfpp[i];
  1029. const float* sep = sbp + n;
  1030. for(;sbp<sep; ++sbp)
  1031. {
  1032. *obp++ = (int)fmaxf(-maxSmpVal,fminf(maxSmpVal, *sbp * maxSmpVal));
  1033. }
  1034. sfpp[i] = sbp;
  1035. }
  1036. break;
  1037. case 8:
  1038. {
  1039. const double* sbp = sdpp[i];
  1040. const double* sep = sbp + n;
  1041. for(; sbp<sep; ++sbp)
  1042. {
  1043. *obp++ = (int)fmax(-maxSmpVal,fmin(maxSmpVal,*sbp * maxSmpVal));
  1044. }
  1045. sdpp[i] = sbp;
  1046. }
  1047. break;
  1048. default:
  1049. { assert(0); }
  1050. }
  1051. }
  1052. if((rc = cmAudioFileWriteInt( h, n, chCnt, srcCh )) != kOkAfRC )
  1053. break;
  1054. wrFrmCnt += n;
  1055. }
  1056. return rc;
  1057. }
  1058. cmRC_t cmAudioFileWriteFloat( cmAudioFileH_t h, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr )
  1059. { return _cmAudioFileWriteRealSamples(h,frmCnt,chCnt,bufPtrPtr,sizeof(float)); }
  1060. cmRC_t cmAudioFileWriteDouble( cmAudioFileH_t h, unsigned frmCnt, unsigned chCnt, double** bufPtrPtr )
  1061. { return _cmAudioFileWriteRealSamples(h,frmCnt,chCnt,bufPtrPtr,sizeof(double)); }
  1062. cmRC_t cmAudioFileMinMaxMean( cmAudioFileH_t h, unsigned chIdx, cmSample_t* minPtr, cmSample_t* maxPtr, cmSample_t* meanPtr )
  1063. {
  1064. assert( minPtr != NULL && maxPtr != NULL && meanPtr != NULL );
  1065. *minPtr = -cmSample_MAX;
  1066. *maxPtr = cmSample_MAX;
  1067. *meanPtr = 0;
  1068. cmRC_t rc = kOkAfRC;
  1069. cmAudioFileGuts* p = _cmAudioFileReadGutsPtr(h,&rc );
  1070. if( rc != kOkAfRC )
  1071. return rc;
  1072. unsigned orgFrmIdx = p->curFrmIdx;
  1073. if((rc = cmAudioFileSeek(h,0)) != kOkAfRC )
  1074. return rc;
  1075. *minPtr = cmSample_MAX;
  1076. *maxPtr = -cmSample_MAX;
  1077. unsigned bufN = 1024;
  1078. cmSample_t buf[ bufN ];
  1079. unsigned frmCnt = 0;
  1080. unsigned actualFrmCnt;
  1081. cmSample_t* bufPtr[1] = { &buf[0] };
  1082. for(; frmCnt<p->info.frameCnt; frmCnt+=actualFrmCnt)
  1083. {
  1084. actualFrmCnt = 0;
  1085. unsigned n = cmMin( p->info.frameCnt-frmCnt, bufN );
  1086. if((rc = cmAudioFileReadSample(h, n, chIdx, 1, bufPtr, &actualFrmCnt)) != kOkAfRC )
  1087. return rc;
  1088. const cmSample_t* sbp = buf;
  1089. const cmSample_t* sep = buf + actualFrmCnt;
  1090. for(; sbp < sep; ++sbp )
  1091. {
  1092. *meanPtr += *sbp;
  1093. if( *minPtr > *sbp )
  1094. *minPtr = *sbp;
  1095. if( *maxPtr < *sbp )
  1096. *maxPtr = *sbp;
  1097. }
  1098. }
  1099. if( frmCnt > 0 )
  1100. *meanPtr /= frmCnt;
  1101. else
  1102. *minPtr = *maxPtr = 0;
  1103. return cmAudioFileSeek( h, orgFrmIdx );
  1104. }
  1105. cmRC_t cmAudioFileWriteFileInt( const char* fn, double srate, unsigned bits, unsigned frmCnt, unsigned chCnt, int** bufPtrPtr, cmRpt_t* rpt )
  1106. {
  1107. cmRC_t rc0, rc1;
  1108. cmAudioFileH_t h = cmAudioFileNewCreate(fn, srate, bits, chCnt, &rc0, rpt );
  1109. if( (cmAudioFileIsValid(h)==false) || (rc0!=kOkAfRC))
  1110. return rc0;
  1111. rc0 = cmAudioFileWriteInt( h, frmCnt, chCnt, bufPtrPtr );
  1112. if(((rc1 = cmAudioFileDelete(&h))!=kOkAfRC) && (rc0!=kOkAfRC))
  1113. rc0 = rc1;
  1114. return rc0;
  1115. }
  1116. cmRC_t cmAudioFileWriteFileFloat( const char* fn, double srate, unsigned bits, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr, cmRpt_t* rpt )
  1117. {
  1118. cmRC_t rc0, rc1;
  1119. cmAudioFileH_t h = cmAudioFileNewCreate(fn, srate, bits, chCnt, &rc0, rpt );
  1120. if( (cmAudioFileIsValid(h)==false) || (rc0!=kOkAfRC))
  1121. return rc0;
  1122. rc0 = cmAudioFileWriteFloat( h, frmCnt, chCnt, bufPtrPtr );
  1123. if(((rc1 = cmAudioFileDelete(&h))!=kOkAfRC) && (rc0!=kOkAfRC))
  1124. rc0 = rc1;
  1125. return rc0;
  1126. }
  1127. cmRC_t cmAudioFileWriteFileDouble( const char* fn, double srate, unsigned bits, unsigned frmCnt, unsigned chCnt, double** bufPtrPtr, cmRpt_t* rpt )
  1128. {
  1129. cmRC_t rc0, rc1;
  1130. cmAudioFileH_t h = cmAudioFileNewCreate(fn, srate, bits, chCnt, &rc0, rpt );
  1131. if( (cmAudioFileIsValid(h)==false) || (rc0!=kOkAfRC))
  1132. return rc0;
  1133. rc0 = cmAudioFileWriteDouble( h, frmCnt, chCnt, bufPtrPtr );
  1134. if(((rc1 = cmAudioFileDelete(&h))!=kOkAfRC) && (rc0!=kOkAfRC))
  1135. rc0 = rc1;
  1136. return rc0;
  1137. }
  1138. cmRC_t cmAudioFileMinMaxMeanFn( const cmChar_t* fn, unsigned chIdx, cmSample_t* minPtr, cmSample_t* maxPtr, cmSample_t* meanPtr, cmRpt_t* rpt )
  1139. {
  1140. cmRC_t rc0 = kOkAfRC;
  1141. cmRC_t rc1;
  1142. cmAudioFileH_t afH = cmAudioFileNewOpen( fn, NULL, &rc0, rpt );
  1143. if( rc0 != kOkAfRC )
  1144. return rc0;
  1145. rc0 = cmAudioFileMinMaxMean( afH, chIdx, minPtr, maxPtr, meanPtr );
  1146. rc1 = cmAudioFileDelete(&afH);
  1147. return rc0 != kOkAfRC ? rc0 : rc1;
  1148. }
  1149. const cmChar_t* cmAudioFileName( cmAudioFileH_t h )
  1150. {
  1151. cmRC_t rc;
  1152. cmAudioFileGuts* p = _cmAudioFileReadGutsPtr(h,&rc );
  1153. if( rc != kOkAfRC )
  1154. return NULL;
  1155. return p->fn;
  1156. }
  1157. const char* cmAudioFileErrorMsg( unsigned rc )
  1158. {
  1159. unsigned i;
  1160. for(i=0; _cmAudioFileErrArray[i].rc != kUnknownErrAfRC; ++i )
  1161. if( _cmAudioFileErrArray[i].rc == rc )
  1162. break;
  1163. return _cmAudioFileErrArray[i].msg;
  1164. }
  1165. cmRC_t cmAudioFileGetInfo( const cmChar_t* fn, cmAudioFileInfo_t* infoPtr, cmRpt_t* rpt )
  1166. {
  1167. cmRC_t rc = kOkAfRC;
  1168. cmAudioFileH_t afH = cmAudioFileNewOpen( fn, infoPtr, &rc, rpt );
  1169. if( rc != kOkAfRC )
  1170. return rc;
  1171. return cmAudioFileDelete(&afH);
  1172. }
  1173. void cmAudioFilePrintInfo( const cmAudioFileInfo_t* infoPtr, cmRpt_t* rpt )
  1174. {
  1175. char* typeStr = "AIFF";
  1176. char* swapStr = "";
  1177. char* aifcStr = "";
  1178. unsigned i;
  1179. if( cmIsFlag(infoPtr->flags,kWavAfFl) )
  1180. typeStr = "WAV";
  1181. if( cmIsFlag(infoPtr->flags,kSwapAfFl) )
  1182. swapStr = "Swap:On";
  1183. if( cmIsFlag(infoPtr->flags,kAifcAfFl))
  1184. aifcStr = "AIFC";
  1185. cmRptPrintf(rpt,"bits:%i chs:%i srate:%f frames:%i type:%s %s %s\n", infoPtr->bits, infoPtr->chCnt, infoPtr->srate, infoPtr->frameCnt, typeStr, swapStr, aifcStr );
  1186. for(i=0; i<infoPtr->markerCnt; ++i)
  1187. cmRptPrintf(rpt,"%i %i %s\n", infoPtr->markerArray[i].id, infoPtr->markerArray[i].frameIdx, infoPtr->markerArray[i].label);
  1188. if( strlen(infoPtr->bextRecd.desc) )
  1189. cmRptPrintf(rpt,"Bext Desc:%s\n",infoPtr->bextRecd.desc );
  1190. if( strlen(infoPtr->bextRecd.origin) )
  1191. cmRptPrintf(rpt,"Bext Origin:%s\n",infoPtr->bextRecd.origin );
  1192. if( strlen(infoPtr->bextRecd.originRef) )
  1193. cmRptPrintf(rpt,"Bext Origin Ref:%s\n",infoPtr->bextRecd.originRef );
  1194. if( strlen(infoPtr->bextRecd.originDate) )
  1195. cmRptPrintf(rpt,"Bext Origin Date:%s\n",infoPtr->bextRecd.originDate );
  1196. if( strlen(infoPtr->bextRecd.originTime ) )
  1197. cmRptPrintf(rpt,"Bext Origin Time:%s\n",infoPtr->bextRecd.originTime );
  1198. cmRptPrintf(rpt,"Bext time high:%i low:%i 0x%x%x\n",infoPtr->bextRecd.timeRefHigh,infoPtr->bextRecd.timeRefLow, infoPtr->bextRecd.timeRefHigh,infoPtr->bextRecd.timeRefLow);
  1199. }
  1200. cmRC_t cmAudioFileReport( cmAudioFileH_t h, cmRpt_t* rpt, unsigned frmIdx, unsigned frmCnt )
  1201. {
  1202. cmRC_t rc = kOkAfRC;
  1203. cmAudioFileGuts* p = _cmAudioFileReadGutsPtr(h,&rc);
  1204. if( rc != kOkAfRC )
  1205. return rc;
  1206. cmRptPrintf(rpt,"function cm_audio_file_test()\n");
  1207. cmRptPrintf(rpt,"#{\n");
  1208. cmAudioFilePrintInfo(&p->info,rpt);
  1209. cmRptPrintf(rpt,"#}\n");
  1210. float buf[ p->info.chCnt * frmCnt ];
  1211. float* bufPtr[p->info.chCnt];
  1212. unsigned i,j,cmtFrmCnt=0;
  1213. for(i=0; i<p->info.chCnt; ++i)
  1214. bufPtr[i] = buf + (i*frmCnt);
  1215. if((rc = cmAudioFileSeek(h,frmIdx)) != kOkAfRC )
  1216. return rc;
  1217. if((rc= cmAudioFileReadFloat(h,frmCnt,0,p->info.chCnt,bufPtr,&cmtFrmCnt )) != kOkAfRC)
  1218. return rc;
  1219. cmRptPrintf(rpt,"m = [\n");
  1220. for(i=0; i<frmCnt; i++)
  1221. {
  1222. for(j=0; j<p->info.chCnt; ++j)
  1223. cmRptPrintf(rpt,"%f ", bufPtr[j][i] );
  1224. cmRptPrintf(rpt,"\n");
  1225. }
  1226. cmRptPrintf(rpt,"];\nplot(m)\nendfunction\n");
  1227. return rc;
  1228. }
  1229. cmRC_t cmAudioFileReportFn( const cmChar_t* fn, unsigned frmIdx, unsigned frmCnt, cmRpt_t* rpt )
  1230. {
  1231. cmAudioFileInfo_t info;
  1232. cmRC_t rc;
  1233. cmAudioFileH_t h = cmAudioFileNewOpen( fn, &info, &rc, rpt );
  1234. if(rc == kOkAfRC )
  1235. {
  1236. cmAudioFileReport(h,rpt,frmIdx,frmCnt);
  1237. }
  1238. return cmAudioFileDelete(&h);
  1239. }
  1240. /// [cmAudioFileExample]
  1241. void cmAudioFileTest( const cmChar_t* audioFn, const cmChar_t* outFn, cmRpt_t* rpt )
  1242. {
  1243. cmAudioFileInfo_t afInfo;
  1244. cmRC_t cmRC;
  1245. // open an audio file
  1246. cmAudioFileH_t afH = cmAudioFileNewOpen( audioFn, &afInfo, &cmRC, rpt );
  1247. if( cmRC != kOkAfRC || cmAudioFileIsValid(afH)==false )
  1248. {
  1249. cmRptPrintf(rpt,"Unable to open the audio file:%s\n",audioFn);
  1250. return;
  1251. }
  1252. // print the header information and one seconds worth of samples
  1253. //cmAudioFileReport( afH, rpt, 66000, (unsigned)afInfo.srate);
  1254. cmAudioFileReport( afH, rpt, 0, 0);
  1255. // close and delete the audio file handle
  1256. cmAudioFileDelete(&afH);
  1257. }
  1258. /// [cmAudioFileExample]