Completed AvailCh DSP Object

Added state[] variable to XFader DSP object.
Completed _cmDspSysPgm_AvailCh() example program.
This commit is contained in:
kevin 2012-12-18 14:46:07 -08:00
parent 9d6ac977aa
commit 2b6a272d55
4 changed files with 140 additions and 48 deletions

View File

@ -2041,16 +2041,28 @@ cmRC_t cmXfaderExec( cmXfader* p, unsigned procSmpCnt, const bool* chGateV,
{ {
cmXfaderCh* cp = p->chArray + i; cmXfaderCh* cp = p->chArray + i;
cp->onFl = false;
cp->offFl = false;
if( chGateV != NULL ) if( chGateV != NULL )
{
cp->onFl = chGateV[i] && !cp->gateFl; // notice fade-in transition begin
cp->gateFl = chGateV[i]; cp->gateFl = chGateV[i];
}
cmReal_t g = cp->gain;
if( cp->gateFl ) if( cp->gateFl )
cp->gain = cmMin(cp->gain + dgain,1.0); cp->gain = cmMin(cp->gain + dgain,1.0);
else else
{
cp->gain = cmMax(cp->gain - dgain,0.0); 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 ) if( cp->gain != 0.0 )
gateFl = true; gateFl = true;
} }
p->onFl = false; p->onFl = false;

View File

@ -300,7 +300,9 @@ extern "C" {
typedef struct typedef struct
{ {
cmReal_t gain; 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; } cmXfaderCh;
typedef struct typedef struct

View File

@ -1430,6 +1430,7 @@ typedef struct
cmXfader* xfdp; cmXfader* xfdp;
unsigned inBaseXfId; unsigned inBaseXfId;
unsigned outBaseXfId; unsigned outBaseXfId;
unsigned stateBaseXfId;
unsigned gainBaseXfId; unsigned gainBaseXfId;
unsigned chCnt; unsigned chCnt;
bool* chGateV; bool* chGateV;
@ -1459,10 +1460,11 @@ cmDspInst_t* _cmDspXfaderAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigne
unsigned chCnt = va_arg(vl,int); unsigned chCnt = va_arg(vl,int);
unsigned fixArgCnt = sizeof(args)/sizeof(args[0]); unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
unsigned argCnt = fixArgCnt + 4*chCnt; unsigned argCnt = fixArgCnt + 5*chCnt;
unsigned inBaseXfId = kGateBaseXfId + chCnt; unsigned inBaseXfId = kGateBaseXfId + chCnt;
unsigned outBaseXfId = inBaseXfId + chCnt; unsigned outBaseXfId = inBaseXfId + chCnt;
unsigned gainBaseXfId= outBaseXfId + chCnt; unsigned stateBaseXfId = outBaseXfId + chCnt;
unsigned gainBaseXfId = stateBaseXfId + chCnt;
cmDspVarArg_t a[ argCnt+1 ]; 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, 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, 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, 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"); cmDspArgSetupN(ctx, a, argCnt, gainBaseXfId, chCnt, "gain", gainBaseXfId, 0, 0, kOutDsvFl | kDoubleDsvFl, "gain output");
cmDspArgSetupNull( a+argCnt); // set terminating arg. flag 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->xfdp = cmXfaderAlloc(ctx->cmProcCtx,NULL,cmDspSampleRate(ctx), chCnt, fadeTimeMs);
p->inBaseXfId = inBaseXfId; p->inBaseXfId = inBaseXfId;
p->outBaseXfId = outBaseXfId; p->outBaseXfId = outBaseXfId;
p->stateBaseXfId = stateBaseXfId;
p->gainBaseXfId = gainBaseXfId; p->gainBaseXfId = gainBaseXfId;
p->chCnt = chCnt; p->chCnt = chCnt;
p->chGateV = cmMemAllocZ(bool,p->chCnt); p->chGateV = cmMemAllocZ(bool,p->chCnt);
@ -1491,6 +1495,11 @@ cmDspInst_t* _cmDspXfaderAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigne
cmDspSetDefaultBool( ctx, &p->inst, kMstrGateXfId, false, false); cmDspSetDefaultBool( ctx, &p->inst, kMstrGateXfId, false, false);
cmDspSetDefaultSymbol( ctx, &p->inst, kOnXfId, p->onSymId ); cmDspSetDefaultSymbol( ctx, &p->inst, kOnXfId, p->onSymId );
cmDspSetDefaultSymbol( ctx, &p->inst, kOffXfId, p->offSymId ); cmDspSetDefaultSymbol( ctx, &p->inst, kOffXfId, p->offSymId );
int i;
for(i=0; i<chCnt; ++i)
cmDspSetDefaultBool( ctx, &p->inst, stateBaseXfId+i, false, false );
return &p->inst; 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); 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 // send the gain output
cmDspSetDouble(ctx,inst,p->gainBaseXfId+i,gain); cmDspSetDouble(ctx,inst,p->gainBaseXfId+i,gain);
} }
@ -1580,8 +1595,6 @@ cmDspRC_t _cmDspXfaderRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t*
break; break;
} }
// record gate changes into p->chGateV[] for later use in _cmDspXfaderExec(). // record gate changes into p->chGateV[] for later use in _cmDspXfaderExec().
if( kGateBaseXfId <= evt->dstVarId && evt->dstVarId < kGateBaseXfId + p->chCnt ) if( kGateBaseXfId <= evt->dstVarId && evt->dstVarId < kGateBaseXfId + p->chCnt )
{ {
@ -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 enum
{ {
kChCntAvId, kChCntAvId,
kModeAvId,
kTrigAvId, kTrigAvId,
kChIdxAvId, kChIdxAvId,
kBaseInDisAvId, kBaseDisInAvId,
kExclusiveModeAvId=0,
kMultiModeAvId=1
}; };
cmDspClass_t _cmAvailCh_DC; cmDspClass_t _cmAvailCh_DC;
@ -5668,10 +5709,8 @@ typedef struct
{ {
cmDspInst_t inst; cmDspInst_t inst;
unsigned chCnt; unsigned chCnt;
unsigned baseOutEnaAvId; unsigned baseDisInAvId;
unsigned baseInDisAvId; unsigned baseGateOutAvId;
unsigned enableSymId;
unsigned disableSymId;
bool* stateArray; bool* stateArray;
} cmDspAvailCh_t; } cmDspAvailCh_t;
@ -5694,30 +5733,34 @@ cmDspInst_t* _cmDspAvailCh_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsig
return NULL; return NULL;
} }
unsigned baseInDisAvId = kBaseInDisAvId; unsigned baseDisInAvId = kBaseDisInAvId;
unsigned baseOutEnaAvId = baseInDisAvId + chCnt; unsigned baseGateOutAvId = baseDisInAvId + chCnt;
cmDspAvailCh_t* p = cmDspInstAllocV(cmDspAvailCh_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1, cmDspAvailCh_t* p = cmDspInstAllocV(cmDspAvailCh_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1,
1, "chs", kChCntAvId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Channel count.", 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, "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.", 1, "ch", kChIdxAvId, 0, 0, kUIntDsvFl | kOutDsvFl, "Currently selected channel.",
chCnt, "dis", baseInDisAvId, 0, 0, kTypeDsvMask | kInDsvFl, "Disable inputs.", chCnt, "dis", baseDisInAvId, 0, 0, kBoolDsvFl | kInDsvFl, "Disable channel gate",
chCnt, "ena", baseOutEnaAvId, 0, 0, kSymDsvFl | kOutDsvFl, "'enable' outputs", chCnt, "gate", baseGateOutAvId, 0, 0, kBoolDsvFl | kOutDsvFl, "Active channel gate",
0 ); 0 );
p->chCnt = chCnt; p->chCnt = chCnt;
p->baseInDisAvId = baseInDisAvId; p->baseDisInAvId = baseDisInAvId;
p->baseOutEnaAvId = baseOutEnaAvId; p->baseGateOutAvId = baseGateOutAvId;
p->enableSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"enable");
p->disableSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"disable");
unsigned i; unsigned i;
for(i=0; i<chCnt; ++i) for(i=0; i<chCnt; ++i)
cmDspSetDefaultSymbol( ctx, &p->inst, 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 ); cmDspSetDefaultUInt( ctx, &p->inst, kChIdxAvId, 0, cmInvalidIdx );
return &p->inst; return &p->inst;
} }
@ -5737,24 +5780,41 @@ cmDspRC_t _cmDspAvailCh_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_
cmDspRC_t rc = kOkDspRC; cmDspRC_t rc = kOkDspRC;
cmDspAvailCh_t* p = (cmDspAvailCh_t*)inst; cmDspAvailCh_t* p = (cmDspAvailCh_t*)inst;
bool exclModeFl = cmDspUInt(inst, kModeAvId ) == kExclusiveModeAvId;
// if this is a trigger // if this is a trigger
if( evt->dstVarId == kTrigAvId ) if( evt->dstVarId == kTrigAvId )
{ {
unsigned i; unsigned i;
bool fl = true;
for(i=0; i<p->chCnt; ++i) for(i=0; i<p->chCnt; ++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); 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; return rc;
} }
// if this is an incoming disable message. // 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); cmDspSetEvent(ctx,inst,evt);
return rc; if( !exclModeFl )
cmDspSetBool(ctx, inst, p->baseGateOutAvId + (evt->dstVarId - p->baseDisInAvId), false);
} }
return rc; return rc;

View File

@ -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"; 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* sphp = cmDspSysAllocInst( h, "Phasor", NULL, 2, cmDspSysSampleRate(h), frqHz );
cmDspInst_t* swtp = cmDspSysAllocInst( h, "WaveTable", NULL, 2, ((int)cmDspSysSampleRate(h)), 4); cmDspInst_t* swtp = cmDspSysAllocInst( h, "WaveTable", NULL, 2, ((int)cmDspSysSampleRate(h)), 4);
cmDspInst_t* fphp = cmDspSysAllocInst( h, "Phasor", NULL, 1, cmDspSysSampleRate(h) ); 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* 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* 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* ao0p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 0 );
cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 1 ); cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 1 );
// phasor->sine->fad-0->aout
cmDspSysConnectAudio(h, sphp, "out", swtp, "phs" ); cmDspSysConnectAudio(h, sphp, "out", swtp, "phs" );
cmDspSysConnectAudio(h, swtp, "out", fad0, "in" ); cmDspSysConnectAudio(h, swtp, "out", fad0, "in-0" );
cmDspSysConnectAudio(h, fad0, "out", ao0p, "in" ); cmDspSysConnectAudio(h, fad0, "out-0", ao0p, "in" );
// phasor->file->fad-1->aout
cmDspSysConnectAudio(h, fphp, "out", fwtp, "phs" ); cmDspSysConnectAudio(h, fphp, "out", fwtp, "phs" );
cmDspSysConnectAudio(h, fwtp, "out", fad1, "in" ); cmDspSysConnectAudio(h, fwtp, "out", fad0, "in-1" );
cmDspSysConnectAudio(h, fad1, "out", ao1p, "in" ); 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; return kOkDspRC;