//--------------------------------------------------------- // processEvent // All events from the sequencer go here //--------------------------------------------------------- bool ISynth::processEvent(const MusECore::MidiPlayEvent& ev) { switch(ev.type()) { case MusECore::ME_CONTROLLER: setController(ev.channel(), ev.dataA(), ev.dataB()); //return true; // ?? break; case MusECore::ME_NOTEON: return playNote(ev.channel(), ev.dataA(), ev.dataB()); case MusECore::ME_NOTEOFF: return playNote(ev.channel(), ev.dataA(), 0); case MusECore::ME_SYSEX: return sysex(ev.len(), ev.data()); case MusECore::ME_PITCHBEND: setController(ev.channel(), MusECore::CTRL_PITCH, ev.dataA()); break; // Synths are not allowed to receive ME_PROGRAM, CTRL_HBANK, or CTRL_LBANK alone anymore - only CTRL_PROGRAM. //case MusECore::ME_PROGRAM: // setController(ev.channel(), MusECore::CTRL_PROGRAM, ev.dataA()); // break; default: break; } return false; }
bool MIDIFileReadMultiTrack::mf_sysex ( MIDIClockTime time, int type, int len, unsigned char *s ) // funcVRM { MIDITimedMessage msg; msg.SetSysEx( type ); // set msg status byte (0xF0 or 0xF7) int num = len; // number of possible SysExURT header data bytes in msg, 0...5 if ( num > 5 ) num = 5; // add up to 5 starting bytes for SysExURT functions if ( num > 0 ) msg.SetByte2( s[0] ); if ( num > 1 ) msg.SetByte3( s[1] ); if ( num > 2 ) msg.SetByte4( s[2] ); if ( num > 3 ) msg.SetByte5( s[3] ); if ( num > 4 ) msg.SetByte6( s[4] ); msg.SetTime ( time ); MIDISystemExclusive sysex( len ); for ( int i = 0; i < len; ++i ) { sysex.PutSysByte ( s[i] ); } msg.SetDataLength( num ); return AddEventToMultiTrack ( msg, &sysex, cur_track ); }
void pluginCore::processSysex(int length, char *data) { tMidiSysex sx; sx.length = length; sx.data = new unsigned char[length]; memcpy(sx.data, data, length * sizeof(char)); m_midi_sysex.push(sx); sysex(length, data[0]); }
bool Mess::processEvent(const MidiPlayEvent& ev) { switch(ev.type()) { case ME_NOTEON: return playNote(ev.channel(), ev.dataA(), ev.dataB()); case ME_NOTEOFF: return playNote(ev.channel(), ev.dataA(), 0); case ME_SYSEX: return sysex(ev.len(), ev.data()); case ME_CONTROLLER: return setController(ev.channel(), ev.dataA(), ev.dataB()); case ME_PITCHBEND: // Tim. return setController(ev.channel(), CTRL_PITCH, ev.dataA()); } return false; }
bool MIDIFileReadMultiTrack::mf_text ( MIDIClockTime time, int type, int len, unsigned char *s ) // VRM { MIDITimedMessage msg; msg.SetStatus ( META_EVENT ); msg.SetMetaType ( ( uchar ) type ); // remember - MF_META_* id codes match META_* codes msg.SetTime ( time ); MIDISystemExclusive sysex( len ); // VRM for ( int i = 0; i < len; ++i ) { sysex.PutSysByte ( s[i] ); // VRM } msg.SetDataLength( 0 ); // VRM // variable data length don't saved to data_length return AddEventToMultiTrack ( msg, &sysex, cur_track ); // VRM }
//--------------------------------------------------------- // processEvent // All events from the sequencer go here //--------------------------------------------------------- bool ISynth::processEvent(const MusECore::MidiPlayEvent& ev) { switch(ev.type()) { case MusECore::ME_CONTROLLER: setController(ev.channel(), ev.dataA(), ev.dataB()); //return true; // ?? break; case MusECore::ME_NOTEON: return playNote(ev.channel(), ev.dataA(), ev.dataB()); case MusECore::ME_NOTEOFF: return playNote(ev.channel(), ev.dataA(), 0); case MusECore::ME_SYSEX: return sysex(ev.len(), ev.data()); case MusECore::ME_PITCHBEND: setController(ev.channel(), MusECore::CTRL_PITCH, ev.dataA()); break; case MusECore::ME_PROGRAM: setController(ev.channel(), MusECore::CTRL_PROGRAM, ev.dataA()); break; default: break; } return false; }
VstIntPtr VSTCALLBACK IPlugVST::VSTDispatcher(AEffect *pEffect, VstInt32 opCode, VstInt32 idx, VstIntPtr value, void *ptr, float opt) { // VSTDispatcher is an IPlugVST class member, we can access anything in IPlugVST from here. IPlugVST* _this = (IPlugVST*) pEffect->object; if (!_this) { return 0; } IPlugBase::IMutexLock lock(_this); // Handle a couple of opcodes here to make debugging easier. switch (opCode) { case effEditIdle: case __effIdleDeprecated: #ifdef USE_IDLE_CALLS _this->OnIdle(); #endif return 0; } Trace(TRACELOC, "%d(%s):%d:%d", opCode, VSTOpcodeStr(opCode), idx, (int) value); switch (opCode) { case effOpen: { _this->HostSpecificInit(); _this->OnParamReset(); return 0; } case effClose: { lock.Destroy(); DELETE_NULL(_this); return 0; } case effGetParamLabel: { if (idx >= 0 && idx < _this->NParams()) { strcpy((char*) ptr, _this->GetParam(idx)->GetLabelForHost()); } return 0; } case effGetParamDisplay: { if (idx >= 0 && idx < _this->NParams()) { _this->GetParam(idx)->GetDisplayForHost((char*) ptr); } return 0; } case effGetParamName: { if (idx >= 0 && idx < _this->NParams()) { strcpy((char*) ptr, _this->GetParam(idx)->GetNameForHost()); } return 0; } //could implement effGetParameterProperties to group parameters, but can't find a host that supports it // case effGetParameterProperties: // { // if (idx >= 0 && idx < _this->NParams()) // { // VstParameterProperties* props = (VstParameterProperties*) ptr; // // props->flags = kVstParameterSupportsDisplayCategory; // props->category = idx+1; // props->numParametersInCategory = 1; // strcpy(props->categoryLabel, "test"); // } // return 1; // } case effGetParameterProperties: { if (idx >= 0 && idx < _this->NParams()) { VstParameterProperties* props = (VstParameterProperties*) ptr; props->flags = 0; IParam* pParam = _this->GetParam(idx); if (pParam->Type() == IParam::kTypeBool) { props->flags |= kVstParameterIsSwitch; } if (pParam->Type() == IParam::kTypeEnum || pParam->Type() == IParam::kTypeInt) { props->flags |= kVstParameterUsesFloatStep; int possibleValuesCount = (int) (pParam->GetMax() - pParam->GetMin()); props->stepFloat = 1.0 / possibleValuesCount; props->smallStepFloat = props->stepFloat; props->largeStepFloat = props->stepFloat; } } return 1; } case effString2Parameter: { if (idx >= 0 && idx < _this->NParams()) { if (ptr) { double v; IParam* pParam = _this->GetParam(idx); if (pParam->GetNDisplayTexts()) { int vi; if (!pParam->MapDisplayText((char*)ptr, &vi)) return 0; v = (double)vi; } else { v = atof((char*)ptr); if (pParam->DisplayIsNegated()) v = -v; } if (_this->GetGUI()) _this->GetGUI()->SetParameterFromPlug(idx, v, false); pParam->Set(v); _this->OnParamChange(idx); } return 1; } return 0; } case effSetSampleRate: { _this->SetSampleRate(opt); _this->Reset(); return 0; } case effSetBlockSize: { _this->SetBlockSize(value); _this->Reset(); return 0; } case effMainsChanged: { if (!value) { _this->OnActivate(false); _this->Reset(); } else { _this->OnActivate(true); } return 0; } case effEditGetRect: { if (ptr && _this->GetGUI()) { *(ERect**) ptr = &(_this->mEditRect); return 1; } ptr = 0; return 0; } case effEditOpen: { IGraphics* pGraphics = _this->GetGUI(); if (pGraphics) { #ifdef _WIN32 if (!pGraphics->OpenWindow(ptr)) pGraphics=0; #else // OSX, check if we are in a Cocoa VST host #if defined(__LP64__) if (!pGraphics->OpenWindow(ptr)) pGraphics=0; #else bool iscocoa = (_this->mHasVSTExtensions&VSTEXT_COCOA); if (iscocoa && !pGraphics->OpenWindow(ptr)) pGraphics=0; if (!iscocoa && !pGraphics->OpenWindow(ptr, 0)) pGraphics=0; #endif #endif if (pGraphics) { _this->OnGUIOpen(); return 1; } } return 0; } case effEditClose: { if (_this->GetGUI()) { _this->OnGUIClose(); _this->GetGUI()->CloseWindow(); return 1; } return 0; } case __effIdentifyDeprecated: { return 'NvEf'; // Random deprecated magic. } case effGetChunk: { BYTE** ppData = (BYTE**) ptr; if (ppData) { bool isBank = (!idx); ByteChunk* pChunk = (isBank ? &(_this->mBankState) : &(_this->mState)); _this->InitChunkWithIPlugVer(pChunk); bool savedOK = true; if (isBank) { _this->ModifyCurrentPreset(); savedOK = _this->SerializePresets(pChunk); } else { savedOK = _this->SerializeState(pChunk); } if (savedOK && pChunk->Size()) { *ppData = pChunk->GetBytes(); return pChunk->Size(); } } return 0; } case effSetChunk: { if (ptr) { bool isBank = (!idx); ByteChunk* pChunk = (isBank ? &(_this->mBankState) : &(_this->mState)); pChunk->Resize(value); memcpy(pChunk->GetBytes(), ptr, value); int pos = 0; int iplugVer = _this->GetIPlugVerFromChunk(pChunk, &pos); isBank &= (iplugVer >= 0x010000); if (isBank) { pos = _this->UnserializePresets(pChunk, pos); } else { pos = _this->UnserializeState(pChunk, pos); _this->ModifyCurrentPreset(); } if (pos >= 0) { _this->RedrawParamControls(); return 1; } } return 0; } case effProcessEvents: { VstEvents* pEvents = (VstEvents*) ptr; if (pEvents && pEvents->events) { for (int i = 0; i < pEvents->numEvents; ++i) { VstEvent* pEvent = pEvents->events[i]; if (pEvent) { if (pEvent->type == kVstMidiType) { VstMidiEvent* pME = (VstMidiEvent*) pEvent; IMidiMsg msg(pME->deltaFrames, pME->midiData[0], pME->midiData[1], pME->midiData[2]); _this->ProcessMidiMsg(&msg); //#ifdef TRACER_BUILD // msg.LogMsg(); //#endif } else if (pEvent->type == kVstSysExType) { VstMidiSysexEvent* pSE = (VstMidiSysexEvent*) pEvent; ISysEx sysex(pSE->deltaFrames, (const BYTE*)pSE->sysexDump, pSE->dumpBytes); _this->ProcessSysEx(&sysex); } } } return 1; } return 0; } case effCanBeAutomated: { return 1; } case effGetInputProperties: { if (ptr && idx >= 0 && idx < _this->NInChannels()) { VstPinProperties* pp = (VstPinProperties*) ptr; pp->flags = kVstPinIsActive; if (!(idx%2) && idx < _this->NInChannels()-1) { pp->flags |= kVstPinIsStereo; } if (_this->GetInputLabel(idx)->GetLength()) { sprintf(pp->label, "%s", _this->GetInputLabel(idx)->Get()); } else { sprintf(pp->label, "Input %d", idx + 1); } return 1; } return 0; } case effGetOutputProperties: { if (ptr && idx >= 0 && idx < _this->NOutChannels()) { VstPinProperties* pp = (VstPinProperties*) ptr; pp->flags = kVstPinIsActive; if (!(idx%2) && idx < _this->NOutChannels()-1) { pp->flags |= kVstPinIsStereo; } if (_this->GetOutputLabel(idx)->GetLength()) { sprintf(pp->label, "%s", _this->GetOutputLabel(idx)->Get()); } else { sprintf(pp->label, "Output %d", idx + 1); } return 1; } return 0; } case effGetPlugCategory: { if (_this->IsInst()) return kPlugCategSynth; return kPlugCategEffect; } case effProcessVarIo: { // VstVariableIo* pIO = (VstVariableIo*) ptr; // For offline processing (of audio files?) return 0; } case effSetSpeakerArrangement: { VstSpeakerArrangement* pInputArr = (VstSpeakerArrangement*) value; VstSpeakerArrangement* pOutputArr = (VstSpeakerArrangement*) ptr; if (pInputArr) { int n = pInputArr->numChannels; _this->SetInputChannelConnections(0, n, true); _this->SetInputChannelConnections(n, _this->NInChannels() - n, false); } if (pOutputArr) { int n = pOutputArr->numChannels; _this->SetOutputChannelConnections(0, n, true); _this->SetOutputChannelConnections(n, _this->NOutChannels() - n, false); } return 1; } case effGetSpeakerArrangement: { VstSpeakerArrangement** ppInputArr = (VstSpeakerArrangement**) value; VstSpeakerArrangement** ppOutputArr = (VstSpeakerArrangement**) ptr; if (ppInputArr) { *ppInputArr = &(_this->mInputSpkrArr); } if (ppOutputArr) { *ppOutputArr = &(_this->mOutputSpkrArr); } return 1; } case effGetEffectName: { if (ptr) { strcpy((char*) ptr, _this->GetEffectName()); return 1; } return 0; } case effGetProductString: { if (ptr) { strcpy((char*) ptr, _this->GetProductName()); return 1; } return 0; } case effGetVendorString: { if (ptr) { strcpy((char*) ptr, _this->GetMfrName()); return 1; } return 0; } case effCanDo: { if (ptr) { Trace(TRACELOC, "VSTCanDo(%s)", (char*) ptr); if (!strcmp((char*) ptr, "receiveVstTimeInfo")) { return 1; } if (_this->DoesMIDI()) { if (!strcmp((char*) ptr, "sendVstEvents") || !strcmp((char*) ptr, "sendVstMidiEvent") || !strcmp((char*) ptr, "receiveVstEvents") || !strcmp((char*) ptr, "receiveVstMidiEvent")) // || { //!strcmp((char*) ptr, "midiProgramNames")) { return 1; } } // Support Reaper VST extensions: http://www.reaper.fm/sdk/vst/ if (!strcmp((char*) ptr, "hasCockosExtensions")) { _this->mHasVSTExtensions |= VSTEXT_COCKOS; return 0xbeef0000; } else if (!strcmp((char*) ptr, "hasCockosViewAsConfig")) { _this->mHasVSTExtensions |= VSTEXT_COCOA; return 0xbeef0000; } } return 0; } case effGetTailSize: { return _this->GetTailSize(); } case effVendorSpecific: { // Support Reaper VST extensions: http://www.reaper.fm/sdk/vst/ if (idx == effGetParamDisplay && ptr) { if (value >= 0 && value < _this->NParams()) { _this->GetParam(value)->GetDisplayForHost((double) opt, true, (char*) ptr); } return 0xbeef; } if (idx == kVstParameterUsesIntStep) { if (value >= 0 && value < _this->NParams()) { if (_this->GetParam(value)->Type() != IParam::kTypeDouble) { return 0xbeef; } } } return 0; } case effGetProgram: { return _this->GetCurrentPresetIdx(); } case effSetProgram: { if (_this->DoesStateChunks() == false) { _this->ModifyCurrentPreset(); // TODO: test, something is funny about this http://forum.cockos.com/showpost.php?p=485113&postcount=22 } _this->RestorePreset((int) value); return 0; } case effGetProgramNameIndexed: { strcpy((char*) ptr, _this->GetPresetName(idx)); return (CSTR_NOT_EMPTY((char*) ptr) ? 1 : 0); } case effSetProgramName: { if (ptr) { _this->ModifyCurrentPreset((char*) ptr); _this->PresetsChangedByHost(); } return 0; } case effGetProgramName: { if (ptr) { int idx = _this->GetCurrentPresetIdx(); strcpy((char*) ptr, _this->GetPresetName(idx)); } return 0; } case effGetMidiKeyName: { if (ptr) { MidiKeyName* pMKN = (MidiKeyName*) ptr; pMKN->keyName[0] = '\0'; if (_this->MidiNoteName(pMKN->thisKeyNumber, pMKN->keyName)) { return 1; } } return 0; } case effGetVstVersion: { return VST_VERSION; } case effEndSetProgram: case effBeginSetProgram: case effGetMidiProgramName: case effHasMidiProgramsChanged: case effGetMidiProgramCategory: case effGetCurrentMidiProgram: case effSetBypass: default: { return 0; } } }
VstIntPtr VSTCALLBACK IPlugVST::VSTDispatcher(AEffect *pEffect, VstInt32 opCode, VstInt32 idx, VstIntPtr value, void *ptr, float opt) { // VSTDispatcher is an IPlugVST class member, we can access anything in IPlugVST from here. IPlugVST* _this = (IPlugVST*) pEffect->object; if (!_this) { return 0; } IPlugBase::IMutexLock lock(_this); // Handle a couple of opcodes here to make debugging easier. switch (opCode) { case effEditIdle: case __effIdleDeprecated: #ifdef USE_IDLE_CALLS _this->OnIdle(); #endif return 0; } Trace(TRACELOC, "%d(%s):%d:%d", opCode, VSTOpcodeStr(opCode), idx, (int) value); switch (opCode) { case effOpen: { _this->HostSpecificInit(); _this->OnParamReset(); return 0; } case effClose: { lock.Destroy(); DELETE_NULL(_this); return 0; } case effGetParamLabel: { if (idx >= 0 && idx < _this->NParams()) { strcpy((char*) ptr, _this->GetParam(idx)->GetLabelForHost()); } return 0; } case effGetParamDisplay: { if (idx >= 0 && idx < _this->NParams()) { _this->GetParam(idx)->GetDisplayForHost((char*) ptr); } return 0; } case effGetParamName: { if (idx >= 0 && idx < _this->NParams()) { strcpy((char*) ptr, _this->GetParam(idx)->GetNameForHost()); } return 0; } case effString2Parameter: { if (idx >= 0 && idx < _this->NParams()) { if (ptr) { IParam* pParam = _this->GetParam(idx); double v = VSTString2Parameter(pParam, (char*)ptr); if (_this->GetGUI()) _this->GetGUI()->SetParameterFromPlug(idx, v, false); pParam->Set(v); _this->OnParamChange(idx); } return 1; } return 0; } case effSetSampleRate: { _this->SetSampleRate(opt); _this->Reset(); return 0; } case effSetBlockSize: { _this->SetBlockSize(value); _this->Reset(); return 0; } case effMainsChanged: { if (!value) { _this->OnActivate(false); _this->Reset(); } else { _this->OnActivate(true); } return 0; } case effEditGetRect: { if (ptr && _this->GetGUI()) { *(ERect**) ptr = &(_this->mEditRect); return 1; } ptr = 0; return 0; } case effEditOpen: { IGraphics* pGraphics = _this->GetGUI(); if (pGraphics) { #if defined(_WIN32) || defined(IPLUG_NO_CARBON_SUPPORT) if (!pGraphics->OpenWindow(ptr)) pGraphics=0; #else // OSX, check if we are in a Cocoa VST host bool iscocoa = (_this->mHasVSTExtensions&VSTEXT_COCOA); if (iscocoa && !pGraphics->OpenWindow(ptr)) pGraphics=0; if (!iscocoa && !pGraphics->OpenWindow(ptr, 0)) pGraphics=0; #endif if (pGraphics) { _this->OnGUIOpen(); return 1; } } return 0; } case effEditClose: { if (_this->GetGUI()) { _this->OnGUIClose(); _this->GetGUI()->CloseWindow(); return 1; } return 0; } case __effIdentifyDeprecated: { return 'NvEf'; // Random deprecated magic. } case effGetChunk: { BYTE** ppData = (BYTE**) ptr; if (ppData) { bool isBank = (!idx); ByteChunk* pChunk = (isBank ? &(_this->mBankState) : &(_this->mState)); InitializeVSTChunk(pChunk); bool savedOK = true; if (isBank) { _this->ModifyCurrentPreset(); savedOK = _this->SerializePresets(pChunk); //savedOK = _this->SerializeState(pChunk); } else { savedOK = _this->SerializeState(pChunk); } if (savedOK && pChunk->Size()) { *ppData = pChunk->GetBytes(); return pChunk->Size(); } } return 0; } case effSetChunk: { if (ptr) { bool isBank = (!idx); ByteChunk* pChunk = (isBank ? &(_this->mBankState) : &(_this->mState)); pChunk->Resize(value); memcpy(pChunk->GetBytes(), ptr, value); int pos = 0; int iplugVer = GetIPlugVerFromChunk(pChunk, &pos); isBank &= (iplugVer >= 0x010000); if (isBank) { pos = _this->UnserializePresets(pChunk, pos); //pos = _this->UnserializeState(pChunk, pos); } else { pos = _this->UnserializeState(pChunk, pos); _this->ModifyCurrentPreset(); } if (pos >= 0) { _this->RedrawParamControls(); return 1; } } return 0; } case effProcessEvents: { VstEvents* pEvents = (VstEvents*) ptr; if (pEvents && pEvents->events) { for (int i = 0; i < pEvents->numEvents; ++i) { VstEvent* pEvent = pEvents->events[i]; if (pEvent) { if (pEvent->type == kVstMidiType) { VstMidiEvent* pME = (VstMidiEvent*) pEvent; IMidiMsg msg(pME->deltaFrames, pME->midiData[0], pME->midiData[1], pME->midiData[2]); _this->ProcessMidiMsg(&msg); //#ifdef TRACER_BUILD // msg.LogMsg(); //#endif } else if (pEvent->type == kVstSysExType) { VstMidiSysexEvent* pSE = (VstMidiSysexEvent*) pEvent; ISysEx sysex(pSE->deltaFrames, (const BYTE*)pSE->sysexDump, pSE->dumpBytes); _this->ProcessSysEx(&sysex); } } } return 1; } return 0; } case effCanBeAutomated: { return 1; } case effGetInputProperties: { if (ptr && idx >= 0 && idx < _this->NInChannels()) { VstPinProperties* pp = (VstPinProperties*) ptr; pp->flags = kVstPinIsActive; if (!(idx%2) && idx < _this->NInChannels()-1) { pp->flags |= kVstPinIsStereo; } sprintf(pp->label, "Input %d", idx + 1); return 1; } return 0; } case effGetOutputProperties: { if (ptr && idx >= 0 && idx < _this->NOutChannels()) { VstPinProperties* pp = (VstPinProperties*) ptr; pp->flags = kVstPinIsActive; if (!(idx%2) && idx < _this->NOutChannels()-1) { pp->flags |= kVstPinIsStereo; } sprintf(pp->label, "Output %d", idx + 1); return 1; } return 0; } case effGetPlugCategory: { if (_this->IsInst()) return kPlugCategSynth; return kPlugCategEffect; } case effProcessVarIo: { // VstVariableIo* pIO = (VstVariableIo*) ptr; // For offline processing (of audio files?) return 0; } case effSetSpeakerArrangement: { VstSpeakerArrangement* pInputArr = (VstSpeakerArrangement*) value; VstSpeakerArrangement* pOutputArr = (VstSpeakerArrangement*) ptr; if (pInputArr) { int n = pInputArr->numChannels; _this->SetInputChannelConnections(0, n, true); _this->SetInputChannelConnections(n, _this->NInChannels() - n, false); } if (pOutputArr) { int n = pOutputArr->numChannels; _this->SetOutputChannelConnections(0, n, true); _this->SetOutputChannelConnections(n, _this->NOutChannels() - n, false); } return 1; } case effGetSpeakerArrangement: { VstSpeakerArrangement** ppInputArr = (VstSpeakerArrangement**) value; VstSpeakerArrangement** ppOutputArr = (VstSpeakerArrangement**) ptr; if (ppInputArr) { *ppInputArr = &(_this->mInputSpkrArr); } if (ppOutputArr) { *ppOutputArr = &(_this->mOutputSpkrArr); } return 1; } case effGetEffectName: { if (ptr) { strcpy((char*) ptr, _this->GetEffectName()); return 1; } return 0; } case effGetProductString: { if (ptr) { strcpy((char*) ptr, _this->GetProductName()); return 1; } return 0; } case effGetVendorString: { if (ptr) { strcpy((char*) ptr, _this->GetMfrName()); return 1; } return 0; } case effGetVendorVersion: { return _this->GetEffectVersion(true); } case effCanDo: { if (ptr) { Trace(TRACELOC, "VSTCanDo(%s)", (char*) ptr); if (!strcmp((char*) ptr, "receiveVstTimeInfo")) { return 1; } if (_this->DoesMIDI()) { if (_this->DoesMIDI() & 1) { if (!strcmp((char*) ptr, "sendVstEvents") || !strcmp((char*) ptr, "sendVstMidiEvent")) { return 1; } } if (_this->DoesMIDI() <= 2) { if (!strcmp((char*) ptr, "receiveVstEvents") || !strcmp((char*) ptr, "receiveVstMidiEvent")) { return 1; } } //if (!strcmp((char*) ptr, "midiProgramNames")) { // return 1; //} } // Support Reaper VST extensions: http://www.reaper.fm/sdk/vst/ if (!strcmp((char*) ptr, "hasCockosExtensions")) { _this->mHasVSTExtensions |= VSTEXT_COCKOS; return 0xbeef0000; } else if (!strcmp((char*) ptr, "hasCockosViewAsConfig")) { _this->mHasVSTExtensions |= VSTEXT_COCOA; return 0xbeef0000; } } return 0; } case effVendorSpecific: { switch (idx) { // Mouse wheel case 0x73744341: { if (value == 0x57686565) { IGraphics* pGraphics = _this->GetGUI(); if (pGraphics) { return pGraphics->ProcessMouseWheel(opt); } } break; } // Support Reaper VST extensions: http://www.reaper.fm/sdk/vst/ case effGetParamDisplay: { if (ptr) { if (value >= 0 && value < _this->NParams()) { _this->GetParam(value)->GetDisplayForHost((double) opt, true, (char*) ptr); } return 0xbeef; } break; } case effString2Parameter: { if (ptr && value >= 0 && value < _this->NParams()) { if (*(char*) ptr != '\0') { IParam* pParam = _this->GetParam(value); sprintf((char*) ptr, "%.17f", pParam->GetNormalized(VSTString2Parameter(pParam, (char*) ptr))); } return 0xbeef; } break; } case kVstParameterUsesIntStep: { if (value >= 0 && value < _this->NParams()) { IParam* pParam = _this->GetParam(value); switch (pParam->Type()) { case IParam::kTypeBool: { return 0xbeef; } case IParam::kTypeInt: case IParam::kTypeEnum: { double min, max; pParam->GetBounds(&min, &max); if (fabs(max - min) < 1.5) { return 0xbeef; } break; } } } break; } } return 0; } case effGetProgram: { return _this->GetCurrentPresetIdx(); } case effSetProgram: { //if (!(_this->DoesStateChunks())) { _this->ModifyCurrentPreset(); //} _this->RestorePreset((int) value); return 0; } case effGetProgramNameIndexed: { strcpy((char*) ptr, _this->GetPresetName(idx)); return (CSTR_NOT_EMPTY((char*) ptr) ? 1 : 0); } case effSetProgramName: { if (ptr) { _this->ModifyCurrentPreset((char*) ptr); } return 0; } case effGetProgramName: { if (ptr) { int idx = _this->GetCurrentPresetIdx(); strcpy((char*) ptr, _this->GetPresetName(idx)); } return 0; } case effGetMidiKeyName: { if (ptr) { MidiKeyName* pMKN = (MidiKeyName*) ptr; pMKN->keyName[0] = '\0'; if (_this->MidiNoteName(pMKN->thisKeyNumber, pMKN->keyName)) { return 1; } } return 0; } case effGetVstVersion: { return VST_VERSION; } case effBeginSetProgram: case effEndSetProgram: case effGetMidiProgramName: case effHasMidiProgramsChanged: case effGetMidiProgramCategory: case effGetCurrentMidiProgram: case effSetBypass: default: { return 0; } } }
static int readtrack(void) /* read a track chunk */ { /* This array is indexed by the high half of a status byte. It's */ /* value is either the number of bytes needed (1 or 2) for a channel */ /* message, or 0 (meaning it's not a channel message). */ static int chantype[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */ 2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */ }; long lookfor; int c, c1, type; int sysexcontinue = 0; /* 1 if last message was an unfinished sysex */ int running = 0; /* 1 when running status used */ int status = 0; /* status value (e.g. 0x90==note-on) */ int needed; if (readmt("MTrk") == EOF) return(0); Mf_toberead = read32bit(); Mf_currtime = 0; if (Mf_starttrack) (*Mf_starttrack)(); while (Mf_toberead > 0) { Mf_currtime += readvarinum(); /* delta time */ c = egetc(); if (sysexcontinue && c != 0xf7) mferror("didn't find expected continuation of a sysex"); if ((c & 0x80) == 0) { /* running status? */ if (status == 0) mferror("unexpected running status"); running = 1; c1 = c; c = status; } else if (c < 0xf0) { status = c; running = 0; } needed = chantype[(c>>4) & 0xf]; if (needed) { /* ie. is it a channel message? */ if (! running) c1 = egetc(); chanmessage(status, c1, (needed>1) ? egetc() : 0); continue;; } switch (c) { case 0xff: /* meta event */ type = egetc(); lookfor = Mf_toberead - readvarinum(); msginit(); while (Mf_toberead > lookfor) msgadd(egetc()); metaevent(type); break; case 0xf0: /* start of system exclusive */ lookfor = Mf_toberead - readvarinum(); msginit(); msgadd(0xf0); while (Mf_toberead > lookfor) msgadd(c = egetc()); if (c == 0xf7 || Mf_nomerge == 0) sysex(); else sysexcontinue = 1; /* merge into next msg */ break; case 0xf7: /* sysex continuation or arbitrary stuff */ lookfor = Mf_toberead - readvarinum(); if (! sysexcontinue) msginit(); while (Mf_toberead > lookfor) msgadd(c=egetc()); if ( ! sysexcontinue ) { if (Mf_arbitrary) (*Mf_arbitrary)(msgleng(),msg()); } else if (c == 0xf7) { sysex(); sysexcontinue = 0; } break; default: badbyte(c); break; } } if (Mf_endtrack) (*Mf_endtrack)(); return(1); }
/* Read a MIDI event, returning a freshly allocated element that can be linked to the event list */ static MidiEventList *read_midi_event(struct md *d) { static uint8 laststatus, lastchan; static uint8 nrpn=0, rpn_msb[MAXCHAN], rpn_lsb[MAXCHAN]; /* one per channel */ uint8 me, type, a,b,c; int32 len, i; MidiEventList *newev; for (;;) { #ifdef tplus if ( (len=getvl(d)) < 0) return 0; d->at+= len; #else d->at+=getvl(d); #endif #ifdef tplus if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } me = (uint8)i; #else if (fread(&me,1,1,d->fp)!=1) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, sys_errlist[errno]); return 0; } #endif if(me==0xF0 || me == 0xF7) /* SysEx event */ { int32 sret; uint8 sysa=0, sysb=0, syschan=0; #ifdef tplus if ( (len=getvl(d)) < 0) return 0; #else len=getvl(d); #endif sret=sysex(len, &syschan, &sysa, &sysb, d); if (sret) { MIDIEVENT(d->at, sret, syschan, sysa, sysb); } } else if(me==0xFF) /* Meta event */ { #ifdef tplus if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } type = (uint8)i; #else fread(&type,1,1,d->fp); #endif #ifdef tplus if ( (len=getvl(d)) < 0) return 0; #else len=getvl(d); #endif if (type>0 && type<16) { static const char *label[]={ "text: ", "text: ", "Copyright: ", "track: ", "instrument: ", "lyric: ", "marker: ", "cue point: "}; dumpstring(len, label[(type>7) ? 0 : type], type, d); } else switch(type) { case 0x21: /* MIDI port number */ if(len == 1) { fread(&d->midi_port_number,1,1,d->fp); if(d->midi_port_number == EOF) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } d->midi_port_number &= 0x0f; if (d->midi_port_number) ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "(MIDI port number %d)", d->midi_port_number); d->midi_port_number &= 0x03; } else skip(d->fp, len); break; case 0x2F: /* End of Track */ return MAGIC_EOT; case 0x51: /* Tempo */ #ifdef tplus if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } a = (uint8)i; if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } b = (uint8)i; if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } c = (uint8)i; #else fread(&a,1,1,d->fp); fread(&b,1,1,d->fp); fread(&c,1,1,d->fp); #endif MIDIEVENT(d->at, ME_TEMPO, c, a, b); default: ctl->cmsg(CMSG_INFO, VERB_DEBUG, "(Meta event type 0x%02x, length %ld)", type, len); skip(d->fp, len); break; } } else { a=me; if (a & 0x80) /* status byte */ { lastchan = MERGE_CHANNEL_PORT(a & 0x0F); laststatus=(a>>4) & 0x07; #ifdef tplus if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } a = (uint8)i; #else fread(&a, 1,1, d->fp); #endif a &= 0x7F; } switch(laststatus) { case 0: /* Note off */ #ifdef tplus if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } b = (uint8)i; #else fread(&b, 1,1, d->fp); #endif b &= 0x7F; /*MIDIEVENT(d->at, ME_NOTEOFF, lastchan, a,b);*/ MIDIEVENT(d->at, ME_NOTEON, lastchan, a,0); case 1: /* Note on */ #ifdef tplus if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } b = (uint8)i; #else fread(&b, 1,1, d->fp); #endif b &= 0x7F; MIDIEVENT(d->at, ME_NOTEON, lastchan, a,b); if (d->curr_track == d->curr_title_track && d->track_info > 1) d->title[0] = '\0'; case 2: /* Key Pressure */ #ifdef tplus if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } b = (uint8)i; #else fread(&b, 1,1, d->fp); #endif b &= 0x7F; MIDIEVENT(d->at, ME_KEYPRESSURE, lastchan, a, b); case 3: /* Control change */ #ifdef tplus if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } b = (uint8)i; #else fread(&b, 1,1, d->fp); #endif b &= 0x7F; { int control=255; switch(a) { #ifdef tplus case 1: control=ME_MODULATION_WHEEL; break; case 5: control=ME_PORTAMENTO_TIME_MSB; break; case 37: control=ME_PORTAMENTO_TIME_LSB; break; case 65: control=ME_PORTAMENTO; break; #endif case 7: control=ME_MAINVOLUME; break; case 10: control=ME_PAN; break; case 11: control=ME_EXPRESSION; break; #ifdef tplus case 64: control=ME_SUSTAIN; b = (b >= 64); break; #else case 64: control=ME_SUSTAIN; break; #endif case 71: control=ME_HARMONICCONTENT; break; case 72: control=ME_RELEASETIME; break; case 73: control=ME_ATTACKTIME; break; case 74: control=ME_BRIGHTNESS; break; case 91: control=ME_REVERBERATION; break; case 93: control=ME_CHORUSDEPTH; break; #ifdef CHANNEL_EFFECT case 94: control=ME_CELESTE; break; ctl->cmsg(CMSG_INFO, VERB_NORMAL, "CELESTE"); case 95: control=ME_PHASER; break; ctl->cmsg(CMSG_INFO, VERB_NORMAL, "PHASER"); #endif case 120: control=ME_ALL_SOUNDS_OFF; break; case 121: control=ME_RESET_CONTROLLERS; break; case 123: control=ME_ALL_NOTES_OFF; break; /* These should be the SCC-1 tone bank switch commands. I don't know why there are two, or why the latter only allows switching to bank 0. Also, some MIDI files use 0 as some sort of continuous controller. This will cause lots of warnings about undefined tone banks. */ case 0: if (d->XG_System_On) control=ME_TONE_KIT; else control=ME_TONE_BANK; break; case 32: if (d->XG_System_On) control=ME_TONE_BANK; break; case 100: nrpn=0; rpn_msb[lastchan]=b; break; case 101: nrpn=0; rpn_lsb[lastchan]=b; break; case 98: nrpn=1; rpn_lsb[lastchan]=b; break; case 99: nrpn=1; rpn_msb[lastchan]=b; break; case 6: if (nrpn) { if (rpn_msb[lastchan]==1) switch (rpn_lsb[lastchan]) { #ifdef tplus case 0x08: control=ME_VIBRATO_RATE; break; case 0x09: control=ME_VIBRATO_DEPTH; break; case 0x0a: control=ME_VIBRATO_DELAY; break; #endif case 0x20: control=ME_BRIGHTNESS; break; case 0x21: control=ME_HARMONICCONTENT; break; /* case 0x63: envelope attack rate case 0x64: envelope decay rate case 0x66: envelope release rate */ } else switch (rpn_msb[lastchan]) { /* case 0x14: filter cutoff frequency case 0x15: filter resonance case 0x16: envelope attack rate case 0x17: envelope decay rate case 0x18: pitch coarse case 0x19: pitch fine */ case 0x1a: d->drumvolume[lastchan][0x7f & rpn_lsb[lastchan]] = b; break; case 0x1c: if (!b) b=(int) (127.0*rand()/(RAND_MAX)); d->drumpanpot[lastchan][0x7f & rpn_lsb[lastchan]] = b; break; case 0x1d: d->drumreverberation[lastchan][0x7f & rpn_lsb[lastchan]] = b; break; case 0x1e: d->drumchorusdepth[lastchan][0x7f & rpn_lsb[lastchan]] = b; break; /* case 0x1f: variation send level */ } ctl->cmsg(CMSG_INFO, VERB_DEBUG, "(Data entry (MSB) for NRPN %02x,%02x: %ld)", rpn_msb[lastchan], rpn_lsb[lastchan], b); break; } switch((rpn_msb[lastchan]<<8) | rpn_lsb[lastchan]) { case 0x0000: /* Pitch bend sensitivity */ control=ME_PITCH_SENS; break; #ifdef tplus case 0x0001: control=ME_FINE_TUNING; break; case 0x0002: control=ME_COARSE_TUNING; break; #endif case 0x7F7F: /* RPN reset */ /* reset pitch bend sensitivity to 2 */ MIDIEVENT(d->at, ME_PITCH_SENS, lastchan, 2, 0); default: ctl->cmsg(CMSG_INFO, VERB_DEBUG, "(Data entry (MSB) for RPN %02x,%02x: %ld)", rpn_msb[lastchan], rpn_lsb[lastchan], b); break; } break; default: ctl->cmsg(CMSG_INFO, VERB_DEBUG, "(Control %d: %d)", a, b); break; } if (control != 255) { MIDIEVENT(d->at, control, lastchan, b, 0); } } break; case 4: /* Program change */ a &= 0x7f; MIDIEVENT(d->at, ME_PROGRAM, lastchan, a, 0); #ifdef tplus case 5: /* Channel pressure */ MIDIEVENT(d->at, ME_CHANNEL_PRESSURE, lastchan, a, 0); #else case 5: /* Channel pressure - NOT IMPLEMENTED */ break; #endif case 6: /* Pitch wheel */ #ifdef tplus if((i = tf_getc(d)) == EOF) { if(errno) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "\"%s\": read_midi_event: %s", d->midi_name, strerror(errno)); else ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Warning: \"%s\": Short midi file.", d->midi_name); return 0; } b = (uint8)i; #else fread(&b, 1,1, d->fp); #endif b &= 0x7F; MIDIEVENT(d->at, ME_PITCHWHEEL, lastchan, a, b); case 7: break; default: ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "*** Can't happen: status 0x%02X, channel 0x%02X", laststatus, lastchan); break; } } }