#include "cmPrefix.h" #include "cmGlobal.h" #include "cmFloatTypes.h" #include "cmRpt.h" #include "cmErr.h" #include "cmCtx.h" #include "cmMem.h" #include "cmMallocDebug.h" #include "cmLinkedHeap.h" #include "cmText.h" #include "cmFileSys.h" #include "cmSymTbl.h" #include "cmJson.h" #include "cmPrefs.h" #include "cmDspValue.h" #include "cmMsgProtocol.h" #include "cmThread.h" #include "cmUdpPort.h" #include "cmUdpNet.h" #include "cmAudioSys.h" #include "cmProcObj.h" #include "cmDspCtx.h" #include "cmDspClass.h" #include "cmDspSys.h" #include "cmDspPgm.h" #include "cmDspPgmPPMain.h" #include "cmAudioFile.h" #include "cmProcObj.h" #include "cmProc.h" #include "cmProc3.h" #include "cmVectOpsTemplateMain.h" #include "cmVectOps.h" /* subnet [ aout ] = fx_chain( ain, hzV ) { cmpThreshDb = -40.0; cmpRatio = 4; cmpAtkMs = 30.0; cmpRlsMs = 100.0; dstInGain = 1.0; dstDSrate = 44100.0; dstBits = 24; eqMode = "LP"; eqHz = hzV[ _i ]; dlyMaxMs = 10000.0; dlyFb = 0.8; loop = loopRecd( ); ps = pitchShift( ); cmp = compressor( cmpThreshDb, cmpRatio, cmpAtkMs, cmpRlsMs ); dst = distortion( dstInGain, dstDSrate, dstBits ); eq = eq( eqMode, eqHz ); dly = delay( dlyMaxMs, dlyFb ); ain -> in.loop.out -> in.ps.out -> in.ps.out loop.out -> ps.in; ps.out -> cmp.in; cmp.out -> dst.in; dst.out -> eq.in; eq.out -> dly.in; dly.out -> aout } audInMapV = [ 0, 1, 0, 1]; audOutMapV = [ 0, 1 ]; hzV = [ 110 220 440 880 ]; ain = audioInput( audioInMap, 1.0 )[ chCnt ]; ef = envFollower( )[ chCnt ]; mtr = meter(0.0,1.0,0.0)[ chCnt ]; fx = fx_chain( ain )( hzV )[ chCnt ]; aout = audioOutput( audioOutMap, 1.0 )[ chCnt ]; ain.out -> ef.in ef.rms -> mtr.in */ // Use the resource int arrays 'pitchList' and 'groupList' to create // the following resource int arrays: // CDmidi - MIDI pitch of all chord notes // CD0midi - MIDI pitch of all low/high chord notes // CD1midi - MIDI pitch of all middle chord notes // NONmidi - MIDI pitch of all non-chord notes. // CDchan - channel index of all chord notes // CD0chan - channel index of all low/high chord notes // CD1chan - channel index of all middle chord notes // NONchan - channel index of all non-chord notes. // cmDspRC_t _cmDspPgm_Main_ProcRsrc( cmDspSysH_t h, cmErr_t* err ) { cmDspRC_t rc; unsigned* midiList = NULL; unsigned midiCnt = 0; unsigned* groupList = NULL; unsigned groupCnt = 0; const cmChar_t* midiListRsrcLabel = "midiList"; const cmChar_t* groupListRsrcLabel = "groupList"; cmJsonH_t jsH = cmDspSysPgmRsrcHandle(h); unsigned i,j,k; if((rc = cmDspRsrcUIntArray(h,&midiCnt,&midiList,midiListRsrcLabel,NULL)) != kOkDspRC ) { rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",midiListRsrcLabel); goto errLabel; } if((rc = cmDspRsrcUIntArray(h,&groupCnt,&groupList,groupListRsrcLabel,NULL)) != kOkDspRC ) { rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",groupListRsrcLabel); goto errLabel; } if( midiCnt != groupCnt ) { rc = cmErrMsg(err,kInvalidStateDspRC,"The resource arrays:%s and %s were not the same length.",midiListRsrcLabel,groupListRsrcLabel); goto errLabel; } for(i=0; i<4; ++i) { int midi[ midiCnt ]; int chan[ midiCnt ]; const cmChar_t* label = NULL; const cmChar_t* label1; for(j=0,k=0; j<midiCnt; ++j) { if( (i<=2 && groupList[j] == i) || (i==3 && groupList[j]!=0) ) { midi[k] = midiList[j]; chan[k] = j; ++k; } } switch( i ) { case 0: label = "NON"; break; case 1: label = "CD0"; break; case 2: label = "CD1"; break; case 3: label = "CD"; break; } if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = cmTsPrintfS("%smidi",label), k, midi ) != kOkJsRC ) { rc = cmErrMsg(err,kJsonFailDspRC,"The chord detector pitch resource '%s' could not be created.", cmStringNullGuard(label1)); goto errLabel; } if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = cmTsPrintfS("%schan",label), k, chan) != kOkJsRC ) { rc = cmErrMsg(err,kJsonFailDspRC,"The chord detector channel index resource '%s' could not be created.", cmStringNullGuard(label1)); goto errLabel; } } errLabel: return rc; } // Use the resource int arrays 'MidiList',"MachineList", "ChordList" and 'GroupList' to create // the resource int arrays. XXXchan arrays contain indexes between 0 and 15. When used with // the chord detector this the 'local' channels are 0-15 and the remote channels are 16-31. // NLCDmidi - MIDI pitch of all local chord notes // NLCD0midi - MIDI pitch of all local low single notes // NLCD1midi - MIDI pitch of all local middle single notes // NLEEmidi - MIDI pitch of all local e-e single notes. // NLCDchan - channel index of all local chord notes // NLCD0chan - channel index of all local high single notes // NLCD1chan - channel index of all local middle single notes // NLEEchan - channel index of all local e-e single notes. // NRCDmidi - MIDI pitch of all remote chord notes // NRCD0midi - MIDI pitch of all remote low single notes // NRCD1midi - MIDI pitch of all remote middle single notes // NREEmidi - MIDI pitch of all remote e-e single notes. // NRCDchan - channel index of all remote chord notes // NRCD0chan - channel index of all remote high single notes // NRCD1chan - channel index of all remote middle single notes // NREEchan - channel index of all remote e-e single notes. // 'local' refers to the machine running the chord detector // 'remote' refers to the machine not running the chord detector cmDspRC_t _cmDspPgm_Main_NetProcRsrc( cmDspSysH_t h, cmErr_t* err ) { cmDspRC_t rc = kOkDspRC; const cmChar_t* midiListRsrcLabel = "MidiList"; unsigned* midiList = NULL; unsigned midiCnt = 0; const cmChar_t* machListRsrcLabel = "MachineList"; unsigned* machList = NULL; unsigned machCnt = 0; const cmChar_t* groupListRsrcLabel = "GroupList"; unsigned* groupList = NULL; unsigned groupCnt = 0; const cmChar_t* chordListRsrcLabel = "ChordList"; unsigned* chordList = NULL; unsigned chordCnt = 0; cmJsonH_t jsH = cmDspSysPgmRsrcHandle(h); const cmChar_t* localNetNodeLabel = NULL; unsigned localNetNodeId = cmInvalidId; bool verboseFl = false; unsigned i,j,k,m; // get the network node id of this machine if(( cmDspRsrcString(h, &localNetNodeLabel, "cdLocalNetNode", NULL )) != kOkDspRC ) { rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource 'cdLocalNetNode' could not be read."); goto errLabel; } if(( localNetNodeId = cmDspSysNetNodeLabelToId(h,localNetNodeLabel)) == cmInvalidId ) { cmErrMsg(err,kInvalidArgDspRC,"The network node label '%s' is not valid.",cmStringNullGuard(localNetNodeLabel)); goto errLabel; } // get the pitch assigned to each channel if((rc = cmDspRsrcUIntArray(h,&midiCnt,&midiList,midiListRsrcLabel,NULL)) != kOkDspRC ) { rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",midiListRsrcLabel); goto errLabel; } // get the network node id of each channel if((rc = cmDspRsrcUIntArray(h,&machCnt,&machList,machListRsrcLabel,NULL)) != kOkDspRC ) { rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",machListRsrcLabel); goto errLabel; } // get the group id of each channel if((rc = cmDspRsrcUIntArray(h,&groupCnt,&groupList,groupListRsrcLabel,NULL)) != kOkDspRC ) { rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",groupListRsrcLabel); goto errLabel; } // get the chord detector flag for each channel if((rc = cmDspRsrcUIntArray(h,&chordCnt,&chordList,chordListRsrcLabel,NULL)) != kOkDspRC ) { rc = cmErrMsg(err,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",chordListRsrcLabel); goto errLabel; } if( midiCnt != groupCnt || midiCnt != machCnt) { rc = cmErrMsg(err,kInvalidStateDspRC,"The resource arrays:%s, %s and %s were not all the same length.",midiListRsrcLabel,machListRsrcLabel,groupListRsrcLabel); goto errLabel; } if( 1 ) { const cmChar_t* label1; unsigned ten = 10; int nsChSelChV[ midiCnt ]; // note selector chord port [0, 5] int nsChSelChIdxV[ midiCnt ]; // index on note selector port int nsNcSelChV[ midiCnt ]; // note selector single-note port [ 2, 3, 4, 7,8,9 ] int nsNcSelChIdxV[ midiCnt ]; // index on note selector single-note port unsigned chIdxCntV[ ten ]; // next index for each note selector port cmVOU_Fill(chIdxCntV,ten,0); for(i=0; i<midiCnt; ++i) { unsigned localFl = i<16; unsigned selIdx = localFl ? 0 : 5; // chord port unsigned chordChFl = chordList[i] != 0; // is this a chord channel nsChSelChV[i] = cmInvalidIdx; nsChSelChIdxV[i] = cmInvalidIdx; if( chordChFl ) { nsChSelChV[ i ] = selIdx; nsChSelChIdxV[ i ] = chIdxCntV[ selIdx ]; chIdxCntV[ selIdx ] += 1; } switch( groupList[i] ) { case 0: selIdx = localFl ? 4 : 9; break; // e-e group case 1: selIdx = localFl ? 2 : 7; break; // hi/lo group case 2: selIdx = localFl ? 3 : 8; break; // mid group default: { assert(0); } } assert( selIdx < ten ); nsNcSelChV[ i ] = selIdx; nsNcSelChIdxV[ i ] = chIdxCntV[ selIdx ]; chIdxCntV[ selIdx ] += 1; } if( verboseFl ) { cmVOI_PrintL("nsChSelChV", err->rpt, 1, midiCnt, nsChSelChV ); cmVOI_PrintL("nsChSelChIdxV", err->rpt, 1, midiCnt, nsChSelChIdxV ); cmVOI_PrintL("nsNcSelChV", err->rpt, 1, midiCnt, nsNcSelChV ); cmVOI_PrintL("nsNcSelChIdxV", err->rpt, 1, midiCnt, nsNcSelChIdxV ); } if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = "nsChSelChV", midiCnt, nsChSelChV ) != kOkJsRC ) { rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1)); goto errLabel; } if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = "nsChSelChIdxV", midiCnt, nsChSelChIdxV ) != kOkJsRC ) { rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1)); goto errLabel; } if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = "nsNcSelChV", midiCnt, nsNcSelChV ) != kOkJsRC ) { rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1)); goto errLabel; } if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = "nsNcSelChIdxV", midiCnt, nsNcSelChIdxV ) != kOkJsRC ) { rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1)); goto errLabel; } for(i=0; i<ten; ++i) { int midi[ midiCnt ]; int chan[ midiCnt ]; for(j=0,k=0; j<midiCnt; ++j) { m = i; if( m == 1 || m == 6 ) m -= 1; if( nsChSelChV[j] == m ) { midi[k] = midiList[j]; chan[k] = j>15 ? j-16 : j; assert( k == nsChSelChIdxV[j] ); ++k; } if( nsNcSelChV[j] == m ) { midi[k] = midiList[j]; chan[k] = j>15 ? j-16 : j; assert( k == nsNcSelChIdxV[j] ); ++k; } } if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = cmTsPrintfS("nsMidi-%i",i), k, midi ) != kOkJsRC ) { rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1)); goto errLabel; } if( verboseFl ) cmVOI_PrintL(label1, err->rpt, 1, k, midi ); if( cmJsonInsertPairIntArray( jsH, cmJsonRoot(jsH), label1 = cmTsPrintfS("nsChan-%i",i), k, chan ) != kOkJsRC ) { rc = cmErrMsg(err,kJsonFailDspRC,"The note selector resource '%s' could not be created.", cmStringNullGuard(label1)); goto errLabel; } if( verboseFl ) cmVOI_PrintL(label1, err->rpt, 1, k, chan ); } } errLabel: return rc; } const cmChar_t* _cmDspPP_SelCheckTitle( cmDspSysH_t h, unsigned i ) { return _cmDspPP_CircuitDesc(i)->title; } cmDspRC_t _cmDspSysPgm_Main( cmDspSysH_t h, void** userPtrPtr ) { cmDspRC_t rc = kOkDspRC; const cmChar_t* chCfgFn = NULL; cmCtx_t* cmCtx = cmDspSysPgmCtx(h); double efOnThrDb = -40; double efOffThrDb = -70; double efMaxDb = -15; unsigned circuitCnt = _cmDspPP_CircuitDescCount(); unsigned resetSymId = cmDspSysRegisterStaticSymbol(h,"_reset"); bool inFileFl = false; cmErr_t err; _cmDspPP_Ctx_t ctx; cmDspPP_CircuitSwitch_t sw; memset(&sw,0,sizeof(sw)); // set up the global context record memset(&ctx,0,sizeof(ctx)); ctx.oChCnt = 2; ctx.err = &err; cmErrSetup(&err,&cmCtx->rpt,"PP Main"); // create the individual non-networked chord detector resource arrays from the base resource arrays if((rc =_cmDspPgm_Main_ProcRsrc(h,&err)) != kOkDspRC ) goto errLabel; // create the individual networked chord detector resource arrays from the base resource arrays if((rc = _cmDspPgm_Main_NetProcRsrc(h,&err)) != kOkDspRC ) goto errLabel; // get the channel cfg configuration file name if( cmJsonPathToString( cmDspSysPgmRsrcHandle(h), NULL, NULL, "chCfgFn", &chCfgFn ) != kOkJsRC ) { rc = cmErrMsg(&err,kRsrcNotFoundDspRC,"The 'chCfgFn' resource was not found."); goto errLabel; } // get the count of channels from the ch. cfg. array if(( ctx.iChCnt = cmChCfgChannelCount(cmCtx,chCfgFn,&ctx.nsCnt)) == 0 ) { rc = cmErrMsg(&err,kPgmCfgFailDspRC,"Unable to obtain the channel count from '%s'.",cmStringNullGuard(chCfgFn)); goto errLabel; } if( rc == kOkDspRC ) { unsigned inChCnt,outChCnt; // channel cfg ctx.chCfg = cmDspSysAllocInst( h, "ChCfg", NULL, 1, chCfgFn ); // global printer ctx.print = cmDspSysAllocInst( h, "Printer", NULL, 1, ">" ); cmDspInst_t** ain; cmDspInst_t* phs; // audio input if( inFileFl ) { unsigned wtSmpCnt = (unsigned)cmDspSysSampleRate(h); unsigned wtMode = 1; //file mode const cmChar_t* fn = "/home/kevin/media/audio/gate_detect/gate_detect2.aif"; phs = cmDspSysAllocInst(h,"Phasor", NULL, 0 ); ain = cmDspSysAllocInstArray(h, ctx.iChCnt, "WaveTable", NULL, NULL, 3, wtSmpCnt, wtMode, fn ); inChCnt = ctx.iChCnt; } else { ain = cmDspSysAllocAudioInAR( h, "audioInMap", 1.0, &inChCnt ); } // envelope followers and RMS meters cmDspSysAllocLabel(h,"EF Gates",kLeftAlignDuiId ); cmDspInst_t** ef = cmDspSysAllocInstArray( h, ctx.iChCnt,"EnvFollow", NULL, NULL, 0 ); cmDspInst_t** mtr = cmDspSysAllocInstArray( h, ctx.iChCnt,"Meter", "mtr", NULL, 3, 0.0, 0.0, 1.0 ); // Level meters cmDspSysNewColumn(h,200); cmDspSysAllocLabel(h,"Level",kLeftAlignDuiId ); cmDspInst_t** lvl = cmDspSysAllocInstArray( h, ctx.iChCnt,"Meter", "lvl", NULL, 3, 0.0, 0.0, 1.0 ); assert( inChCnt == ctx.iChCnt ); // Onset count displays cmDspSysNewColumn(h,200); cmDspInst_t** onn = cmDspSysAllocInstArray( h, ctx.iChCnt,"Scalar", "on", NULL, 5, kNumberDuiId, 0.0, 10000.0, 1.0, 0.0 ); cmDspSysNewColumn(h,200); // program reset button cmDspInst_t* resetBtn = cmDspSysAllocButton( h, "reset", 0 ); cmDspSysAssignInstAttrSymbol(h,resetBtn, resetSymId ); // circuit selection check-boxes cmDspInst_t** csel = cmDspSysAllocInstArray( h, circuitCnt, "Button", NULL, _cmDspPP_SelCheckTitle, 2, kCheckDuiId, 0.0 ); cmDspSysNewColumn(h,200); cmDspSysAllocLabel(h,"Out Gains",kLeftAlignDuiId ); // output gain controls cmDspInst_t** ogain = cmDspSysAllocInstArray( h, ctx.oChCnt,"Scalar", "mgain", NULL, 5, kNumberDuiId, 0.0, 10.0, 0.01, 1.0); // envelope follower parameters cmDspInst_t* onThr = cmDspSysAllocScalar( h, "On Thresh",-100.0, 0.0, 0.1, efOnThrDb); cmDspInst_t* offThr = cmDspSysAllocScalar( h, "Off Thresh",-100.0, 0.0, 0.1, efOffThrDb); cmDspInst_t* maxDb = cmDspSysAllocScalar( h, "Max Db", -100.0, 0.0, 0.1, efMaxDb); // switcher and circuits _cmDspPP_CircuitSwitchAlloc(h, &ctx, &sw, resetBtn, csel, ain, ef); // audio output cmDspInst_t** aout = cmDspSysAllocAudioOutAR( h, "audioOutMap", 1.0, &outChCnt ); assert( outChCnt == ctx.oChCnt ); //cmDspInst_t* prt = cmDspSysAllocInst( h, "Printer", NULL, 2, "", 250 ); // check for errors if((rc = cmDspSysLastRC(h)) != kOkDspRC ) goto doneLabel; if( inFileFl ) { cmDspSysConnectAudio11N1( h, phs, "out", ain, "phs", ctx.iChCnt ); // phs -> wt cmDspSysConnectAudioN1N1( h, ain, "out", ef, "in", ctx.iChCnt ); // wt -> EF } else { cmDspSysConnectAudioN1N1( h, ain, "out", ef, "in", ctx.iChCnt ); // ain -> EF } cmDspSysInstallCb1NN1( h, ctx.chCfg, "gain", ain, "gain", ctx.iChCnt ); // chCfg -> ain (gain) cmDspSysConnectAudioN1N1( h, sw.omix, "out", aout, "in", ctx.oChCnt ); // Sw.mix -> aout cmDspSysInstallCbN1N1( h, ogain, "val", aout, "gain", ctx.oChCnt ); // gain -> aout cmDspSysInstallCb( h, resetBtn,"sym", ctx.chCfg, "sel", NULL ); // reset -> chCfg cmDspSysInstallCbN1N1( h, ef, "gate", mtr, "in", ctx.iChCnt ); // EF -> meter (gate) cmDspSysInstallCbN1N1( h, ef, "level", lvl, "in", ctx.iChCnt ); // EF -> meter (level) cmDspSysInstallCbN1N1( h, ef, "ons", onn, "val", ctx.iChCnt ); cmDspSysInstallCb11N1( h, onThr, "val", ef, "ondb", ctx.iChCnt ); // EF sensivity settings cmDspSysInstallCb11N1( h, offThr, "val", ef, "offdb", ctx.iChCnt ); // cmDspSysInstallCb11N1( h, maxDb, "val", ef, "maxdb", ctx.iChCnt ); // //cmDspSysInstallCbN111( h, ef, "level", prt, "in", ctx.iChCnt ); doneLabel: _cmDspPP_CircuitSwitchFree(h, &sw ); } errLabel: if( rc != kOkDspRC ) cmErrMsg(&err,rc,"'main' construction failed."); return rc; }