diff --git a/cmProc3.c b/cmProc3.c index 9482564..38468be 100644 --- a/cmProc3.c +++ b/cmProc3.c @@ -2041,16 +2041,28 @@ cmRC_t cmXfaderExec( cmXfader* p, unsigned procSmpCnt, const bool* chGateV, { cmXfaderCh* cp = p->chArray + i; + cp->onFl = false; + cp->offFl = false; + if( chGateV != NULL ) + { + cp->onFl = chGateV[i] && !cp->gateFl; // notice fade-in transition begin cp->gateFl = chGateV[i]; + } + + cmReal_t g = cp->gain; if( cp->gateFl ) cp->gain = cmMin(cp->gain + dgain,1.0); else + { cp->gain = cmMax(cp->gain - dgain,0.0); + cp->offFl = g>0.0 && cp->gain==0.0; // notice fade-out transition end + } if( cp->gain != 0.0 ) gateFl = true; + } p->onFl = false; diff --git a/cmProc3.h b/cmProc3.h index 878e60f..ab2739c 100644 --- a/cmProc3.h +++ b/cmProc3.h @@ -300,7 +300,9 @@ extern "C" { typedef struct { cmReal_t gain; - bool gateFl; + bool gateFl; // true if channel is on + bool onFl; // true if gateFl transitioned to true on this cycle + bool offFl; // true if gateFl transitioned to false on this cycle } cmXfaderCh; typedef struct diff --git a/dsp/cmDspFx.c b/dsp/cmDspFx.c index 819b0a7..fab4ac5 100644 --- a/dsp/cmDspFx.c +++ b/dsp/cmDspFx.c @@ -1430,6 +1430,7 @@ typedef struct cmXfader* xfdp; unsigned inBaseXfId; unsigned outBaseXfId; + unsigned stateBaseXfId; unsigned gainBaseXfId; unsigned chCnt; bool* chGateV; @@ -1444,8 +1445,8 @@ cmDspInst_t* _cmDspXfaderAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigne { "chs", kChCntXfId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Input and Output channel count"}, { "ms", kFadeTimeMsXfId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Fade time in milliseonds."}, { "mgate", kMstrGateXfId, 0, 0, kInDsvFl | kBoolDsvFl | kOptArgDsvFl, "Master gate - can be used to set all gates."}, - { "on", kOnXfId, 0, 0, kOutDsvFl | kSymDsvFl, "Send 'on' when all ch's transition from off to on."}, - { "off", kOffXfId, 0, 0, kOutDsvFl | kSymDsvFl, "Send 'off' when all ch's transition from on to off."}, + { "on", kOnXfId, 0, 0, kOutDsvFl | kSymDsvFl, "Send 'on' when all ch's transition from off to on."}, + { "off", kOffXfId, 0, 0, kOutDsvFl | kSymDsvFl, "Send 'off' when all ch's transition from on to off."}, }; if( va_cnt < 1 ) @@ -1457,12 +1458,13 @@ cmDspInst_t* _cmDspXfaderAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigne va_list vl1; va_copy(vl1,vl); - unsigned chCnt = va_arg(vl,int); - unsigned fixArgCnt = sizeof(args)/sizeof(args[0]); - unsigned argCnt = fixArgCnt + 4*chCnt; - unsigned inBaseXfId = kGateBaseXfId + chCnt; - unsigned outBaseXfId = inBaseXfId + chCnt; - unsigned gainBaseXfId= outBaseXfId + chCnt; + unsigned chCnt = va_arg(vl,int); + unsigned fixArgCnt = sizeof(args)/sizeof(args[0]); + unsigned argCnt = fixArgCnt + 5*chCnt; + unsigned inBaseXfId = kGateBaseXfId + chCnt; + unsigned outBaseXfId = inBaseXfId + chCnt; + unsigned stateBaseXfId = outBaseXfId + chCnt; + unsigned gainBaseXfId = stateBaseXfId + chCnt; cmDspVarArg_t a[ argCnt+1 ]; @@ -1471,6 +1473,7 @@ cmDspInst_t* _cmDspXfaderAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigne cmDspArgSetupN(ctx, a, argCnt, kGateBaseXfId, chCnt, "gate", kGateBaseXfId, 0, 0, kInDsvFl | kBoolDsvFl, "gate flags"); cmDspArgSetupN(ctx, a, argCnt, inBaseXfId, chCnt, "in", inBaseXfId, 0, 0, kInDsvFl | kAudioBufDsvFl, "audio input"); cmDspArgSetupN(ctx, a, argCnt, outBaseXfId, chCnt, "out", outBaseXfId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "audio output"); + cmDspArgSetupN(ctx, a, argCnt, stateBaseXfId, chCnt, "state",stateBaseXfId, 0, 0, kOutDsvFl | kBoolDsvFl, "current fader state"); cmDspArgSetupN(ctx, a, argCnt, gainBaseXfId, chCnt, "gain", gainBaseXfId, 0, 0, kOutDsvFl | kDoubleDsvFl, "gain output"); cmDspArgSetupNull( a+argCnt); // set terminating arg. flag @@ -1480,6 +1483,7 @@ cmDspInst_t* _cmDspXfaderAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigne p->xfdp = cmXfaderAlloc(ctx->cmProcCtx,NULL,cmDspSampleRate(ctx), chCnt, fadeTimeMs); p->inBaseXfId = inBaseXfId; p->outBaseXfId = outBaseXfId; + p->stateBaseXfId = stateBaseXfId; p->gainBaseXfId = gainBaseXfId; p->chCnt = chCnt; p->chGateV = cmMemAllocZ(bool,p->chCnt); @@ -1489,8 +1493,13 @@ cmDspInst_t* _cmDspXfaderAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigne // set default values for the parameters that were not explicitely set in the va_arg list cmDspSetDefaultDouble( ctx, &p->inst, kFadeTimeMsXfId, 0, 100 ); cmDspSetDefaultBool( ctx, &p->inst, kMstrGateXfId, false, false); - cmDspSetDefaultSymbol( ctx, &p->inst, kOnXfId, p->onSymId ); - cmDspSetDefaultSymbol( ctx, &p->inst, kOffXfId, p->offSymId ); + cmDspSetDefaultSymbol( ctx, &p->inst, kOnXfId, p->onSymId ); + cmDspSetDefaultSymbol( ctx, &p->inst, kOffXfId, p->offSymId ); + + int i; + for(i=0; iinst, stateBaseXfId+i, false, false ); + return &p->inst; } @@ -1541,6 +1550,12 @@ cmDspRC_t _cmDspXfaderExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* cmVOS_MultVVS(op,n,ip,gain); } + if( p->xfdp->chArray[i].onFl ) + cmDspSetBool(ctx,inst,p->stateBaseXfId+i,true); + + if( p->xfdp->chArray[i].offFl ) + cmDspSetBool(ctx,inst,p->stateBaseXfId+i,false); + // send the gain output cmDspSetDouble(ctx,inst,p->gainBaseXfId+i,gain); } @@ -1580,8 +1595,6 @@ cmDspRC_t _cmDspXfaderRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* break; } - - // record gate changes into p->chGateV[] for later use in _cmDspXfaderExec(). if( kGateBaseXfId <= evt->dstVarId && evt->dstVarId < kGateBaseXfId + p->chCnt ) { @@ -5284,10 +5297,10 @@ cmDspInst_t* _cmDspGateToSym_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, uns cmDspGateToSym_t* p = cmDspInstAllocV(cmDspGateToSym_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl, 1, "on_sym", kOnSymGsId, 0, 0, kSymDsvFl | kInDsvFl | kOptArgDsvFl,"'on' symbol id (default:'on')", 1, "off_sym",kOffSymGsId, 0, 0, kSymDsvFl | kInDsvFl | kOptArgDsvFl,"'off' symbol id (default:'off')", - 1, "on", kOnGsId, 0, 0, kBoolDsvFl | kInDsvFl, "On - send out 'on' symbol when a 'true' is received.", - 1, "off", kOffGsId, 0, 0, kBoolDsvFl | kInDsvFl, "Off - send out 'off' symbol when a 'false' is received.", - 1, "both", kBothGsId, 0, 0, kBoolDsvFl | kInDsvFl, "Send 'on' on 'true' and 'off' on 'false'.", - 1, "out", kOutGsId, 0, 0, kSymDsvFl | kOutDsvFl, "Output", + 1, "on", kOnGsId, 0, 0, kBoolDsvFl | kInDsvFl, "On - send out 'on' symbol when a 'true' is received.", + 1, "off", kOffGsId, 0, 0, kBoolDsvFl | kInDsvFl, "Off - send out 'off' symbol when a 'false' is received.", + 1, "both", kBothGsId, 0, 0, kBoolDsvFl | kInDsvFl, "Send 'on' on 'true' and 'off' on 'false'.", + 1, "out", kOutGsId, 0, 0, kSymDsvFl | kOutDsvFl, "Output", 0 ); @@ -5654,12 +5667,40 @@ struct cmDspClass_str* cmRouterClassCons( cmDspCtx_t* ctx ) } //========================================================================================================================================== +// Purpose: AvailCh can be used to implement a channel switching circuit. +// +// Inputs: +// chs - The count of channels. Constructor only argument. +// trig - Any input causes the next available channel, i, to be enabled. +// gate[i] transmits 'true'. In 'exclusive (0) mode all active +// channels are then requested to shutdown by transmitting 'false' on +// gate[] - only the new channel will be active. In 'multi' (1) mode +// no signal is sent out the gate[]. +// dis[chCnt] - Recieves a gate signal from an external object which indicates +// when a channel is no longer active. When a 'false' is received on dis[i] +// the channel i is marked as available. In 'multi' mode 'false' is +// then transmitted on gate[i]. +// Outputs: +// gate[chCnt] - 'true' is transmitted when a channel is made active (see trig) +// 'false' is transmitted to notify the channel that it should shutdown. +// The channel is not considered actually shutdown until dis[i] +// recieves a 'false'. +// Notes: +// The gate[] output is designed to work with the gate[] input of Xfader. When +// availCh.gate[] goes high Xfader fades in, when availCh.gate[] goes low +// Xfader fades out. The dis[] channel is designed to connect from Xfader.state[]. +// When Xfader.state[] goes low, when a fade-out is complete, the connected AvailCh +// is marked as available. enum { kChCntAvId, + kModeAvId, kTrigAvId, kChIdxAvId, - kBaseInDisAvId, + kBaseDisInAvId, + + kExclusiveModeAvId=0, + kMultiModeAvId=1 }; cmDspClass_t _cmAvailCh_DC; @@ -5668,10 +5709,8 @@ typedef struct { cmDspInst_t inst; unsigned chCnt; - unsigned baseOutEnaAvId; - unsigned baseInDisAvId; - unsigned enableSymId; - unsigned disableSymId; + unsigned baseDisInAvId; + unsigned baseGateOutAvId; bool* stateArray; } cmDspAvailCh_t; @@ -5694,29 +5733,33 @@ cmDspInst_t* _cmDspAvailCh_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsig return NULL; } - unsigned baseInDisAvId = kBaseInDisAvId; - unsigned baseOutEnaAvId = baseInDisAvId + chCnt; + unsigned baseDisInAvId = kBaseDisInAvId; + unsigned baseGateOutAvId = baseDisInAvId + chCnt; cmDspAvailCh_t* p = cmDspInstAllocV(cmDspAvailCh_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1, - 1, "chs", kChCntAvId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Channel count.", - 1, "trig", kTrigAvId, 0, 0, kTypeDsvMask | kInDsvFl, "Trigger the unit to select the next available channel.", - 1, "ch", kChIdxAvId, 0, 0, kUIntDsvFl | kReqArgDsvFl | kInDsvFl, "Currently selected channel.", - chCnt, "dis", baseInDisAvId, 0, 0, kTypeDsvMask | kInDsvFl, "Disable inputs.", - chCnt, "ena", baseOutEnaAvId, 0, 0, kSymDsvFl | kOutDsvFl, "'enable' outputs", + 1, "chs", kChCntAvId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Channel count.", + 1, "mode", kModeAvId, 0, 0, kUIntDsvFl | kInDsvFl, "Mode: 0=exclusive (dflt) 1=multi", + 1, "trig", kTrigAvId, 0, 0, kTypeDsvMask | kInDsvFl, "Trigger the unit to select the next available channel.", + 1, "ch", kChIdxAvId, 0, 0, kUIntDsvFl | kOutDsvFl, "Currently selected channel.", + chCnt, "dis", baseDisInAvId, 0, 0, kBoolDsvFl | kInDsvFl, "Disable channel gate", + chCnt, "gate", baseGateOutAvId, 0, 0, kBoolDsvFl | kOutDsvFl, "Active channel gate", 0 ); p->chCnt = chCnt; - p->baseInDisAvId = baseInDisAvId; - p->baseOutEnaAvId = baseOutEnaAvId; - p->enableSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"enable"); - p->disableSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"disable"); + p->baseDisInAvId = baseDisInAvId; + p->baseGateOutAvId = baseGateOutAvId; unsigned i; for(i=0; iinst, baseOutEnaAvId+i, p->disableSymId ); - + { + cmDspSetDefaultBool( ctx, &p->inst, baseDisInAvId+i, false, false ); + cmDspSetDefaultBool( ctx, &p->inst, baseGateOutAvId+i, false, false ); + } + cmDspSetDefaultUInt( ctx, &p->inst, kModeAvId, 0, kExclusiveModeAvId ); cmDspSetDefaultUInt( ctx, &p->inst, kChIdxAvId, 0, cmInvalidIdx ); + + return &p->inst; } @@ -5737,24 +5780,41 @@ cmDspRC_t _cmDspAvailCh_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_ cmDspRC_t rc = kOkDspRC; cmDspAvailCh_t* p = (cmDspAvailCh_t*)inst; + bool exclModeFl = cmDspUInt(inst, kModeAvId ) == kExclusiveModeAvId; + // if this is a trigger if( evt->dstVarId == kTrigAvId ) { unsigned i; + bool fl = true; for(i=0; ichCnt; ++i) - if( cmDspSymbol(inst,p->baseOutEnaAvId+i) == p->disableSymId ) + { + // the actual channel's active state is held in the 'dis' variable. + bool activeFl = cmDspBool(inst,p->baseDisInAvId+i); + + // if ch[i] is the first avail inactive channel + if( fl && !activeFl ) { cmDspSetUInt(ctx,inst,kChIdxAvId,i); - cmDspSetSymbol(ctx,inst,p->baseOutEnaAvId,p->enableSymId); + cmDspSetBool(ctx, inst, p->baseDisInAvId + i, true); + cmDspSetBool(ctx, inst, p->baseGateOutAvId + i, true); + fl = false; } + + // if ch[i] is active - then request that it shutdown + if( activeFl && exclModeFl) + cmDspSetBool(ctx, inst, p->baseGateOutAvId + i, false); + + } return rc; } // if this is an incoming disable message. - if( p->baseInDisAvId <= evt->dstVarId && evt->dstVarId < p->baseInDisAvId+p->chCnt ) + if( p->baseDisInAvId <= evt->dstVarId && evt->dstVarId < p->baseDisInAvId+p->chCnt && cmDsvGetBool(evt->valuePtr) == false) { - cmDspSetSymbol(ctx,inst,p->baseOutEnaAvId,p->disableSymId); - return rc; + cmDspSetEvent(ctx,inst,evt); + if( !exclModeFl ) + cmDspSetBool(ctx, inst, p->baseGateOutAvId + (evt->dstVarId - p->baseDisInAvId), false); } return rc; diff --git a/dsp/cmDspPgm.c b/dsp/cmDspPgm.c index 3586b56..22683bb 100644 --- a/dsp/cmDspPgm.c +++ b/dsp/cmDspPgm.c @@ -2321,26 +2321,44 @@ cmDspRC_t _cmDspSysPgm_AvailCh( cmDspSysH_t h, void** userPtrPtr ) const char* fn = "/home/kevin/media/audio/20110723-Kriesberg/Audio Files/Piano 3_01.wav"; - cmDspInst_t* chk = cmDspSysAllocInst(h,"Button", "Next", 2, kCheckDuiId, 0.0 ); + cmDspInst_t* chk0 = cmDspSysAllocInst(h,"Button", "0", 2, kButtonDuiId, 0.0 ); + //cmDspInst_t* chk1 = cmDspSysAllocInst(h,"Button", "1", 2, kCheckDuiId, 0.0 ); + cmDspInst_t* achp = cmDspSysAllocInst( h, "AvailCh", NULL, 1, xfadeChCnt ); cmDspInst_t* sphp = cmDspSysAllocInst( h, "Phasor", NULL, 2, cmDspSysSampleRate(h), frqHz ); cmDspInst_t* swtp = cmDspSysAllocInst( h, "WaveTable", NULL, 2, ((int)cmDspSysSampleRate(h)), 4); cmDspInst_t* fphp = cmDspSysAllocInst( h, "Phasor", NULL, 1, cmDspSysSampleRate(h) ); cmDspInst_t* fwtp = cmDspSysAllocInst( h, "WaveTable", NULL, 5, ((int)cmDspSysSampleRate(h)), 1, fn, -1, 7000000 ); cmDspInst_t* fad0 = cmDspSysAllocInst( h, "Xfader", NULL, 3, xfadeChCnt, xfadeMs, xfadeInitFl ); - cmDspInst_t* fad1 = cmDspSysAllocInst( h, "Xfader", NULL, 3, xfadeChCnt, xfadeMs, xfadeInitFl ); + + cmDspInst_t* prp = cmDspSysAllocInst( h, "Printer", NULL, 1, ">" ); cmDspInst_t* ao0p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 0 ); cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 1 ); - cmDspSysConnectAudio(h, sphp, "out", swtp, "phs" ); - cmDspSysConnectAudio(h, swtp, "out", fad0, "in" ); - cmDspSysConnectAudio(h, fad0, "out", ao0p, "in" ); - cmDspSysConnectAudio(h, fphp, "out", fwtp, "phs" ); - cmDspSysConnectAudio(h, fwtp, "out", fad1, "in" ); - cmDspSysConnectAudio(h, fad1, "out", ao1p, "in" ); + // phasor->sine->fad-0->aout + cmDspSysConnectAudio(h, sphp, "out", swtp, "phs" ); + cmDspSysConnectAudio(h, swtp, "out", fad0, "in-0" ); + cmDspSysConnectAudio(h, fad0, "out-0", ao0p, "in" ); + + // phasor->file->fad-1->aout + cmDspSysConnectAudio(h, fphp, "out", fwtp, "phs" ); + cmDspSysConnectAudio(h, fwtp, "out", fad0, "in-1" ); + cmDspSysConnectAudio(h, fad0, "out-1", ao1p, "in" ); + + //cmDspSysInstallCb(h, chk0, "out", fad0, "gate-0", NULL); + //cmDspSysInstallCb(h, chk1, "out", fad0, "gate-1", NULL); + + cmDspSysInstallCb(h, chk0, "sym", achp, "trig", NULL); + cmDspSysInstallCb(h, achp, "gate-0", fad0, "gate-0", NULL ); + cmDspSysInstallCb(h, fad0, "state-0", achp, "dis-0", NULL ); + + cmDspSysInstallCb(h, achp, "gate-1", fad0, "gate-1", NULL ); + cmDspSysInstallCb(h, fad0, "state-1", achp, "dis-1", NULL ); + + cmDspSysInstallCb(h, fad0, "state-0", prp, "in", NULL); return kOkDspRC;