libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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]