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

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