libcm is a C development framework with an emphasis on audio signal processing applications.
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.

cmAudioFile.c 52KB

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