From 27da08004c5f024a0f35e3cb4c2b3942548ebcfa Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Fri, 11 Mar 2005 04:58:01 +0000 Subject: restructured VSThost code better shell support fix for build system update for flext build systemcleanups VSTTime info added event processing (like Midi in) svn path=/trunk/; revision=2617 --- externals/grill/vst/src/vstmaster.cpp | 288 ++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 externals/grill/vst/src/vstmaster.cpp (limited to 'externals/grill/vst/src/vstmaster.cpp') diff --git a/externals/grill/vst/src/vstmaster.cpp b/externals/grill/vst/src/vstmaster.cpp new file mode 100644 index 00000000..0395fb65 --- /dev/null +++ b/externals/grill/vst/src/vstmaster.cpp @@ -0,0 +1,288 @@ +/* +vst~ - VST plugin object for PD +based on the work of Jarno Seppänen and Mark Williamson + +Copyright (c)2003-2005 Thomas Grill (gr@grrrr.org) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. +*/ + +#include "vsthost.h" + +static const int VST_VERSION = 100; +static const char *vendor = "grrrr.org"; +static const char *product = "vst~"; + + +void VSTPlugin::ProcessEvent(const VstEvent &ev) +{ + if(!responder) return; + + if(ev.type == kVstMidiType) { + const VstMidiEvent &mev = (const VstMidiEvent &)ev; + t_atom lst[10]; + SetSymbol(lst[0],sym_evmidi); + int midi = ((unsigned char)mev.midiData[0]>>4)-8; + FLEXT_ASSERT(midi >= 0 && midi < 8); + SetSymbol(lst[1],sym_midi[midi]); + SetInt(lst[2],(unsigned char)mev.midiData[0]&0x0f); + SetInt(lst[3],(unsigned char)mev.midiData[1]); + SetInt(lst[4],(unsigned char)mev.midiData[2]); + // what about running status? (obviously not possible) + SetInt(lst[5],mev.deltaFrames); + SetInt(lst[6],mev.noteLength); + SetInt(lst[7],mev.noteOffset); + SetInt(lst[8],(int)mev.detune); + SetInt(lst[9],(int)mev.noteOffVelocity); + responder->Respond(sym_event,9,lst); + } + else { + const t_symbol *sym; + if(ev.type == kVstAudioType) + sym = sym_evaudio; + else if(ev.type == kVstVideoType) + sym = sym_evvideo; + else if(ev.type == kVstParameterType) + sym = sym_evparam; + else if(ev.type == kVstTriggerType) + sym = sym_evtrigger; + else if(ev.type == kVstSysExType) + sym = sym_evsysex; + else + sym = sym_ev_; + + int data = ev.byteSize-sizeof(ev.deltaFrames)-sizeof(ev.flags); + const int stsize = 16; + t_atom stlst[stsize]; + t_atom *lst = data+3 > stsize?new t_atom[data+3]:stlst; + + SetSymbol(lst[0],sym); + SetInt(lst[1],ev.deltaFrames); + SetInt(lst[2],ev.flags); + for(int i = 0; i < data; ++i) SetInt(lst[3],(unsigned char)ev.data[i]); + + responder->Respond(sym_event,data+3,lst); + + if(lst != stlst) delete[] lst; + } +} + +// Host callback dispatcher +long VSTPlugin::Master(AEffect *effect, long opcode, long index, long value, void *ptr, float opt) +{ +#ifdef FLEXT_LOGGING + post("VST -> host: Eff = 0x%.8X, Opcode = %d, Index = %d, Value = %d, PTR = %.8X, OPT = %.3f\n",(int)effect, opcode,index,value,(int)ptr,opt); +#endif + + VSTPlugin *th = effect?(VSTPlugin *)effect->user:NULL; + + switch (opcode) { + case audioMasterAutomate: // 0 +#ifdef FLEXT_LOGGING + post("Automate index=%li value=%li opt=%f",index,value,opt); +#endif + // index, value given + //! \todo set effect parameter + return 0; + + case audioMasterVersion: // 1 + // support VST 2.3 + return 2300; + + case audioMasterCurrentId: // 2 + // set to subplugin id (default 0) + return uniqueid; + + case audioMasterIdle: // 3 + effect->dispatcher(effect, effEditIdle, 0, 0, NULL, 0.0f); + return 0; + + case audioMasterPinConnected: // 4 + //! \todo set connection state correctly (if possible..) + // index=pin, value=0..input, else..output +#ifdef FLEXT_LOGGING + post("Pin connected pin=%li conn=%li",index,value); +#endif + return 0; // 0 means connected + + case audioMasterWantMidi: // 6 +#ifdef FLEXT_LOGGING + post("Want MIDI = %li",value); +#endif + return 0; // VST header says: "currently ignored" + + case audioMasterGetTime: { // 7 + if(!th) return 0; + + static VstTimeInfo time; + memset(&time,0,sizeof(time)); + + // flags + time.flags = kVstTempoValid|kVstBarsValid|kVstCyclePosValid|kVstPpqPosValid|kVstSmpteValid|kVstTimeSigValid; + + if(th->transchg) { time.flags |= kVstTransportChanged; th->transchg = false; } + if(th->playing) time.flags |= kVstTransportPlaying; + if(th->looping) time.flags |= kVstTransportCycleActive; + + time.sampleRate = th->samplerate; + time.samplePos = th->samplepos; + time.ppqPos = th->ppqpos; + + time.tempo = th->tempo; + time.barStartPos = th->barstartpos; + time.cycleStartPos = th->cyclestartpos; + time.cycleEndPos = th->cycleendpos; + + time.timeSigNumerator = th->timesignom; + time.timeSigDenominator = th->timesigden; + + // SMPTE data + time.smpteOffset = th->smpteoffset; + time.smpteFrameRate = th->smpterate; + +// time.samplesToNextClock = 0; + + if(value&kVstNanosValid) { + time.nanoSeconds = flext::GetOSTime()*1.e9; + time.flags |= kVstNanosValid; + } + + return (long)&time; + } + + case audioMasterProcessEvents: { // 8 + // VST event data from plugin + VstEvents *evs = static_cast(ptr); + if(th) { + for(int i = 0; i < evs->numEvents; ++i) + th->ProcessEvent(*evs->events[i]); + return 1; + } + else + return 0; + } + + case audioMasterSetTime: { // 9 + VstTimeInfo *tminfo = static_cast(ptr); +#ifdef FLEXT_DEBUG + post("TimeInfo pos=%lf rate=%lf filter=%li",tminfo->samplePos,tminfo->sampleRate,value); +#endif + return 0; // not supported + } + + case audioMasterTempoAt: // 10 + return 0; // not supported + + case audioMasterGetNumAutomatableParameters: // 11 + return 0; // not supported + + case audioMasterSizeWindow: // 15 + return 0; + + case audioMasterGetSampleRate: // 16 + return 0; // not supported + case audioMasterGetBlockSize: // 17 + return 0; // not supported + + case audioMasterGetCurrentProcessLevel: // 23 + // return thread state + return flext::GetThreadId() == flext::GetSysThreadId()?2:1; + + case audioMasterGetVendorString: // 32 + strcpy((char*)ptr,vendor); + return 0; + + case audioMasterGetProductString: // 33 + strcpy((char *)ptr,product); + return 0; + + case audioMasterGetVendorVersion: // 34 + return VST_VERSION; + + case audioMasterCanDo: // 37 +#ifdef FLEXT_LOGGING + post("\taudioMasterCanDo PTR = %s",ptr); +#endif + if(!strcmp((char *)ptr,"sendVstEvents")) + return 1; + else if(!strcmp((char *)ptr,"sendVstMidiEvent")) + return 1; + else if(!strcmp((char *)ptr,"sendVstTimeInfo")) + return 1; // NOT YET + else if(!strcmp((char *)ptr,"receiveVstEvents")) + return 1; + else if(!strcmp((char *)ptr,"receiveVstMidiEvent")) + return 1; + else if(!strcmp((char *)ptr,"receiveVstTimeInfo")) + return 1; // NOT YET + else if(!strcmp((char *)ptr,"reportConnectionChanges")) + return 0; // \TODO PD has hard times supporting that... + else if(!strcmp((char *)ptr,"acceptIOChanges")) + return 0; // \TODO what does this means exactly? + else if(!strcmp((char *)ptr,"supplyIdle")) + return 1; + else if(!strcmp((char *)ptr,"sizeWindow")) + return 1; + else if(!strcmp((char *)ptr,"supportShell")) + return 0; // deprecated - new one is shellCategory + else if(!strcmp((char *)ptr,"offline")) + return 0; // not supported + else if(!strcmp((char *)ptr,"asyncProcessing")) + return 0; // not supported + else if(!strcmp((char *)ptr,"shellCategory")) + return 1; // supported! + else if(!strcmp((char *)ptr,"editFile")) + return 0; // not supported + else if(!strcmp((char *)ptr,"openFileSelector")) + return 0; // not supported + else if(!strcmp((char *)ptr,"closeFileSelector")) + return 0; // not supported + else if(!strcmp((char *)ptr,"startStopProcess")) + return 0; // not supported +#ifdef FLEXT_DEBUG + else + post("Unknown audioMasterCanDo PTR = %s",ptr); +#endif + + return 0; // not supported + + case audioMasterGetLanguage: // 38 + return kVstLangEnglish; + + case audioMasterGetDirectory: // 41 + return (long)(th?th->dllname.c_str():dllloading.c_str()); + + case audioMasterUpdateDisplay: // 42 +#ifdef FLEXT_LOGGING + post("UPDATE DISPLAY"); +#endif + return 0; + + default: +#ifdef FLEXT_DEBUG + post("Unknown opcode %li",opcode); +#endif + return 0; + } +} + +void VSTPlugin::updatepos(long frames) +{ + bool inloop = ppqpos < cycleendpos; + + // \todo should the sample position also jump back when cycling? + // and if, how? + samplepos += frames; + + ppqpos += frames*tempo/(samplerate*60); + + if(looping) { + double cyclelen = cycleendpos-cyclestartpos; + if(cyclelen > 0) { + if(inloop && ppqpos >= cycleendpos) + ppqpos = cyclestartpos+fmod(ppqpos-cyclestartpos,cyclelen); + } + else + ppqpos = cyclestartpos; + } +} -- cgit v1.2.1