diff --git a/cwAudioFileProc.cpp b/cwAudioFileProc.cpp index 9210604..3abd850 100644 --- a/cwAudioFileProc.cpp +++ b/cwAudioFileProc.cpp @@ -119,7 +119,7 @@ namespace cw for(unsigned i=0; ichCnt; ++i) { - if((rc = dsp::pv_anl::create( p->anlA[i], p->procSmpN, ctx->srcSrate, p->wndSmpN, p->hopSmpN, dsp::pv_anl::kNoCalcHzPvaFl )) != kOkRC ) + if((rc = dsp::pv_anl::create( p->anlA[i], p->procSmpN, ctx->srcSrate, p->wndSmpN, p->wndSmpN, p->hopSmpN, dsp::pv_anl::kNoCalcHzPvaFl )) != kOkRC ) { rc = cwLogError(rc,"PVOC analysis component create failed."); goto errLabel; diff --git a/cwAudioTransforms.cpp b/cwAudioTransforms.cpp index 1dd0840..837abcc 100644 --- a/cwAudioTransforms.cpp +++ b/cwAudioTransforms.cpp @@ -234,7 +234,7 @@ namespace cw unsigned flags = kCalcHzPvaFl; unsigned wndTypeId = wnd_func::kHannWndId; - if((rc = create( pva, procSmpCnt, srate, wndSmpCnt, hopSmpCnt, flags )) != kOkRC ) + if((rc = create( pva, procSmpCnt, srate, wndSmpCnt, wndSmpCnt, hopSmpCnt, flags )) != kOkRC ) { } diff --git a/cwAudioTransforms.h b/cwAudioTransforms.h index e99b2b3..7b37e15 100644 --- a/cwAudioTransforms.h +++ b/cwAudioTransforms.h @@ -500,6 +500,10 @@ namespace cw unsigned flags; unsigned procSmpCnt; T srate; + + unsigned maxWndSmpCnt; + unsigned maxBinCnt; + unsigned wndSmpCnt; unsigned hopSmpCnt; unsigned binCnt; @@ -514,7 +518,7 @@ namespace cw typedef obj_str< double> dobj_t; template< typename T > - rc_t create( struct obj_str*& p, unsigned procSmpCnt, const T& srate, unsigned wndSmpCnt, unsigned hopSmpCnt, unsigned flags ) + rc_t create( struct obj_str*& p, unsigned procSmpCnt, const T& srate, unsigned maxWndSmpCnt, unsigned wndSmpCnt, unsigned hopSmpCnt, unsigned flags ) { rc_t rc = kOkRC; @@ -527,6 +531,8 @@ namespace cw p->flags = flags; p->procSmpCnt = procSmpCnt; + p->maxWndSmpCnt = maxWndSmpCnt; + p->maxBinCnt = fft::window_sample_count_to_bin_count(maxWndSmpCnt); p->wndSmpCnt = wndSmpCnt; p->hopSmpCnt = hopSmpCnt; p->binCnt = p->ft->binN; diff --git a/cwDsp.cpp b/cwDsp.cpp index 7d0a24f..7962a69 100644 --- a/cwDsp.cpp +++ b/cwDsp.cpp @@ -12,6 +12,12 @@ // fft // +unsigned cw::dsp::fft::window_sample_count_to_bin_count( unsigned wndSmpN ) +{ return wndSmpN/2 + 1; } + +unsigned cw::dsp::fft::bin_count_to_window_sample_count( unsigned binN ) +{ return (binN-1) * 2; } + cw::rc_t cw::dsp::fft::test() { typedef float real_t; diff --git a/cwDsp.h b/cwDsp.h index bfc06fb..da6feb8 100644 --- a/cwDsp.h +++ b/cwDsp.h @@ -196,6 +196,10 @@ namespace cw namespace fft { + + unsigned window_sample_count_to_bin_count( unsigned wndSmpN ); + unsigned bin_count_to_window_sample_count( unsigned binN ); + enum { kToPolarFl = 0x01, // convert to polar (magn./phase) @@ -231,7 +235,7 @@ namespace cw p->flags = flags; p->inN = xN; - p->binN = xN/2 + 1; + p->binN = window_sample_count_to_bin_count(xN); p->magV = mem::allocZ(p->binN); p->phsV = mem::allocZ(p->binN); @@ -368,7 +372,7 @@ namespace cw p = mem::allocZ< obj_str >(1); p->binN = binN; - p->outN = (binN-1)*2; + p->outN = fft::bin_count_to_window_sample_count(binN); if( std::is_same::value ) { diff --git a/cwDspTransforms.cpp b/cwDspTransforms.cpp index 26e3250..412bc52 100644 --- a/cwDspTransforms.cpp +++ b/cwDspTransforms.cpp @@ -29,6 +29,10 @@ namespace cw } } +//---------------------------------------------------------------------------------------------------------------- +// compressor +// + cw::rc_t cw::dsp::compressor::create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t inGain, real_t rmsWndMaxMs, real_t rmsWndMs, real_t threshDb, real_t ratio_num, real_t atkMs, real_t rlsMs, real_t outGain, bool bypassFl ) { p = mem::allocZ(); @@ -162,7 +166,111 @@ void cw::dsp::compressor::set_rms_wnd_ms( obj_t* p, real_t ms ) p->rmsWndCnt = p->rmsWndAllocCnt; } +//---------------------------------------------------------------------------------------------------------------- +// Limiter +// +cw::rc_t cw::dsp::limiter::create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t thresh, real_t igain, real_t ogain, bool bypassFl ) +{ + p = mem::allocZ(); + + p->procSmpCnt = procSmpCnt; + p->thresh = thresh; + p->igain = igain; + p->ogain = ogain; + return kOkRC; +} + +cw::rc_t cw::dsp::limiter::destroy( obj_t*& p ) +{ + mem::release(p); + return kOkRC; +} + +cw::rc_t cw::dsp::limiter::exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n ) +{ + if( p->bypassFl ) + { + vop::copy(y,x,n); // copy through - with no input gain + return kOkRC; + } + else + { + real_t T = p->thresh * p->ogain; + + for(unsigned i=0; iigain; + + if( v >= mx ) + y[i] = s; + else + { + if( v < p->thresh ) + { + y[i] = s * T * v/p->thresh; + } + else + { + // apply a linear limiting function + y[i] = s * (T + (1.0f-T) * (v-p->thresh)/(1.0f-p->thresh)); + } + } + } + } + return kOkRC; +} + +//---------------------------------------------------------------------------------------------------------------- +// dc-filter +// + +cw::rc_t cw::dsp::dc_filter::create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t gain, bool bypassFl ) +{ + p = mem::allocZ(); + + p->gain = gain; + p->bypassFl = bypassFl; + p->b0 = 1; + p->b[0] = -1; + p->a[0] = -0.999; + p->d[0] = 0; + p->d[1] = 0; + + + return kOkRC; +} + +cw::rc_t cw::dsp::dc_filter::destroy( obj_t*& pp ) +{ + mem::release(pp); + return kOkRC; +} + +cw::rc_t cw::dsp::dc_filter::exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n ) +{ + + if( p->bypassFl ) + vop::copy(y,x,n); + else + vop::filter(y,n,x,n,p->b0, p->b, p->a, p->d, 1 ); + + return kOkRC; +} + +cw::rc_t cw::dsp::dc_filter::set( obj_t* p, real_t gain, bool bypassFl ) +{ + p->gain = gain; + p->bypassFl = bypassFl; + return kOkRC; +} + + +//---------------------------------------------------------------------------------------------------------------- +// Recorder +// cw::rc_t cw::dsp::recorder::create( obj_t*& pRef, real_t srate, real_t max_secs, unsigned chN ) { diff --git a/cwDspTransforms.h b/cwDspTransforms.h index 1ce6db1..fd0c455 100644 --- a/cwDspTransforms.h +++ b/cwDspTransforms.h @@ -46,6 +46,40 @@ namespace cw void set_rms_wnd_ms( obj_t* p, real_t ms ); } + namespace limiter + { + typedef struct + { + unsigned procSmpCnt; + real_t igain; // applied before thresholding + real_t thresh; // linear (0.0-1.0) threshold. + real_t ogain; // applied after thresholding + bool bypassFl; + } obj_t; + + rc_t create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t thresh, real_t igain, real_t ogain, bool bypassFl ); + rc_t destroy( obj_t*& pp ); + rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n ); + } + + namespace dc_filter + { + typedef struct + { + real_t d[2]; // + real_t b[1]; // + real_t a[1]; // a[dn] feedback coeff's + real_t b0; // feedforward coeff 0 + bool bypassFl; + real_t gain; + } obj_t; + + rc_t create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t gain, bool bypassFl ); + rc_t destroy( obj_t*& pp ); + rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n ); + rc_t set( obj_t* p, real_t gain, bool bypassFl ); + } + namespace recorder { typedef struct diff --git a/cwFlow.cpp b/cwFlow.cpp index cc689e5..34ac885 100644 --- a/cwFlow.cpp +++ b/cwFlow.cpp @@ -37,7 +37,9 @@ namespace cw { "pv_synthesis", &pv_synthesis::members }, { "spec_dist", &spec_dist::members }, { "compressor", &compressor::members }, + { "limiter", &limiter::members }, { "audio_delay", &audio_delay::members }, + { "dc_filter", &dc_filter::members }, { "balance", &balance::members }, { nullptr, nullptr } }; diff --git a/cwFlowProc.cpp b/cwFlowProc.cpp index abe42f2..e26215e 100644 --- a/cwFlowProc.cpp +++ b/cwFlowProc.cpp @@ -1396,8 +1396,9 @@ namespace cw enum { kInPId, - kHopSmpNPId, + kMaxWndSmpNPId, kWndSmpNPId, + kHopSmpNPId, kHzFlPId, kOutPId }; @@ -1406,6 +1407,7 @@ namespace cw { pv_t** pvA; // pvA[ srcBuf.chN ] unsigned pvN; + unsigned maxWndSmpN; unsigned wndSmpN; unsigned hopSmpN; bool hzFl; @@ -1422,8 +1424,9 @@ namespace cw if((rc = var_register_and_get( ctx, kAnyChIdx, kInPId, "in", srcBuf, - kHopSmpNPId, "hopSmpN", inst->hopSmpN, + kMaxWndSmpNPId, "maxWndSmpN", inst->maxWndSmpN, kWndSmpNPId, "wndSmpN", inst->wndSmpN, + kHopSmpNPId, "hopSmpN", inst->hopSmpN, kHzFlPId, "hzFl", inst->hzFl )) != kOkRC ) { goto errLabel; @@ -1441,7 +1444,7 @@ namespace cw // create a pv anlaysis object for each input channel for(unsigned i=0; ichN; ++i) { - if((rc = create( inst->pvA[i], ctx->ctx->framesPerCycle, srcBuf->srate, inst->wndSmpN, inst->hopSmpN, flags )) != kOkRC ) + if((rc = create( inst->pvA[i], ctx->ctx->framesPerCycle, srcBuf->srate, inst->maxWndSmpN, inst->wndSmpN, inst->hopSmpN, flags )) != kOkRC ) { rc = cwLogError(kOpFailRC,"The PV analysis object create failed on the instance '%s'.",ctx->label); goto errLabel; @@ -1456,7 +1459,7 @@ namespace cw goto errLabel; // create the fbuf 'out' - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, inst->pvA[0]->binCnt, inst->pvA[0]->hopSmpCnt, magV, phsV, hzV ); + rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, inst->pvA[0]->maxBinCnt, srcBuf->chN, inst->pvA[0]->binCnt, inst->pvA[0]->hopSmpCnt, magV, phsV, hzV ); } @@ -1515,7 +1518,7 @@ namespace cw if( dsp::pv_anl::exec( inst->pvA[i], srcBuf->buf + i*srcBuf->frameN, srcBuf->frameN ) ) { // rescale the frequency domain magnitude - vop::mul(dstBuf->magV[i], dstBuf->binN/2, dstBuf->binN); + vop::mul(dstBuf->magV[i], dstBuf->binN_V[i]/2, dstBuf->binN_V[i]); dstBuf->readyFlV[i] = true; @@ -1580,9 +1583,9 @@ namespace cw // create a pv anlaysis object for each input channel for(unsigned i=0; ichN; ++i) { - unsigned wndSmpN = (srcBuf->binN-1)*2; + unsigned wndSmpN = (srcBuf->binN_V[i]-1)*2; - if((rc = create( inst->pvA[i], ctx->ctx->framesPerCycle, srcBuf->srate, wndSmpN, srcBuf->hopSmpN )) != kOkRC ) + if((rc = create( inst->pvA[i], ctx->ctx->framesPerCycle, srcBuf->srate, wndSmpN, srcBuf->hopSmpN_V[i] )) != kOkRC ) { rc = cwLogError(kOpFailRC,"The PV synthesis object create failed on the instance '%s'.",ctx->label); goto errLabel; @@ -1719,7 +1722,7 @@ namespace cw // create a spec_dist object for each input channel for(unsigned i=0; ichN; ++i) { - if((rc = create( inst->sdA[i], srcBuf->binN )) != kOkRC ) + if((rc = create( inst->sdA[i], srcBuf->binN_V[i] )) != kOkRC ) { rc = cwLogError(kOpFailRC,"The 'spec dist' object create failed on the instance '%s'.",ctx->label); goto errLabel; @@ -1746,7 +1749,7 @@ namespace cw } // create the output buffer - if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->binN, srcBuf->hopSmpN, magV, phsV, hzV )) != kOkRC ) + if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->maxBinN, srcBuf->chN, srcBuf->binN_V, srcBuf->hopSmpN_V, magV, phsV, hzV )) != kOkRC ) goto errLabel; } @@ -1820,7 +1823,7 @@ namespace cw dstBuf->readyFlV[i] = false; if( srcBuf->readyFlV[i] ) { - dsp::spec_dist::exec( inst->sdA[i], srcBuf->magV[i], srcBuf->phsV[i], srcBuf->binN ); + dsp::spec_dist::exec( inst->sdA[i], srcBuf->magV[i], srcBuf->phsV[i], srcBuf->binN_V[i] ); dstBuf->readyFlV[i] = true; //If == 0 ) @@ -1897,7 +1900,8 @@ namespace cw // create a compressor object for each input channel for(unsigned i=0; ichN; ++i) { - real_t igain, maxWnd_ms, wnd_ms, thresh, ratio, atk_ms, rls_ms, ogain, bypassFl; + real_t igain, maxWnd_ms, wnd_ms, thresh, ratio, atk_ms, rls_ms, ogain; + bool bypassFl; // get the compressor variable values @@ -2033,6 +2037,184 @@ namespace cw }; } + + //------------------------------------------------------------------------------------------------------------------ + // + // Limiter + // + namespace limiter + { + + enum + { + kInPId, + kBypassPId, + kInGainPId, + kThreshPId, + kOutGainPId, + kOutPId, + }; + + + typedef dsp::limiter::obj_t limiter_t; + + typedef struct + { + limiter_t** limA; + unsigned limN; + } inst_t; + + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + const abuf_t* srcBuf = nullptr; // + inst_t* inst = mem::allocZ(); + + ctx->userPtr = inst; + + // verify that a source buffer exists + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC ) + { + rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); + goto errLabel; + } + else + { + // allocate pv channel array + inst->limN = srcBuf->chN; + inst->limA = mem::allocZ( inst->limN ); + + // create a limiter object for each input channel + for(unsigned i=0; ichN; ++i) + { + real_t igain, thresh, ogain; + bool bypassFl; + + + // get the limiter variable values + if((rc = var_register_and_get( ctx, i, + kBypassPId, "bypass", bypassFl, + kInGainPId, "igain", igain, + kThreshPId, "thresh", thresh, + kOutGainPId, "ogain", ogain )) != kOkRC ) + { + goto errLabel; + } + + // create the limiter instance + if((rc = dsp::limiter::create( inst->limA[i], srcBuf->srate, srcBuf->frameN, igain, thresh, ogain, bypassFl)) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The 'limiter' object create failed on the instance '%s'.",ctx->label); + goto errLabel; + } + + } + + // create the output audio buffer + if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC ) + goto errLabel; + } + + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + rc_t rc = kOkRC; + + inst_t* inst = (inst_t*)ctx->userPtr; + for(unsigned i=0; ilimN; ++i) + destroy(inst->limA[i]); + + mem::release(inst->limA); + mem::release(inst); + + return rc; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + real_t rtmp; + bool btmp; + + if( var->chIdx != kAnyChIdx && var->chIdx < inst->limN ) + { + limiter_t* c = inst->limA[ var->chIdx ]; + + switch( var->vid ) + { + case kBypassPId: rc = var_get( var, btmp ); c->bypassFl=btmp; break; + case kInGainPId: rc = var_get( var, rtmp ); c->igain=rtmp; break; + case kOutGainPId: rc = var_get( var, rtmp ); c->ogain=rtmp; break; + case kThreshPId: rc = var_get( var, rtmp ); c->thresh=rtmp; break; + default: + cwLogWarning("Unhandled variable id '%i' on instance: %s.", var->vid, ctx->label ); + } + //printf("lim byp:%i igain:%f ogain:%f rat:%f thresh:%f atk:%i rls:%i wnd:%i : rc:%i val:%f\n", + // c->bypassFl, c->inGain, c->outGain,c->ratio_num,c->threshDb,c->atkSmp,c->rlsSmp,c->rmsWndCnt,rc,tmp); + } + + + return rc; + } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + const abuf_t* srcBuf = nullptr; + abuf_t* dstBuf = nullptr; + unsigned chN = 0; + + // get the src buffer + if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC ) + goto errLabel; + + // get the dst buffer + if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC ) + goto errLabel; + + chN = std::min(srcBuf->chN,inst->limN); + + for(unsigned i=0; ilimA[i], srcBuf->buf + i*srcBuf->frameN, dstBuf->buf + i*srcBuf->frameN, srcBuf->frameN ); + } + + + + + errLabel: + return rc; + } + + rc_t report( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + for(unsigned i=0; ilimN; ++i) + { + limiter_t* c = inst->limA[i]; + cwLogInfo("%s ch:%i : bypass:%i procSmpN:%i igain:%f threshdb:%f ogain:%f", + ctx->label,i,c->bypassFl,c->procSmpCnt,c->igain,c->thresh,c->ogain ); + } + + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec, + .report = report + }; + } + //------------------------------------------------------------------------------------------------------------------ // // audio_delay @@ -2177,7 +2359,159 @@ namespace cw } + //------------------------------------------------------------------------------------------------------------------ + // + // DC Filter + // + namespace dc_filter + { + + enum + { + kInPId, + kBypassPId, + kGainPId, + kOutPId, + }; + + + typedef dsp::dc_filter::obj_t dc_filter_t; + + typedef struct + { + dc_filter_t** dcfA; + unsigned dcfN; + } inst_t; + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + const abuf_t* srcBuf = nullptr; // + inst_t* inst = mem::allocZ(); + + ctx->userPtr = inst; + + // verify that a source buffer exists + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC ) + { + rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); + goto errLabel; + } + else + { + // allocate channel array + inst->dcfN = srcBuf->chN; + inst->dcfA = mem::allocZ( inst->dcfN ); + + // create a dc_filter object for each input channel + for(unsigned i=0; ichN; ++i) + { + real_t gain; + bool bypassFl; + + + // get the dc_filter variable values + if((rc = var_register_and_get( ctx, i, + kBypassPId, "bypass", bypassFl, + kGainPId, "gain", gain )) != kOkRC ) + { + goto errLabel; + } + + // create the dc_filter instance + if((rc = dsp::dc_filter::create( inst->dcfA[i], srcBuf->srate, srcBuf->frameN, gain, bypassFl)) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The 'dc_filter' object create failed on the instance '%s'.",ctx->label); + goto errLabel; + } + + } + + // create the output audio buffer + if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC ) + goto errLabel; + } + + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + rc_t rc = kOkRC; + + inst_t* inst = (inst_t*)ctx->userPtr; + for(unsigned i=0; idcfN; ++i) + destroy(inst->dcfA[i]); + + mem::release(inst->dcfA); + mem::release(inst); + + return rc; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + return kOkRC; + } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + const abuf_t* srcBuf = nullptr; + abuf_t* dstBuf = nullptr; + unsigned chN = 0; + + // get the src buffer + if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC ) + goto errLabel; + + // get the dst buffer + if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC ) + goto errLabel; + + chN = std::min(srcBuf->chN,inst->dcfN); + + for(unsigned i=0; i( ctx, kGainPId, i ); + bool bypassFl = val_get( ctx, kBypassPId, i ); + + dsp::dc_filter::set( inst->dcfA[i], gain, bypassFl ); + + dsp::dc_filter::exec( inst->dcfA[i], srcBuf->buf + i*srcBuf->frameN, dstBuf->buf + i*srcBuf->frameN, srcBuf->frameN ); + } + + errLabel: + return rc; + } + + rc_t report( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + for(unsigned i=0; idcfN; ++i) + { + dc_filter_t* c = inst->dcfA[i]; + cwLogInfo("%s ch:%i : bypass:%i gain:%f", + ctx->label,i,c->bypassFl,c->gain ); + } + + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec, + .report = report + }; + } + + } } diff --git a/cwFlowProc.h b/cwFlowProc.h index 532ed0b..a5d053a 100644 --- a/cwFlowProc.h +++ b/cwFlowProc.h @@ -16,7 +16,9 @@ namespace cw namespace pv_synthesis { extern class_members_t members; } namespace spec_dist { extern class_members_t members; } namespace compressor { extern class_members_t members; } + namespace limiter { extern class_members_t members; } namespace audio_delay { extern class_members_t members; } + namespace dc_filter { extern class_members_t members; } namespace balance { extern class_members_t members; } } } diff --git a/cwFlowTypes.cpp b/cwFlowTypes.cpp index 75a6615..02eef5b 100644 --- a/cwFlowTypes.cpp +++ b/cwFlowTypes.cpp @@ -175,7 +175,11 @@ namespace cw if( v->u.fbuf == nullptr ) printf("fbuf: "); else - printf("fbuf: chN:%i binN:%i hopSmpN:%i srate:%8.1f", v->u.fbuf->chN, v->u.fbuf->binN, v->u.fbuf->hopSmpN, v->u.fbuf->srate ); + { + printf("fbuf: chN:%i srate:%8.1f ", v->u.fbuf->chN, v->u.fbuf->srate ); + for(unsigned i; iu.fbuf->chN; ++i) + printf("(binN:%i hopSmpN:%i) ", v->u.fbuf->binN_V[i], v->u.fbuf->hopSmpN_V[i] ); + } break; case kBoolMtxTFl: @@ -899,25 +903,38 @@ const cw::flow::sample_t* cw::flow::abuf_get_channel( abuf_t* abuf, unsigned c return abuf->buf + (chIdx*abuf->frameN); } - - -cw::flow::fbuf_t* cw::flow::fbuf_create( srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV, const sample_t** phsV, const sample_t** hzV ) +cw::flow::fbuf_t* cw::flow::fbuf_create( srate_t srate, unsigned maxBinN, unsigned chN, const unsigned* binN_V, const unsigned* hopSmpN_V, const sample_t** magV, const sample_t** phsV, const sample_t** hzV ) { + unsigned curMaxBinN = vop::max(binN_V,chN); + + if( curMaxBinN > maxBinN ) + { + cwLogWarning("A channel bin count (%i) execeeds the max bin count (%i). Max. bin count increased to:%i.",curMaxBinN,maxBinN,curMaxBinN); + maxBinN = curMaxBinN; + } + fbuf_t* f = mem::allocZ(); - f->srate = srate; - f->chN = chN; - f->binN = binN; - f->hopSmpN = hopSmpN; - f->magV = mem::allocZ(chN); - f->phsV = mem::allocZ(chN); - f->hzV = mem::allocZ(chN); - f->readyFlV= mem::allocZ(chN); + f->srate = srate; + f->maxBinN = maxBinN; + f->chN = chN; + f->binN_V = mem::allocZ(chN);; + f->hopSmpN_V = mem::allocZ(chN); + f->magV = mem::allocZ(chN); + f->phsV = mem::allocZ(chN); + f->hzV = mem::allocZ(chN); + f->readyFlV = mem::allocZ(chN); + + vop::copy( f->binN_V, binN_V, chN ); + vop::copy( f->hopSmpN_V, hopSmpN_V, chN ); + + + if( magV != nullptr || phsV != nullptr || hzV != nullptr ) { for(unsigned chIdx=0; chIdxmagV[ chIdx ] = (sample_t*)magV[chIdx]; f->phsV[ chIdx ] = (sample_t*)phsV[chIdx]; f->hzV[ chIdx ] = (sample_t*)hzV[chIdx]; @@ -925,30 +942,48 @@ cw::flow::fbuf_t* cw::flow::fbuf_create( srate_t srate, unsigned chN, unsigned } else { - sample_t* buf = mem::allocZ( chN * kFbufVectN * binN ); - - for(unsigned chIdx=0,j=0; chIdx( kFbufVectN * maxBinN ); + sample_t* m = buf; + for(unsigned chIdx=0; chIdxmagV[chIdx] = buf + j + 0 * binN; - f->phsV[chIdx] = buf + j + 1 * binN; - f->hzV[ chIdx] = buf + j + 2 * binN; + f->magV[chIdx] = m + 0 * f->binN_V[chIdx]; + f->phsV[chIdx] = m + 1 * f->binN_V[chIdx]; + f->hzV[ chIdx] = m + 2 * f->binN_V[chIdx]; + m += f->binN_V[chIdx]; + assert( m <= buf + kFbufVectN * maxBinN ); } - + f->buf = buf; } - return f; + return f; } + +cw::flow::fbuf_t* cw::flow::fbuf_create( srate_t srate, unsigned maxBinN, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV, const sample_t** phsV, const sample_t** hzV ) +{ + unsigned binN_V[ chN ]; + unsigned hopSmpN_V[ chN ]; + + vop::fill( binN_V, chN, binN ); + vop::fill( hopSmpN_V, chN, binN ); + return fbuf_create( srate, maxBinN, chN, binN_V, hopSmpN_V, magV, phsV, hzV ); + +} + + + void cw::flow::fbuf_destroy( fbuf_t*& fbuf ) { if( fbuf == nullptr ) return; - - mem::release( fbuf->magV); - mem::release( fbuf->phsV); - mem::release( fbuf->hzV); + + mem::release( fbuf->binN_V ); + mem::release( fbuf->hopSmpN_V); + //mem::release( fbuf->magV); + //mem::release( fbuf->phsV); + //mem::release( fbuf->hzV); mem::release( fbuf->buf); mem::release( fbuf->readyFlV); mem::release( fbuf); @@ -956,12 +991,16 @@ void cw::flow::fbuf_destroy( fbuf_t*& fbuf ) cw::flow::fbuf_t* cw::flow::fbuf_duplicate( const fbuf_t* src ) { - fbuf_t* fbuf = fbuf_create( src->srate, src->chN, src->binN, src->hopSmpN ); + fbuf_t* fbuf = fbuf_create( src->srate, src->maxBinN, src->chN, src->binN_V, src->hopSmpN_V ); + for(unsigned i=0; ichN; ++i) { - vop::copy( fbuf->magV[i], src->magV[i], fbuf->binN ); - vop::copy( fbuf->phsV[i], src->phsV[i], fbuf->binN ); - vop::copy( fbuf->hzV[i], src->hzV[i], fbuf->binN ); + fbuf->binN_V[i] = src->binN_V[i]; + fbuf->hopSmpN_V[i] = src->hopSmpN_V[i]; + + vop::copy( fbuf->magV[i], src->magV[i], fbuf->binN_V[i] ); + vop::copy( fbuf->phsV[i], src->phsV[i], fbuf->binN_V[i] ); + vop::copy( fbuf->hzV[i], src->hzV[i], fbuf->binN_V[i] ); } return fbuf; } @@ -1325,11 +1364,11 @@ cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* va return rc; } -cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV, const sample_t** phsV, const sample_t** hzV ) +cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned maxBinN, unsigned chN, const unsigned* binN_V, const unsigned* hopSmpN_V, const sample_t** magV, const sample_t** phsV, const sample_t** hzV ) { rc_t rc = kOkRC; fbuf_t* fbuf; - if((fbuf = fbuf_create( srate, chN, binN, hopSmpN, magV, phsV, hzV )) == nullptr ) + if((fbuf = fbuf_create( srate, maxBinN, chN, binN_V, hopSmpN_V, magV, phsV, hzV )) == nullptr ) return cwLogError(kOpFailRC,"fbuf create failed on instance:'%s' variable:'%s'.", inst->label, var_label); if((rc = _var_register_and_set( inst, var_label, vid, chIdx, fbuf )) != kOkRC ) @@ -1338,6 +1377,15 @@ cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label return rc; } +cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned maxBinN, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV, const sample_t** phsV, const sample_t** hzV ) +{ + unsigned binN_V[ chN ]; + unsigned hopSmpN_V[ chN ]; + vop::fill(binN_V,chN,binN); + vop::fill(hopSmpN_V,chN, hopSmpN ); + return var_register_and_set(inst,var_label,vid,chIdx,srate,maxBinN, chN,binN_V, hopSmpN_V, magV, phsV, hzV); +} + cw::rc_t cw::flow::var_get( const variable_t* var, bool& valRef ) { return _val_get_driver(var,valRef); } diff --git a/cwFlowTypes.h b/cwFlowTypes.h index 7d524b8..f13ea8c 100644 --- a/cwFlowTypes.h +++ b/cwFlowTypes.h @@ -24,7 +24,7 @@ namespace cw enum { - kFbufVectN = 3, + kFbufVectN = 3, // count of signal vectors in fbuf (mag,phs,hz) kAnyChIdx = kInvalidIdx, kLocalValueN = 2 }; @@ -32,16 +32,17 @@ namespace cw typedef struct fbuf_str { struct value_str* base; - srate_t srate; // signal sample rate - unsigned flags; // See kXXXFbufFl - unsigned chN; // count of channels - unsigned binN; // count of sample frames per channel - unsigned hopSmpN; // hop sample count - sample_t** magV; // magV[ chN ][ binN ] - sample_t** phsV; // phsV[ chN ][ binN ] - sample_t** hzV; // hzV[ chN ][ binN ] - bool* readyFlV; // readyFlV[chN] true if this channel is ready to be processed (used to sync. fbuf rate to abuf rate) - sample_t* buf; // memory used by this buffer (or NULL if magV,phsV,hzV point are proxied to another buffer) + srate_t srate; // signal sample rate + unsigned flags; // See kXXXFbufFl + unsigned maxBinN; // max value that any value in binN_V[] is allowed to take + unsigned chN; // count of channels + unsigned* binN_V; // binN_V[ chN ] count of sample frames per channel + unsigned* hopSmpN_V; // hopSmpN_V[ chN ] hop sample count + sample_t** magV; // magV[ chN ][ binN ] + sample_t** phsV; // phsV[ chN ][ binN ] + sample_t** hzV; // hzV[ chN ][ binN ] + bool* readyFlV; // readyFlV[chN] true if this channel is ready to be processed (used to sync. fbuf rate to abuf rate) + sample_t* buf; // memory used by this buffer (or NULL if magV,phsV,hzV point are proxied to another buffer) } fbuf_t; enum @@ -233,7 +234,8 @@ namespace cw rc_t abuf_set_channel( abuf_t* buf, unsigned chIdx, const sample_t* v, unsigned vN ); const sample_t* abuf_get_channel( abuf_t* buf, unsigned chIdx ); - fbuf_t* fbuf_create( srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr ); + fbuf_t* fbuf_create( srate_t srate, unsigned maxBinN, unsigned chN, const unsigned* binN_V, const unsigned* hopSmpN_V, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr ); + fbuf_t* fbuf_create( srate_t srate, unsigned maxBinN, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr ); void fbuf_destroy( fbuf_t*& buf ); fbuf_t* fbuf_duplicate( const fbuf_t* src ); @@ -368,7 +370,8 @@ namespace cw rc_t var_register_and_set( instance_t* inst, const char* label, unsigned vid, unsigned chIdx, variable_t*& varRef ); rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN ); - rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr ); + rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned maxBinN, unsigned chN, const unsigned* binN_V, const unsigned* hopSmpN_V, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr ); + rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned maxBinN, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr ); inline rc_t _var_register_and_set(cw::flow::instance_t*, unsigned int ) { return kOkRC; } diff --git a/cwIoPresetSelApp.cpp b/cwIoPresetSelApp.cpp index 37e47de..bd8577b 100644 --- a/cwIoPresetSelApp.cpp +++ b/cwIoPresetSelApp.cpp @@ -83,6 +83,7 @@ namespace cw kFragListId, kFragPanelId, + kFragMeasId, kFragBegLocId, kFragEndLocId, @@ -169,6 +170,7 @@ namespace cw { kPanelDivId, kFragListId, "fragListId" }, { kFragListId, kFragPanelId, "fragPanelId" }, + { kFragPanelId, kFragMeasId, "fragMeasId" }, { kFragPanelId, kFragBegLocId, "fragBegLocId" }, { kFragPanelId, kFragEndLocId, "fragEndLocId" }, { kFragPanelId, kFragPresetRowId, "fragPresetRowId" }, @@ -1475,7 +1477,7 @@ namespace cw unsigned fragId = kInvalidId; unsigned uuId = kInvalidId; - // get the fragment id (uuid) of the selected fragment + // get the fragment id (uuid) of the selected (high-lighted) fragment if((fragId = preset_sel::ui_select_fragment_id(app->psH)) == kInvalidId ) { rc = cwLogError(kInvalidStateRC,"There is no selected fragment to delete."); diff --git a/cwPianoScore.cpp b/cwPianoScore.cpp index 9493818..3ceae5a 100644 --- a/cwPianoScore.cpp +++ b/cwPianoScore.cpp @@ -325,6 +325,17 @@ namespace cw return nullptr; } + + const event_t* _loc_to_event( score_t* p, unsigned loc ) + { + const event_t* e = p->base; + for(; e!=nullptr; e=e->link) + if( e->loc == loc ) + return e; + + return nullptr; + + } } } @@ -467,10 +478,31 @@ bool cw::score::is_loc_valid( handle_t h, unsigned locId ) return locId < p->maxLocId; } +unsigned cw::score::loc_to_measure( handle_t h, unsigned locId ) +{ + score_t* p = _handleToPtr(h); + const event_t* e; + if((e = _loc_to_event(p,locId)) == nullptr ) + return 0; + + return kInvalidId; +} + +unsigned cw::score::loc_to_next_note_on_measure( handle_t h, unsigned locId ) +{ + score_t* p = _handleToPtr(h); + const event_t* e = _loc_to_event(p,locId); + + while( e != nullptr ) + if( midi::isNoteOn(e->status)) + return e->meas; + + return kInvalidId; +} + const cw::score::event_t* cw::score::uid_to_event( handle_t h, unsigned uid ) { - - score_t* p = _handleToPtr(h); + //hscore_t* p = _handleToPtr(h); return nullptr; } diff --git a/cwPianoScore.h b/cwPianoScore.h index 8c02ee3..a8a6f7f 100644 --- a/cwPianoScore.h +++ b/cwPianoScore.h @@ -39,9 +39,12 @@ namespace cw unsigned loc_count( handle_t h ); bool is_loc_valid( handle_t h, unsigned locId ); + unsigned loc_to_measure( handle_t h, unsigned locId ); + unsigned loc_to_next_note_on_measure( handle_t h, unsigned locId ); const event_t* uid_to_event( handle_t h, unsigned uid ); + // Format the event as a string for printing. rc_t event_to_string( handle_t h, unsigned uid, char* buf, unsigned buf_byte_cnt ); diff --git a/cwPvAudioFileProc.cpp b/cwPvAudioFileProc.cpp index d3ce15c..ee37283 100644 --- a/cwPvAudioFileProc.cpp +++ b/cwPvAudioFileProc.cpp @@ -298,7 +298,7 @@ namespace cw for(unsigned i=0; ipvoc_ctx.srcChN; ++i) { - if((rc = dsp::pv_anl::create( p->anlA[i], p->pvoc_ctx.procSmpN, ctx->srcSrate, p->pvoc_ctx.wndSmpN, p->pvoc_ctx.hopSmpN, dsp::pv_anl::kNoCalcHzPvaFl )) != kOkRC ) + if((rc = dsp::pv_anl::create( p->anlA[i], p->pvoc_ctx.procSmpN, ctx->srcSrate, p->pvoc_ctx.wndSmpN, p->pvoc_ctx.wndSmpN, p->pvoc_ctx.hopSmpN, dsp::pv_anl::kNoCalcHzPvaFl )) != kOkRC ) { rc = cwLogError(rc,"PVOC analysis component create failed."); goto errLabel; diff --git a/cwVectOps.h b/cwVectOps.h index 55aa632..5381e5c 100644 --- a/cwVectOps.h +++ b/cwVectOps.h @@ -402,6 +402,60 @@ namespace cw return rms; } + + // Direct form II algorithm based on the MATLAB implmentation + // http://www.mathworks.com/access/helpdesk/help/techdoc/ref/filter.html#f83-1015962 + // The only difference between this function and the equivalent MATLAB filter() function + // is that the first feedforward coeff is given as a seperate value. The first b coefficient + // in this function is therefore the same as the second coefficient in the MATLAB function. + // and the first a[] coefficient (which is generally set to 1.0) is skipped. + // Example: + // Matlab: b=[.5 .4 .3] a=[1 .2 .1] + // Equiv: b0 = .5 b=[ .4 .3] a=[ .2 .1]; + // + // y[yn] - output vector + // x[xn] - input vector. xn must be <= yn. if xn < yn then the end of y[] is set to zero. + // b0 - signal scale. This can also be seen as b[0] (which is not included in b[]) + // b[dn] - feedforward coeff's b[1..dn-1] + // a[dn] - feedback coeff's a[1..dn-1] + // d[dn+1] - delay registers - note that this array must be one element longer than the coeff arrays. + // + + template< typename S, typename T > + S* filter( S* y, + unsigned yn, + const S* x, + unsigned xn, + T b0, + const T* b, + const T* a, + T* d, + unsigned dn ) + { + unsigned i,j; + S y0 = 0; + unsigned n = yn xn ) + fill(y+i,yn-i,0); + + return y; + + } +