123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- #include "cmGlobal.h"
- #include "cmFloatTypes.h"
- #include "cmRpt.h"
- #include "cmErr.h"
- #include "cmCtx.h"
- #include "cmMem.h"
- #include "cmMallocDebug.h"
- #include "cmAudioFile.h"
- #include "cmVectOpsTemplateMain.h"
-
- #include "cmAudioFileMgr.h"
-
- struct cmAfm_str;
-
- typedef struct
- {
- cmSample_t* minV; // minV[summN]
- cmSample_t* maxV; // maxV[summN]
- unsigned summN; // lenght of minV[] and maxV[]
- } cmAfmSummary_t;
-
- typedef struct cmAfmFile_str
- {
- unsigned id;
- cmAudioFileH_t afH;
- cmAudioFileInfo_t afInfo;
- unsigned smpPerSummPt;
-
- cmAfmSummary_t* summArray; // summArray[ afInfo.chCnt ]
- cmSample_t* summMem; // memory used by summArray[] vectors
-
- struct cmAfm_str* p;
- struct cmAfmFile_str* next;
- struct cmAfmFile_str* prev;
- } cmAfmFile_t;
-
- typedef struct cmAfm_str
- {
- cmErr_t err;
- cmAfmFile_t* list;
- } cmAfm_t;
-
-
- cmAfmH_t cmAfmNullHandle = cmSTATIC_NULL_HANDLE;
- cmAfmFileH_t cmAfmFileNullHandle = cmSTATIC_NULL_HANDLE;
-
- cmAfm_t* _cmAfmHandleToPtr( cmAfmH_t h )
- {
- cmAfm_t* p = (cmAfm_t*)h.h;
- assert(p!=NULL);
- return p;
- }
-
- cmAfmFile_t* _cmAfmFileHandleToPtr( cmAfmFileH_t fh )
- {
- cmAfmFile_t* fp = (cmAfmFile_t*)fh.h;
- assert(fp!=NULL);
- return fp;
- }
-
-
- cmAfmRC_t _cmAfmFileClose( cmAfmFile_t* fp )
- {
- cmAfmRC_t rc = kOkAfmRC;
-
- if( cmAudioFileIsValid( fp->afH ) )
- if( cmAudioFileDelete( &fp->afH) != kOkAfRC )
- return cmErrMsg(&fp->p->err,kAudioFileFailAfmRC,"Audio file close failed on '%s'.",cmStringNullGuard(cmAudioFileName(fp->afH)));
-
- if( fp->next != NULL )
- fp->next->prev = fp->prev;
-
- if( fp->prev != NULL )
- fp->prev->next = fp->next;
-
- if( fp->p->list == fp )
- fp->p->list = fp->next;
-
-
- cmMemFree(fp->summArray);
- cmMemFree(fp->summMem);
- cmMemFree(fp);
-
- return rc;
- }
-
- cmAfmRC_t cmAfmFileOpen( cmAfmH_t h, cmAfmFileH_t* fhp, const cmChar_t* audioFn, unsigned id, cmAudioFileInfo_t* afInfo )
- {
- cmAfmRC_t rc;
- cmRC_t afRC;
-
- if((rc = cmAfmFileClose(fhp)) != kOkAfmRC )
- return rc;
-
- cmAfmFile_t* fp = cmMemAllocZ(cmAfmFile_t,1);
- fp->p = _cmAfmHandleToPtr(h);
-
- // open the audio file
- if( cmAudioFileIsValid(fp->afH = cmAudioFileNewOpen(audioFn, &fp->afInfo, &afRC, fp->p->err.rpt )) == false )
- {
- rc = cmErrMsg(&fp->p->err,kAudioFileFailAfmRC,"The audio file '%s' could not be opened.",cmStringNullGuard(audioFn));
- goto errLabel;
- }
-
- // prepend the new file to the mgr's file list
- if( fp->p->list != NULL )
- fp->p->list->prev = fp;
-
- fp->next = fp->p->list;
- fp->p->list = fp;
-
- fp->id = id;
-
- fhp->h = fp;
-
- if( afInfo != NULL )
- *afInfo = fp->afInfo;
-
-
- errLabel:
- if( rc != kOkAfmRC )
- _cmAfmFileClose(fp);
-
- return rc;
- }
-
- cmAfmRC_t cmAfmFileClose( cmAfmFileH_t* fhp )
- {
- cmAfmRC_t rc = kOkAfmRC;
- if( fhp==NULL || cmAfmFileIsValid(*fhp)==false)
- return rc;
-
- cmAfmFile_t* fp = _cmAfmFileHandleToPtr( *fhp );
- if((rc = _cmAfmFileClose(fp)) != kOkAfmRC )
- return rc;
-
- fhp->h = NULL;
-
- return rc;
- }
-
- bool cmAfmFileIsValid( cmAfmFileH_t fh )
- { return fh.h != NULL; }
-
-
- unsigned cmAfmFileId( cmAfmFileH_t fh )
- {
- cmAfmFile_t* fp = _cmAfmFileHandleToPtr( fh );
- return fp->id;
- }
-
- cmAudioFileH_t cmAfmFileHandle( cmAfmFileH_t fh )
- {
- cmAfmFile_t* fp = _cmAfmFileHandleToPtr( fh );
- return fp->afH;
- }
-
- const cmAudioFileInfo_t* cmAfmFileInfo( cmAfmFileH_t fh )
- {
- cmAfmFile_t* fp = _cmAfmFileHandleToPtr( fh );
- return &fp->afInfo;
- }
-
- cmAfmRC_t cmAfmFileSummarize( cmAfmFileH_t fh, unsigned smpPerSummPt )
- {
- cmAfmFile_t* fp = _cmAfmFileHandleToPtr(fh);
- cmAfmRC_t rc = kOkAfmRC;
- unsigned chCnt = fp->afInfo.chCnt;
-
- // summary points per channel per vector
- unsigned summN = (unsigned)ceil((double)fp->afInfo.frameCnt / smpPerSummPt );
-
- // total summary points in all channels and vectors
- unsigned n = chCnt*2*summN;
-
- // Calc the number of summary points per audio file read
- unsigned ptsPerRd = cmMax(1,cmMax(smpPerSummPt,8192) / smpPerSummPt);
-
- // Calc the number samples per audio file read as an integer multiple of ptsPerRd.
- unsigned frmCnt = ptsPerRd * smpPerSummPt;
-
- unsigned actualFrmCnt = 0;
- cmSample_t* chBuf[ chCnt ];
- cmSample_t buf[ frmCnt * chCnt ];
- unsigned i;
-
- // allocate the summary record array
- if( fp->summArray == NULL )
- fp->summArray = cmMemAllocZ( cmAfmSummary_t, chCnt );
-
- // allocate the summary vector memory for all channels
- fp->summMem = cmMemResizeZ( cmSample_t, fp->summMem, n);
- fp->smpPerSummPt = smpPerSummPt;
-
- // setup the summary record array and audio file read buffer
- for(i=0; i<chCnt; ++i)
- {
- // assign memory to the summary vectors
- fp->summArray[i].minV = fp->summMem + i * summN * 2;
- fp->summArray[i].maxV = fp->summArray[i].minV + summN;
- fp->summArray[i].summN = summN;
-
- // setup the audio file reading channel buffer
- chBuf[i] = buf + (i*frmCnt);
- }
-
- // read the entire file and calculate the summary vectors
- i = 0;
- do
- {
- unsigned chIdx = 0;
- unsigned j,k;
-
- // read the next frmCnt samples from the
- if( cmAudioFileReadSample(fp->afH, frmCnt, chIdx, chCnt, chBuf, &actualFrmCnt ) != kOkAfRC )
- {
- rc = cmErrMsg(&fp->p->err,kAudioFileFailAfmRC,"Audio file read failed on '%s'.",cmStringNullGuard(cmAudioFileName(fp->afH)));
- goto errLabel;
- }
-
- // for each summary point
- for(k=0; k<actualFrmCnt && i<summN; k+=smpPerSummPt,++i)
- {
- // cnt of samples in this summary report
- unsigned m = cmMin(smpPerSummPt,actualFrmCnt-k);
-
- // for each channel
- for(j=0; j<chCnt; ++j)
- {
- fp->summArray[j].minV[i] = cmVOS_Min(chBuf[j]+k,m,1);
- fp->summArray[j].maxV[i] = cmVOS_Max(chBuf[j]+k,m,1);
- }
- }
- }while( i<summN && actualFrmCnt==frmCnt );
-
- errLabel:
- return rc;
- }
-
- // Downsample the summary data to produce the output.
- // There must be 1 or more summary points per output point.
- cmAfmRC_t _cmAfmFileGetDownSummary(
- cmAfmFile_t* fp,
- unsigned chIdx,
- unsigned begSmpIdx,
- unsigned smpCnt,
- cmSample_t* minV,
- cmSample_t* maxV,
- unsigned outCnt )
- {
- assert( smpCnt >= outCnt );
-
- double smpPerOut = (double)smpCnt/outCnt;
- double summPerOut = smpPerOut/fp->smpPerSummPt;
-
- unsigned i;
-
- for(i=0; i<outCnt; ++i)
- {
- double fsbi = (begSmpIdx + (i*smpPerOut)) / fp->smpPerSummPt; // starting summary pt index
- double fsei = fsbi + summPerOut; // endiing summary pt index
- unsigned si = (unsigned)floor(fsbi);
- unsigned sn = (unsigned)floor(fsei - fsbi + 1);
-
- if( si > fp->summArray[chIdx].summN )
- {
- minV[i] = 0;
- maxV[i] = 0;
- }
- else
- {
- if( si + sn > fp->summArray[chIdx].summN )
- sn = fp->summArray[chIdx].summN - si;
-
- if( sn == 0 )
- {
- minV[i] = 0;
- maxV[i] = 0;
- }
- else
- {
- minV[i] = cmVOS_Min(fp->summArray[chIdx].minV+si,sn,1);
- maxV[i] = cmVOS_Max(fp->summArray[chIdx].maxV+si,sn,1);
- }
- }
- }
-
- return kOkAfmRC;
- }
-
- // Downsample the audio data to produce the output.
- cmAfmRC_t _cmAfmFileGetDownAudio(
- cmAfmFile_t* fp,
- unsigned chIdx,
- unsigned begSmpIdx,
- unsigned smpCnt,
- cmSample_t* minV,
- cmSample_t* maxV,
- unsigned outCnt )
- {
- assert( smpCnt >= outCnt );
-
- cmAfmRC_t rc = kOkAfmRC;
- unsigned actualFrmCnt = 0;
- unsigned chCnt = 1;
- unsigned i;
- cmSample_t buf[ smpCnt ];
- cmSample_t* chBuf[] = { buf };
-
- // seek to the read location
- if( cmAudioFileSeek( fp->afH, begSmpIdx ) != kOkAfRC )
- {
- rc = cmErrMsg(&fp->p->err,kAudioFileFailAfmRC,"Audio file seek failed on '%s'.",cmStringNullGuard(cmAudioFileName(fp->afH)));
- goto errLabel;
- }
-
- // read 'smpCnt' samples into chBuf[][]
- if( cmAudioFileReadSample(fp->afH, smpCnt, chIdx, chCnt, chBuf, &actualFrmCnt ) != kOkAfRC )
- {
- rc = cmErrMsg(&fp->p->err,kAudioFileFailAfmRC,"Audio file read failed on '%s' durnig upsample.",cmStringNullGuard(cmAudioFileName(fp->afH)));
- goto errLabel;
- }
-
-
- double smpPerOut = (double)smpCnt/outCnt;
-
- for(i=0; i<outCnt; ++i)
- {
- double fsbi = i*smpPerOut;
- double fsei = fsbi + smpPerOut;
- unsigned si = (unsigned)floor(fsbi);
- unsigned sn = (unsigned)floor(fsei - fsbi + 1);
-
- if( si > smpCnt )
- {
- minV[i] = 0;
- maxV[i] = 0;
- }
-
- if( si + sn > smpCnt )
- sn = smpCnt - si;
-
- minV[i] = cmVOS_Min(chBuf[chIdx]+si,sn,1);
- maxV[i] = cmVOS_Max(chBuf[chIdx]+si,sn,1);
- }
-
- errLabel:
- return rc;
- }
-
-
- // If there is one or less summary points per output
- cmAfmRC_t _cmAfmFileGetUpSummary(
- cmAfmFile_t* fp,
- unsigned chIdx,
- unsigned begSmpIdx,
- unsigned smpCnt,
- cmSample_t* minV,
- cmSample_t* maxV,
- unsigned outCnt )
- {
- assert( outCnt >= smpCnt );
- cmAfmRC_t rc = kOkAfmRC;
- unsigned actualFrmCnt = 0;
- unsigned chCnt = 1;
- unsigned i;
- cmSample_t buf[ smpCnt ];
- cmSample_t* chBuf[] = { buf };
-
- if( cmAudioFileSeek( fp->afH, begSmpIdx ) != kOkAfRC )
- {
- rc = cmErrMsg(&fp->p->err,kAudioFileFailAfmRC,"Audio file seek failed on '%s'.",cmStringNullGuard(cmAudioFileName(fp->afH)));
- goto errLabel;
- }
-
- if( cmAudioFileReadSample(fp->afH, smpCnt, chIdx, chCnt, chBuf, &actualFrmCnt ) != kOkAfRC )
- {
- rc = cmErrMsg(&fp->p->err,kAudioFileFailAfmRC,"Audio file read failed on '%s' durnig upsample.",cmStringNullGuard(cmAudioFileName(fp->afH)));
- goto errLabel;
- }
-
-
- for(i=0; i<outCnt; ++i)
- {
- unsigned si = cmMin(smpCnt-1, (unsigned)floor(i * smpCnt / outCnt));
- cmSample_t v = buf[si];
- minV[i] = v;
- maxV[i] = v;
- }
-
- errLabel:
- return rc;
-
- }
-
-
- cmAfmRC_t cmAfmFileGetSummary( cmAfmFileH_t fh, unsigned chIdx, unsigned begSmpIdx, unsigned smpCnt, cmSample_t* minV, cmSample_t* maxV, unsigned outCnt )
- {
- cmAfmRC_t rc = kOkAfmRC;
- cmAfmFile_t* fp = _cmAfmFileHandleToPtr(fh);
- double maxHiResDurSecs = 20.0;
-
- if( smpCnt <= outCnt )
- rc = _cmAfmFileGetUpSummary( fp, chIdx, begSmpIdx, smpCnt, minV, maxV, outCnt );
- else
- {
- if( smpCnt/fp->afInfo.srate < maxHiResDurSecs )
- rc = _cmAfmFileGetDownAudio( fp, chIdx, begSmpIdx, smpCnt, minV, maxV, outCnt );
- else
- rc = _cmAfmFileGetDownSummary( fp, chIdx, begSmpIdx, smpCnt, minV, maxV, outCnt );
- }
-
- return rc;
- }
-
- //----------------------------------------------------------------------------
- // Audio File Manager
- //----------------------------------------------------------------------------
- cmAfmRC_t _cmAfmDestroy( cmAfm_t* p )
- {
- cmAfmRC_t rc = kOkAfmRC;
-
- while( p->list != NULL )
- {
- if((rc = _cmAfmFileClose(p->list)) != kOkAfmRC )
- goto errLabel;
- }
-
- cmMemFree(p);
-
- errLabel:
- return rc;
- }
-
- cmAfmRC_t cmAfmCreate( cmCtx_t* ctx, cmAfmH_t* hp )
- {
- cmAfmRC_t rc;
- if((rc = cmAfmDestroy(hp)) != kOkAfmRC )
- return rc;
-
- cmAfm_t* p = cmMemAllocZ(cmAfm_t,1);
- cmErrSetup(&p->err,&ctx->rpt,"Audio File Mgr");
-
- hp->h = p;
-
- return rc;
- }
-
- cmAfmRC_t cmAfmDestroy( cmAfmH_t* hp )
- {
- cmAfmRC_t rc = kOkAfmRC;
-
- if( hp==NULL || cmAfmIsValid(*hp)==false)
- return rc;
-
- cmAfm_t* p = _cmAfmHandleToPtr(*hp);
-
- if((rc = _cmAfmDestroy(p)) != kOkAfmRC )
- return rc;
-
- hp->h = NULL;
-
- return rc;
- }
-
- bool cmAfmIsValid( cmAfmH_t h )
- { return h.h != NULL; }
-
- cmAfmFileH_t cmAfmIdToHandle( cmAfmH_t h, unsigned fileId )
- {
- cmAfm_t* p = _cmAfmHandleToPtr(h);
- cmAfmFile_t* fp = p->list;
- cmAfmFileH_t fh = cmAfmFileNullHandle;
-
- for(; fp!=NULL; fp=fp->next)
- if( fp->id == fileId )
- {
- fh.h = fp;
- break;
- }
-
- return fh;
- }
|