diff --git a/cwAudioFileOps.cpp b/cwAudioFileOps.cpp index 41e586c..4411119 100644 --- a/cwAudioFileOps.cpp +++ b/cwAudioFileOps.cpp @@ -3,6 +3,7 @@ #include "cwCommonImpl.h" #include "cwMem.h" #include "cwFile.h" +#include "cwText.h" #include "cwObject.h" #include "cwAudioFile.h" #include "cwUtility.h" @@ -45,6 +46,37 @@ cw::rc_t cw::afop::sine( const object_t* cfg ) return rc; } +cw::rc_t cw::afop::clicks(const char* fn, double srate, unsigned bits, double secs, const unsigned* clickSmpOffsArray, unsigned clickSmpOffsN, double clickAmp, double decay, double burstMs ) +{ + rc_t rc = kOkRC; + unsigned xN = srate * secs; + float* x = mem::alloc(xN); + unsigned bN = srate * burstMs / 1000.0; + unsigned chCnt = 1; + float b[ bN ]; + + for(unsigned i=0; i= xN ) + return cwLogError(kInvalidArgRC,"Click index %i (%f secs) is greater than the signal length: %i (%f secs).", smp_idx, smp_idx/srate, xN, secs ); + + for(unsigned j=0; jgetv("dstFn",dstFn,"dstBits",dstBits,"dstSrate",dstSrate,"dstSecs",dstSecs,"op",opLabel,"sine",sineNode,"click",clickNode)) != kOkRC ) + { + cwLogError(rc,"generate() arg. parse failed."); + } + else + { + + outFn = filesys::expandPath(dstFn); + + if( textCompare(opLabel,"sine") == 0 ) + { + double gain = 1.0; + double hz = 100.0; + if((rc = sineNode->getv("gain",gain,"hertz",hz)) != kOkRC ) + { + rc = cwLogError(rc,"Error parsing generator 'sine' parameters."); + goto errLabel; + } + else + { + if((rc = sine( dstFn, dstSrate, dstBits, hz, gain, dstSecs)) != kOkRC ) + { + rc = cwLogError(rc,"Sine generator failed.."); + goto errLabel; + } + } + } + + if( textCompare(opLabel,"click") == 0 ) + { + double gain = 1.0; + double decay = 0.7; + const object_t* msL = nullptr; + + if((rc = clickNode->getv("gain",gain,"decay",decay,"msL",msL)) != kOkRC ) + { + rc = cwLogError(rc,"Error parsing generator 'click' parameters."); + goto errLabel; + } + else + { + unsigned msA_N = msL->child_count(); + unsigned msA[ msA_N ]; + + for(unsigned i=0; ichild_ele(i)->value( msA[i] )) != kOkRC ) + { + rc = cwLogError(rc,"Error parsing generator 'click' msL[] values."); + goto errLabel; + } + + if((rc = clicks( outFn, dstSrate, dstBits, dstSecs, msA, msA_N, gain, -decay )) != kOkRC ) + { + rc = cwLogError(rc,"Error generating click audio file."); + goto errLabel; + } + + } + } + } + + errLabel: + + mem::release(outFn); + + return rc; +} cw::rc_t cw::afop::test( const object_t* cfg ) diff --git a/cwAudioFileOps.h b/cwAudioFileOps.h index 1d67650..b355288 100644 --- a/cwAudioFileOps.h +++ b/cwAudioFileOps.h @@ -10,6 +10,12 @@ namespace cw rc_t sine( const char* fn, double srate, unsigned bits, double hz, double gain, double secs ); rc_t sine( const object_t* cfg ); + // Generate clicks (unit impulses) at the sample locations. + rc_t clicks( const char* fn, double srate, unsigned bits, double secs, const unsigned* clickSmpOffsArray, unsigned clickSmpOffsetN, double clickAmp = 0.9, double decay=0.7, double burstMs=10 ); + + // Parse the 'generate' paramter configuration and generate a file. + rc_t generate( const object_t* cfg ); + // Mix a set of audio files. rc_t mix( const char* fnV[], const float* gainV, unsigned srcN, const char* outFn, unsigned outBits ); rc_t mix( const object_t* cfg ); @@ -47,8 +53,10 @@ namespace cw rc_t parallelMix( const char* dstFn, unsigned dstBits, const char* srcDir, const parallelMixArg_t* argL, unsigned argN ); rc_t parallelMix( const object_t* cfg ); + // Currawong on-line transform application rc_t transformApp( const object_t* cfg ); + // Convolve an impulse response from 'impulseRespnseFn' with 'srcFn'. rc_t convolve( const char* dstFn, unsigned dstBits, const char* srcFn, const char* impulseResponseFn, float irScale=1 ); rc_t convolve( const object_t* cfg );