diff --git a/cmProc4.c b/cmProc4.c index 727c66d..d29640f 100644 --- a/cmProc4.c +++ b/cmProc4.c @@ -4502,3 +4502,74 @@ cmRC_t cmRecdPlayExec( cmRecdPlay* p, const cmSample_t** iChs, cmSample_ return cmOkRC; } + +//======================================================================================================================= +cmGoertzel* cmGoertzelAlloc( cmCtx* c, cmGoertzel* p, double srate, const double* fcHzV, unsigned chCnt ) +{ + cmGoertzel* op = cmObjAlloc(cmGoertzel,c,p); + + if( cmGoertzelInit(op,srate,fcHzV,chCnt) != cmOkRC ) + cmGoertzelFree(&op); + + return op; +} + +cmRC_t cmGoertzelFree( cmGoertzel** pp ) +{ + cmRC_t rc = cmOkRC; + if( pp==NULL || *pp==NULL ) + return rc; + + cmGoertzel* p = *pp; + if((rc = cmGoertzelFinal(p)) != cmOkRC ) + return rc; + + cmMemFree(p->ch); + cmObjFree(pp); + return rc; + +} + +cmRC_t cmGoertzelInit( cmGoertzel* p, double srate, const double* fcHzV, unsigned chCnt ) +{ + cmRC_t rc; + unsigned i; + + if((rc = cmGoertzelFinal(p)) != cmOkRC ) + return rc; + + p->ch = cmMemResizeZ(cmGoertzelCh,p->ch,chCnt); + p->chCnt = chCnt; + p->srate = srate; + + for(i=0; ichCnt; ++i) + p->ch[i].coeff = 2*cos(2*M_PI*fcHzV[i]/srate); + + return rc; +} + +cmRC_t cmGoertzelFinal( cmGoertzel* p ) +{ return cmOkRC; } + +cmRC_t cmGoertzelExec( cmGoertzel* p, const cmSample_t* x, unsigned procSmpCnt, double* outV, unsigned chCnt ) +{ + unsigned i,j; + + for(i=0; ich + i; + + ch->s1 = x[0]; + ch->s2 = x[1] + 2 * x[0] * ch->coeff; + for(j=2; js0 = x[j] + ch->coeff * ch->s1 - ch->s2; + ch->s2 = ch->s1; + ch->s1 = ch->s0; + } + + outV[i] = ch->s2*ch->s2 + ch->s1*ch->s1 - ch->coeff * ch->s2 * ch->s1; + } + + return cmOkRC; +} diff --git a/cmProc4.h b/cmProc4.h index ae1890e..5a68ffa 100644 --- a/cmProc4.h +++ b/cmProc4.h @@ -627,7 +627,10 @@ extern "C" { cmRC_t cmScModulatorDump( cmScModulator* p ); //======================================================================================================================= - + // + // Record fragments of audio, store them, and play them back at a later time. + // + typedef struct cmRecdPlayFrag_str { unsigned labelSymId; // this fragments label @@ -658,6 +661,17 @@ extern "C" { } cmRecdPlay; + // srate - system sample rate + // fragCnt - total count of samples to record + // chCnt - count of input and output audio channels. + // initFragSecs - amount of memory to pre-allocate for each fragment. + // maxLaSecs - maximum value for curLaSecs + // curLaSecs - current duration of look-ahead buffer + // + // The look-ahead buffer is a circular buffer which hold the previous 'curLaSecs' seconds + // of incoming audio. When recording is enabled with via cmRecdPlayBeginRecord() the + // look ahead buffer is automatically prepended to the fragment. + cmRecdPlay* cmRecdPlayAlloc( cmCtx* c, cmRecdPlay* p, double srate, unsigned fragCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs ); cmRC_t cmRecdPlayFree( cmRecdPlay** pp ); cmRC_t cmRecdPlayInit( cmRecdPlay* p, double srate, unsigned flagCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs ); @@ -667,16 +681,49 @@ extern "C" { cmRC_t cmRecdPlaySetLaSecs( cmRecdPlay* p, double curLaSecs ); + // Deactivates all active recorders and players, zeros the look-ahead buffer and + // rewinds all fragment play positions. This function does not clear the audio from + // frabments that have already been recorded. cmRC_t cmRecdPlayRewind( cmRecdPlay* p ); + cmRC_t cmRecdPlayBeginRecord( cmRecdPlay* p, unsigned labelSymId ); cmRC_t cmRecdPlayEndRecord( cmRecdPlay* p, unsigned labelSymId ); cmRC_t cmRecdPlayBeginPlay( cmRecdPlay* p, unsigned labelSymId ); cmRC_t cmRecdPlayEndPlay( cmRecdPlay* p, unsigned labelSymId ); + // Begin fading out the specified fragment at a rate deteremined by 'dbPerSec'. cmRC_t cmRecdPlayBeginFade( cmRecdPlay* p, unsigned labelSymId, double fadeDbPerSec ); cmRC_t cmRecdPlayExec( cmRecdPlay* p, const cmSample_t** iChs, cmSample_t** oChs, unsigned chCnt, unsigned smpCnt ); + //======================================================================================================================= + // Goertzel Filter + // + + typedef struct + { + double s0; + double s1; + double s2; + double coeff; + } cmGoertzelCh; + + typedef struct + { + cmObj obj; + cmGoertzelCh* ch; + unsigned chCnt; + double srate; + } cmGoertzel; + + cmGoertzel* cmGoertzelAlloc( cmCtx* c, cmGoertzel* p, double srate, const double* fcHzV, unsigned chCnt ); + cmRC_t cmGoertzelFree( cmGoertzel** pp ); + cmRC_t cmGoertzelInit( cmGoertzel* p, double srate, const double* fcHzV, unsigned chCnt ); + cmRC_t cmGoertzelFinal( cmGoertzel* p ); + cmRC_t cmGoertzelExec( cmGoertzel* p, const cmSample_t* in, unsigned procSmpCnt, double* outV, unsigned chCnt ); + + + #ifdef __cplusplus } #endif