diff --git a/cwAudioDeviceFile.cpp b/cwAudioDeviceFile.cpp index fdb6da9..5a2f990 100644 --- a/cwAudioDeviceFile.cpp +++ b/cwAudioDeviceFile.cpp @@ -48,13 +48,17 @@ namespace cw unsigned iChCnt; bool iEnableFl; audioPacket_t iPkt; - float* iPktAudioBuf; + sample_t* iPktAudioBuf; unsigned iCbCnt; - float** iChArray; // iChArray[2] - float* iChSmpBuf; // + sample_t** iChArray; // iChArray[ iChCnt ] + sample_t* iChSmpBuf; // unsigned iErrCnt; // count of errors unsigned iFrmCnt; // count of frames read + sample_t* iCacheBuf; // iCacheFrameBuf[ iCacheFrameN * iChCnt ] (interleaved) + unsigned iCacheFrameN; // count of frames in iCacheBuf + unsigned iCacheIdx; // next frame to read (always at channel 0) + char* oFname; audiofile::handle_t oFileH; unsigned oFlags; @@ -62,10 +66,10 @@ namespace cw bool oEnableFl; unsigned oBitsPerSample; audioPacket_t oPkt; - float* oPktAudioBuf; + sample_t* oPktAudioBuf; unsigned oCbCnt; - float** oChArray; // oChArray[2] - float* oChSmpBuf; // + sample_t** oChArray; // oChArray[2] + sample_t* oChSmpBuf; // unsigned oErrCnt; // count of errors unsigned oFrmCnt; // count of frames written @@ -169,9 +173,104 @@ namespace cw mem::release(d->iPktAudioBuf); mem::release(d->iChArray); mem::release(d->iChSmpBuf); + mem::release(d->iCacheBuf); } } + rc_t _fill_input_packet_from_cache( dev_t* d ) + { + rc_t rc = kOkRC; + unsigned n = d->framesPerCycle; + unsigned m = d->framesPerCycle; + + // set n to the count of frames to copy from the cache into the pkt + if( d->iCacheIdx + n > d->iCacheFrameN ) + n = d->iCacheFrameN - d->iCacheIdx; + + if( n > 0 ) + { + memcpy( d->iPktAudioBuf, d->iCacheBuf + (d->iCacheIdx * d->iChCnt), d->framesPerCycle * d->iChCnt * sizeof(sample_t)); + d->iCacheIdx += n; + + // set m to the count of frames to zero at the end of the pkt + m = d->framesPerCycle - n; + } + + if( m > 0 ) + { + memset( d->iPktAudioBuf + (n*d->iChCnt), 0, m * d->iChCnt * sizeof(sample_t)); + d->iCacheIdx = d->iCacheFrameN; + } + + return rc; + } + + rc_t _fill_input_packet_from_file( dev_t* d ) + { + rc_t rc = kOkRC; + unsigned actualFrameCnt = 0; + + // read the file + if((rc = readFloat(d->iFileH, d->framesPerCycle, 0, d->iChCnt, d->iChArray, &actualFrameCnt)) == kOkRC ) + d->iFrmCnt += actualFrameCnt; + else + { + rc = cwLogError(rc,"File read failed on audio device file: %s.",cwStringNullGuard(d->label)); + d->iErrCnt += 1; + goto errLabel; + } + + // interleave into the iPkt audio buffer + vop::interleave( d->iPktAudioBuf, d->iChSmpBuf, actualFrameCnt, d->iChCnt ); + + if( actualFrameCnt < d->framesPerCycle ) + { + for(unsigned i=0; iiChCnt; ++i) + vop::fill( d->iPktAudioBuf + (actualFrameCnt * d->iChCnt) + i, 0, d->framesPerCycle-actualFrameCnt, d->iChCnt ); + } + + // d->iPktAudioBuf[] now contains d->framesPerCycle*d->iChCnt samples + + errLabel: + return rc; + } + + rc_t _cache_input( dev_t* d, unsigned frameN ) + { + rc_t rc = kOkRC; + unsigned n = 0; + + d->iCacheFrameN = frameN; + d->iCacheBuf = mem::resize(d->iCacheBuf, d->iCacheFrameN * d->iChCnt); + d->iCacheIdx = 0; + + while(n < d->iCacheFrameN ) + { + if((rc = _fill_input_packet_from_file(d)) != kOkRC ) + { + rc = cwLogError(rc,"Read failed while reading the input cache."); + d->iCacheFrameN = 0; // this will prevent the cache from being used + goto errLabel; + } + + unsigned copyFrameN = d->framesPerCycle; + if( n + copyFrameN > d->iCacheFrameN ) + copyFrameN = d->iCacheFrameN - n; + + memcpy( d->iCacheBuf + n * d->iChCnt, d->iPktAudioBuf, copyFrameN * d->iChCnt * sizeof(sample_t)); + + n += copyFrameN; + } + + if( n % d->iChCnt != 0 ) + { + cwLogWarning("The cache buffer seems to have a size mismatch with the input audio file."); + } + + errLabel: + return rc; + } + rc_t _open_input( dev_t* d, unsigned devIdx ) { rc_t rc = kOkRC; @@ -217,6 +316,11 @@ namespace cw for(unsigned i=0; iiChCnt; ++i) d->iChArray[i] = d->iChSmpBuf + i*d->framesPerCycle; + + // if input caching was requested + if( cwIsFlag(d->iFlags,kCacheFl) ) + if((rc = _cache_input(d,info.frameCnt)) != kOkRC ) + cwLogError(rc,"Cache load failed on '%s'.",cwStringNullGuard(d->iFname)); errLabel: return rc; @@ -226,34 +330,18 @@ namespace cw { rc_t rc = kOkRC; - unsigned actualFrameCnt = 0; if( !d->iEnableFl ) { memset(d->iPkt.audioBytesPtr,0,d->iChCnt*d->framesPerCycle*sizeof(sample_t)); } else - { - // read the file - if((rc = readFloat(d->iFileH, d->framesPerCycle, 0, d->iChCnt, d->iChArray, &actualFrameCnt)) == kOkRC ) - d->iFrmCnt += actualFrameCnt; + { + if( d->iCacheFrameN ) + rc = _fill_input_packet_from_cache(d); else - { - rc = cwLogError(rc,"File read failed on audio device file: %s.",cwStringNullGuard(d->label)); - d->iErrCnt += 1; - goto errLabel; - } - - // interleave into the iPkt audio buffer - vop::interleave( d->iPktAudioBuf, d->iChSmpBuf, actualFrameCnt, d->iChCnt ); - - if( actualFrameCnt < d->framesPerCycle ) - { - for(unsigned i=0; iiChCnt; ++i) - vop::fill( d->iPktAudioBuf + (actualFrameCnt * d->iChCnt) + i, 0, d->framesPerCycle-actualFrameCnt, d->iChCnt ); - } + rc = _fill_input_packet_from_file(d); } - errLabel: return rc; } @@ -377,7 +465,7 @@ namespace cw dev_t* d = nullptr; // block on the cond. var - unlock the mutex - if((rc = mutex::waitOnCondVar(p->mutexH,false,p->threadTimeOutMs)) != kOkRC ) + if((rc = mutex::waitOnCondVar(p->mutexH,false,p->threadTimeOutMs/2)) != kOkRC ) { if( rc != kTimeOutRC ) { @@ -658,6 +746,7 @@ cw::rc_t cw::audio::device::file::deviceStart( struct driver_str* dr if((rc0 = _indexToDev( p, devIdx, d )) == kOkRC ) { + /* if( d->iFileH.isValid() && cwIsFlag(d->iFlags,kRewindOnStartFl) ) if((rc0 = seek(d->iFileH,0)) != kOkRC ) rc0 = cwLogError(rc0,"Rewind on start failed on the audio device file input file."); @@ -665,6 +754,7 @@ cw::rc_t cw::audio::device::file::deviceStart( struct driver_str* dr if( d->oFileH.isValid() && cwIsFlag(d->oFlags,kRewindOnStartFl) ) if((rc1 = seek(d->oFileH,0)) != kOkRC ) rc1 = cwLogError(rc1,"Rewind on start failed on the audio device file output file."); + */ } if((rc0 = rcSelect(rc0,rc1)) == kOkRC ) @@ -734,8 +824,6 @@ cw::rc_t cw::audio::device::file::deviceEnable( struct driver_str* drv, unsigne else d->oEnableFl = enableFl; - printf("Enable i:%i o:%i\n",d->iEnableFl,d->oEnableFl); - errLabel: return rc; } diff --git a/cwAudioDeviceFile.h b/cwAudioDeviceFile.h index b2d43ad..d03a3ee 100644 --- a/cwAudioDeviceFile.h +++ b/cwAudioDeviceFile.h @@ -33,6 +33,7 @@ namespace cw enum { kRewindOnStartFl = 0x01, + kCacheFl = 0x02 }; // A device may have an input, an output or both. diff --git a/cwIo.cpp b/cwIo.cpp index f9dd606..d169aa6 100644 --- a/cwIo.cpp +++ b/cwIo.cpp @@ -1878,6 +1878,7 @@ namespace cw const char* label = nullptr; const char* iFname = nullptr; bool iRwdOnStartFl = false; + bool iCacheFl = true; const char* oFname = nullptr; unsigned oChCnt = 0; @@ -1892,6 +1893,7 @@ namespace cw if((rc = fnode->getv_opt("enableFl", enableFl, "in_fname", iFname, "in_rewind_on_start_fl",iRwdOnStartFl, + "in_cache_fl",iCacheFl, "out_fname", oFname, "out_rewind_on_start_fl",oRwdOnStartFl, "out_ch_count", oChCnt )) != kOkRC ) @@ -1906,6 +1908,8 @@ namespace cw if( iFname != nullptr ) { unsigned iFlags = iRwdOnStartFl ? audio::device::file::kRewindOnStartFl : 0; + + iFlags += iCacheFl ? audio::device::file::kCacheFl : 0; if((rc = createInDevice( p->audioDevFileH, label, iFname, iFlags )) != kOkRC ) {