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 51KB

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