diff --git a/dsp/cmDspBuiltIn.c b/dsp/cmDspBuiltIn.c index dcf7b14..c57916b 100644 --- a/dsp/cmDspBuiltIn.c +++ b/dsp/cmDspBuiltIn.c @@ -40,6 +40,7 @@ #include "cmMidi.h" #include "cmProc2.h" #include "cmVectOpsTemplateMain.h" +#include "cmMidiPort.h" /* About variables: @@ -979,6 +980,239 @@ struct cmDspClass_str* cmSigGenClassCons( cmDspCtx_t* ctx ) return &_cmSigGenDC; } +//========================================================================================================================================== +enum +{ + kDeviceMiId, + kPortMiId, + kSmpIdxMiId, + kStatusMiId, + kD0MiId, + kD1MiId +}; + + +cmDspClass_t _cmMidiInDC; + +typedef struct +{ + cmDspInst_t inst; + unsigned midiSymId; + unsigned prevSmpIdx; +} cmDspMidiIn_t; + +cmDspInst_t* _cmDspMidiInAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) +{ + cmDspVarArg_t args[] = + { + { "device", kDeviceMiId, 0, 0, kOutDsvFl | kUIntDsvFl, "MIDI device" }, + { "port", kPortMiId, 0, 0, kOutDsvFl | kUIntDsvFl, "MIDI device port"}, + { "smpidx", kSmpIdxMiId, 0, 0, kOutDsvFl | kUIntDsvFl, "Message time tag as sample index."}, + { "status", kStatusMiId, 0, 0, kOutDsvFl | kUIntDsvFl, "MIDI status" }, + { "d0", kD0MiId, 0, 0, kOutDsvFl | kUIntDsvFl, "MIDI channel message d0" }, + { "d1", kD1MiId, 0, 0, kOutDsvFl | kUIntDsvFl, "MIDI channel message d1" }, + { NULL, 0, 0, 0, 0 } + }; + + cmDspMidiIn_t* p = cmDspInstAlloc(cmDspMidiIn_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl); + + p->midiSymId = cmDspSysAssignInstAttrSymbolStr( ctx->dspH, &p->inst, "_midi" ); + + return &p->inst; +} + +cmDspRC_t _cmDspMidiInReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspMidiIn_t* p = (cmDspMidiIn_t*)inst; + cmDspApplyAllDefaults(ctx,inst); + p->prevSmpIdx = 0; + return rc; +} + +cmDspRC_t _cmDspMidiInRecvFunc( cmDspCtx_t* ctx, struct cmDspInst_str* inst, unsigned attrSymId, const cmDspValue_t* value ) +{ + cmDspMidiIn_t* p = (cmDspMidiIn_t*)inst; + + if( attrSymId == p->midiSymId ) + { + cmMidiPacket_t* pkt = (cmMidiPacket_t*)(value->u.m.u.vp); + unsigned i; + + cmDspSetUInt(ctx, inst, kDeviceMiId, pkt->devIdx); + cmDspSetUInt(ctx, inst, kPortMiId, pkt->portIdx); + + for(i=0; imsgCnt; ++i) + { + cmMidiMsg* m = pkt->msgArray + i; + unsigned deltaSmpCnt = floor((m->deltaUs * cmDspSampleRate(ctx)) / 1000000.0); + + if( p->prevSmpIdx == 0 ) + p->prevSmpIdx = ctx->cycleCnt * cmDspSamplesPerCycle(ctx); + else + p->prevSmpIdx += deltaSmpCnt; + + cmDspSetUInt(ctx, inst, kSmpIdxMiId, p->prevSmpIdx ); + cmDspSetUInt(ctx, inst, kD1MiId, m->d1 ); + cmDspSetUInt(ctx, inst, kD0MiId, m->d0 ); + cmDspSetUInt(ctx, inst, kStatusMiId, m->status ); + } + } + + return kOkDspRC; +} + +struct cmDspClass_str* cmMidiInClassCons( cmDspCtx_t* ctx ) +{ + cmDspClassSetup(&_cmMidiInDC,ctx,"MidiIn", + NULL, + _cmDspMidiInAlloc, + NULL, + _cmDspMidiInReset, + NULL, + NULL, + NULL, + _cmDspMidiInRecvFunc, + "Midi input port"); + + return &_cmMidiInDC; +} + +//========================================================================================================================================== +enum +{ + kDeviceMoId, + kPortMoId, + kStatusMoId, + kD0MoId, + kD1MoId +}; + +cmDspClass_t _cmMidiOutDC; + +typedef struct +{ + cmDspInst_t inst; + unsigned devIdx; + unsigned portIdx; +} cmDspMidiOut_t; + +cmDspRC_t _cmDspMidiOutSetDevice( cmDspCtx_t* ctx, cmDspMidiOut_t* p, const cmChar_t* deviceStr ) +{ + cmDspRC_t rc = kOkDspRC; + + if( deviceStr != NULL ) + if((p->devIdx = cmMpDeviceNameToIndex(deviceStr)) == cmInvalidIdx ) + rc = cmDspInstErr(ctx,&p->inst,kInvalidArgDspRC,"The MIDI device '%s' could not be found.",cmStringNullGuard(deviceStr)); + + return rc; +} + +cmDspRC_t _cmDspMidiOutSetPort( cmDspCtx_t* ctx, cmDspMidiOut_t* p, const cmChar_t* portStr ) +{ + cmDspRC_t rc = kOkDspRC; + + if( portStr == NULL ) + return rc; + + if( p->devIdx == cmInvalidIdx ) + rc = cmDspInstErr(ctx,&p->inst,kInvalidArgDspRC,"The MIDI port cannot be set until the MIDI device is set."); + else + { + if((p->portIdx = cmMpDevicePortNameToIndex(p->devIdx,kOutMpFl,portStr)) == cmInvalidIdx ) + rc = cmDspInstErr(ctx,&p->inst,kInvalidArgDspRC,"The MIDI port '%s' could not be found on device '%s'.",cmStringNullGuard(portStr),cmStringNullGuard(cmMpDeviceName(p->devIdx))); + } + + return rc; +} + +cmDspInst_t* _cmDspMidiOutAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) +{ + cmDspVarArg_t args[] = + { + { "device", kDeviceMoId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "MIDI device name"}, + { "port", kPortMoId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "MIDI port name"}, + { "status", kStatusMoId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI status" }, + { "d0", kD0MoId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI channel message d0" }, + { "d1", kD1MoId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI channel message d1" }, + { NULL, 0, 0, 0, 0 } + }; + + cmDspMidiOut_t* p = cmDspInstAlloc(cmDspMidiOut_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl); + + p->devIdx = cmInvalidIdx; + p->portIdx = cmInvalidIdx; + + cmDspSetDefaultUInt(ctx,&p->inst, kStatusMoId, 0, 0 ); + cmDspSetDefaultUInt(ctx,&p->inst, kD0MoId, 0, 0 ); + cmDspSetDefaultUInt(ctx,&p->inst, kD1MoId, 0, 0 ); + + return &p->inst; +} + +cmDspRC_t _cmDspMidiOutReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspMidiOut_t* p = (cmDspMidiOut_t*)inst; + + cmDspApplyAllDefaults(ctx,inst); + + _cmDspMidiOutSetDevice(ctx,p,cmDspStrcz(inst,kDeviceMoId)); + _cmDspMidiOutSetPort( ctx,p,cmDspStrcz(inst,kPortMoId)); + + return rc; +} + +cmDspRC_t _cmDspMidiOutRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspMidiOut_t* p = (cmDspMidiOut_t*)inst; + + switch( evt->dstVarId ) + { + case kDeviceMoId: + _cmDspMidiOutSetDevice(ctx, p, cmDsvStrcz(evt->valuePtr) ); + break; + + case kPortMoId: + _cmDspMidiOutSetPort(ctx, p, cmDsvStrcz(evt->valuePtr) ); + break; + + case kStatusMoId: + if( p->devIdx != cmInvalidIdx && p->portIdx != cmInvalidIdx ) + { + unsigned status = cmDsvGetUInt(evt->valuePtr); + unsigned d0 = cmDspUInt(inst,kD0MoId); + unsigned d1 = cmDspUInt(inst,kD1MoId); + if( cmMpDeviceSend( p->devIdx, p->portIdx, status, d0, d1 ) != kOkMpRC ) + cmDspInstErr(ctx,inst,kInvalidArgDspRC,"MIDI send failed."); + } + break; + + default: + cmDspSetEvent(ctx,inst,evt); + break; + } + + + return kOkDspRC; +} + +struct cmDspClass_str* cmMidiOutClassCons( cmDspCtx_t* ctx ) +{ + cmDspClassSetup(&_cmMidiOutDC,ctx,"MidiOut", + NULL, + _cmDspMidiOutAlloc, + NULL, + _cmDspMidiOutReset, + NULL, + _cmDspMidiOutRecv, + NULL, + NULL, + "Midi input port"); + + return &_cmMidiOutDC; +} + //========================================================================================================================================== enum { @@ -2980,7 +3214,7 @@ cmDspRC_t _cmDspWaveTableReadAudioFile( cmDspCtx_t* ctx, cmDspWaveTable_t* p, un cmDspRC_t _cmDspWaveTableInitAudioFile( cmDspCtx_t* ctx, cmDspWaveTable_t* p ) { - cmDspRC_t rc; + cmDspRC_t rc = kOkDspRC; cmAudioFileH_t afH; cmRC_t afRC; cmAudioFileInfo_t afInfo; @@ -2992,7 +3226,7 @@ cmDspRC_t _cmDspWaveTableInitAudioFile( cmDspCtx_t* ctx, cmDspWaveTable_t* p ) // if the file name is valid if( fn == NULL || strlen(fn)==0 ) { - cmDspInstErr(ctx,&p->inst,kVarNotValidDspRC,"Audio file loading was requested for the wave table but no file name was given."); + rc = cmDspInstErr(ctx,&p->inst,kVarNotValidDspRC,"Audio file loading was requested for the wave table but no file name was given."); goto errLabel; } @@ -3468,7 +3702,7 @@ cmDspRC_t _cmSprintfGetInputTypes( cmDspCtx_t* ctx, cmDspClass_t* classPtr, cons snprintf(fmtArray[j].label,kSprintfLabelCharCnt,"in-%i",j); fmtArray[j].label[kSprintfLabelCharCnt]=0; - fmtArray[j].label[kSprintfDocCharCnt] = 0; + fmtArray[j].doc[kSprintfDocCharCnt] = 0; switch( fmt[ i + fn - 1 ] ) { @@ -4942,6 +5176,8 @@ cmDspClassConsFunc_t _cmDspClassBuiltInArray[] = cmCounterClassCons, cmPhasorClassCons, + cmMidiOutClassCons, + cmMidiInClassCons, cmAudioInClassCons, cmAudioOutClassCons, cmAudioFileOutClassCons, @@ -5018,6 +5254,7 @@ cmDspClassConsFunc_t _cmDspClassBuiltInArray[] = cmScFolClassCons, cmScModClassCons, cmGSwitchClassCons, + cmScaleRangeClassCons, NULL, }; diff --git a/dsp/cmDspPgm.c b/dsp/cmDspPgm.c index 61aa51f..3443459 100644 --- a/dsp/cmDspPgm.c +++ b/dsp/cmDspPgm.c @@ -25,6 +25,40 @@ #include "cmDspPgmPP.h" #include "cmDspPgmKr.h" +cmDspRC_t _cmDspSysPgm_Test_Midi( cmDspSysH_t h, void** userPtrPtr ) +{ + cmDspRC_t rc = kOkDspRC; + + cmDspInst_t* sendBtn = cmDspSysAllocInst( h,"Button", "Send", 2, kButtonDuiId, 0.0 ); + cmDspInst_t* status = cmDspSysAllocInst( h,"Scalar", "Status", 5, kNumberDuiId, 0.0, 127.0, 1.0, 144.0); + cmDspInst_t* d0 = cmDspSysAllocInst( h,"Scalar", "D0", 5, kNumberDuiId, 0.0, 127.0, 1.0, 64.0); + cmDspInst_t* d1 = cmDspSysAllocInst( h,"Scalar", "D1", 5, kNumberDuiId, 0.0, 127.0, 1.0, 64.0); + cmDspInst_t* midiOut = cmDspSysAllocInst( h,"MidiOut", NULL, 2, "Fastlane", "Fastlane MIDI A"); + cmDspInst_t* midiIn = cmDspSysAllocInst( h,"MidiIn", NULL, 0 ); + cmDspInst_t* printer = cmDspSysAllocInst( h,"Printer", NULL, 1, ">" ); + + // check for allocation errors + if((rc = cmDspSysLastRC(h)) != kOkDspRC ) + goto errLabel; + + cmDspSysInstallCb( h, sendBtn, "out", d1, "send", NULL); + cmDspSysInstallCb( h, sendBtn, "out", d0, "send", NULL); + cmDspSysInstallCb( h, sendBtn, "out", status, "send", NULL); + + cmDspSysInstallCb( h, status, "val", midiOut, "status",NULL); + cmDspSysInstallCb( h, d0, "val", midiOut, "d0", NULL); + cmDspSysInstallCb( h, d1, "val", midiOut, "d1", NULL); + + cmDspSysInstallCb( h, midiIn, "status", printer, "in", NULL); + cmDspSysInstallCb( h, midiIn, "d0", printer, "in", NULL); + cmDspSysInstallCb( h, midiIn, "d1", printer, "in", NULL); + cmDspSysInstallCb( h, midiIn, "smpidx", printer, "in", NULL); + + errLabel: + return rc; + +} + cmDspRC_t _cmDspSysPgm_Stereo_Through( cmDspSysH_t h, void** userPtrPtr ) { bool useBuiltInFl = true; @@ -2332,7 +2366,7 @@ cmDspRC_t _cmDspSysPgm_AvailCh( cmDspSysH_t h, void** userPtrPtr ) 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* prp = cmDspSysAllocInst( h, "Printer", NULL, 1, ">" ); + //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 ); @@ -2389,6 +2423,7 @@ _cmDspSysPgm_t _cmDspSysPgmArray[] = { "pickup tails", _cmDspSysPgm_NoiseTails, NULL, NULL }, { "tails_2", _cmDspSysPgm_NoiseTails2, NULL, NULL }, { "pickups", _cmDspSysPgm_Pickups0, NULL, NULL }, + { "midi_test", _cmDspSysPgm_Test_Midi, NULL, NULL }, { "2_thru", _cmDspSysPgm_Stereo_Through, NULL, NULL }, { "guitar", _cmDspSysPgmGuitar, NULL, NULL }, { "2_fx", _cmDspSysPgm_Stereo_Fx, NULL, NULL }, diff --git a/dsp/cmDspSys.c b/dsp/cmDspSys.c index 5d3fc73..9082365 100644 --- a/dsp/cmDspSys.c +++ b/dsp/cmDspSys.c @@ -10,6 +10,7 @@ #include "cmText.h" #include "cmFileSys.h" #include "cmSymTbl.h" +#include "cmMidi.h" #include "cmJson.h" #include "cmPrefs.h" #include "cmDspValue.h" @@ -619,10 +620,13 @@ cmDspRC_t cmDspSysRcvMsg( cmDspSysH_t h, cmAudioSysCtx_t* asCtx, const void* } else { - // the msg selector is the second field in the data packet (following the audio system sub-system id) - const unsigned msgTypeSelId = ((const unsigned*)msgPtr)[1]; + unsigned* hdr = (unsigned*)msgPtr; - switch( msgTypeSelId ) + // the msg selector is the second field in the data packet (following the audio system sub-system id) + //const unsigned msgTypeSelId = ((const unsigned*)msgPtr)[1]; + + + switch( hdr[1] ) { case kUiSelAsId: _cmDspSysHandleUiMsg(p,ip,msgPtr,msgByteCnt); @@ -633,11 +637,27 @@ cmDspRC_t cmDspSysRcvMsg( cmDspSysH_t h, cmAudioSysCtx_t* asCtx, const void* break; case kMidiMsgArraySelAsId: + { + cmMidiPacket_t pkt; + cmDspValue_t v; + + pkt.cbDataPtr = NULL; + pkt.devIdx = hdr[2]; + pkt.portIdx = hdr[3]; + pkt.msgCnt = hdr[4]; + pkt.msgArray = (cmMidiMsg*)(hdr + 5); + unsigned midiSymId = cmDspSysRegisterStaticSymbol(h,"_midi"); + + v.u.m.u.vp = &pkt; + cmDspSysBroadcastValue(h, midiSymId, &v); + + /* // data format for MIDI messages { kMidiMsgArraytSelAsId, devIdx, portIdx, msgCnt, msgArray[msgCnt] } where each msgArray[] record is a cmMidiMsg record. */ + } break; }