//------------------------------------------------------------------------------------------------------- void AudioEffect::DECLARE_VST_DEPRECATED (hasClip) (bool state) { if (state) cEffect.flags |= DECLARE_VST_DEPRECATED (effFlagsHasClip); else cEffect.flags &= ~DECLARE_VST_DEPRECATED (effFlagsHasClip); }
//------------------------------------------------------------------------------------------------------- bool AudioEffect::DECLARE_VST_DEPRECATED (isOutputConnected) (VstInt32 output) { VstInt32 ret = 0; if (audioMaster) ret = (VstInt32)audioMaster (&cEffect, DECLARE_VST_DEPRECATED (audioMasterPinConnected), output, 1, 0, 0); return ret ? false : true; // return value is 0 for true }
//------------------------------------------------------------------------------------------------------- void AudioEffect::DECLARE_VST_DEPRECATED (canMono) (bool state) { if (state) cEffect.flags |= DECLARE_VST_DEPRECATED (effFlagsCanMono); else cEffect.flags &= ~DECLARE_VST_DEPRECATED (effFlagsCanMono); }
TimedFader::TimedFader(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, 1, 3) { //inits here! fOutput = 1.0f; faderSteps = 15; currentFaderFrameCount = 1; setNumInputs(2); setNumOutputs(2); setUniqueID('tFd1'); // identify here DECLARE_VST_DEPRECATED(canMono) (); canProcessReplacing(); strcpy(programName, "Timed Fader 1"); setParameter(PARAM_PlayDuration, 30.0f); // 10 seconds //0.166667); //~30 seconds setParameter(PARAM_FadeDuration, 3.0f); // 3 seconds fPlaySecondsRemaining = fPlayDuration; fFadeSecondsRemaining = fFadeDuration; state = STATE_DONE; muteGain = (float)pow(10.0f, 0.05f * -60.0f); muteGain *= 0.01f; fSecondsPerFrame = 1 / sampleRate; // Create the editor faderDisplay = new FaderDisplay(this); editor = faderDisplay; suspend(); // flush buffer }
mdaLimiter::mdaLimiter(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, 1, 5) // 1 program, 4 parameters { fParam1 = (float)0.60; //thresh fParam2 = (float)0.60; //trim fParam3 = (float)0.15; //attack fParam4 = (float)0.50; //release fParam5 = (float)0.40; //knee setNumInputs(2); // stereo in setNumOutputs(2); // stereo out setUniqueID('mdaL'); // identify DECLARE_VST_DEPRECATED(canMono) (); canProcessReplacing(); // supports both accumulating and replacing output strcpy(programName, "Limiter"); // default program name if(fParam5>0.5) //soft knee { thresh = (float)pow(10.0, 1.0 - (2.0 * fParam1)); } else //hard knee { thresh = (float)pow(10.0, (2.0 * fParam1) - 2.0); } trim = (float)(pow(10.0, (2.0 * fParam2) - 1.0)); att = (float)pow(10.0, -0.01 - 2.0 * fParam3);//wavelab overruns with zero??? rel = (float)pow(10.0, -2.0 - (3.0 * fParam4)); gain = 1.0; }
/*! The constructor of your class is passed a parameter of the type \e audioMasterCallback. The actual mechanism in which your class gets constructed is not important right now. Effectively your class is constructed by the hosting application, which passes an object of type \e audioMasterCallback that handles the interaction with the plug-in. You pass this on to the base class' constructor and then can forget about it. \param audioMaster Passed by the Host and handles interaction \param numPrograms Pass the number of programs the plug-in provides \param numParams Pass the number of parameters the plug-in provides \code MyPlug::MyPlug (audioMasterCallback audioMaster) : AudioEffectX (audioMaster, 1, 1) // 1 program, 1 parameter only { setNumInputs (2); // stereo in setNumOutputs (2); // stereo out setUniqueID ('MyPl'); // you must change this for other plug-ins! canProcessReplacing (); // supports replacing mode } \endcode \sa setNumInputs, setNumOutputs, setUniqueID, canProcessReplacing */ AudioEffect::AudioEffect (audioMasterCallback audioMaster, VstInt32 numPrograms, VstInt32 numParams) : audioMaster (audioMaster) , editor (0) , sampleRate (44100.f) , blockSize (1024) , numPrograms (numPrograms) , numParams (numParams) , curProgram (0) { memset (&cEffect, 0, sizeof (cEffect)); cEffect.magic = kEffectMagic; cEffect.dispatcher = dispatchEffectClass; cEffect.DECLARE_VST_DEPRECATED (process) = DECLARE_VST_DEPRECATED (processClass); cEffect.setParameter = setParameterClass; cEffect.getParameter = getParameterClass; cEffect.numPrograms = numPrograms; cEffect.numParams = numParams; cEffect.numInputs = 1; // mono input cEffect.numOutputs = 2; // stereo output cEffect.DECLARE_VST_DEPRECATED (ioRatio) = 1.f; cEffect.object = this; cEffect.uniqueID = CCONST ('N', 'o', 'E', 'f'); cEffect.version = 1; cEffect.processReplacing = processClassReplacing; #if VST_2_4_EXTENSIONS canProcessReplacing (); // mandatory in VST 2.4! cEffect.processDoubleReplacing = processClassDoubleReplacing; #endif }
mdaDetune::mdaDetune(audioMasterCallback audioMaster): AudioEffectX(audioMaster, NPROGS, NPARAMS) { setNumInputs(2); setNumOutputs(2); setUniqueID('mdat'); ///identify mdaDetune-in here DECLARE_VST_DEPRECATED(canMono) (); canProcessReplacing(); programs[0].param[0] = 0.20f; //fine programs[0].param[1] = 0.90f; //mix programs[0].param[2] = 0.50f; //output programs[0].param[3] = 0.50f; //chunksize strcpy(programs[0].name, "Stereo Detune"); programs[1].param[0] = 0.20f; programs[1].param[1] = 0.90f; programs[1].param[2] = 0.50f; programs[1].param[3] = 0.50f; strcpy(programs[1].name,"Symphonic"); programs[2].param[0] = 0.8f; programs[2].param[1] = 0.7f; programs[2].param[2] = 0.50f; programs[2].param[3] = 0.50f; strcpy(programs[2].name,"Out Of Tune"); ///initialise... curProgram=0; suspend(); semi = 3.0f * 0.20f * 0.20f * 0.20f; dpos2 = (float)pow(1.0594631f, semi); dpos1 = 1.0f / dpos2; wet = 1.0f; dry = wet - wet * 0.90f * 0.90f; wet = (wet + wet - wet * 0.90f) * 0.90f; }
void mdaLooplex::resume() { //should reset position here... bufpos = 0; //needIdle(); //idle broken in VST2.4 DECLARE_VST_DEPRECATED (wantEvents) (); }
static VstIntPtr VSTCALLBACK audioMaster( AEffect * effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void * ptr, float opt) { audioMasterData * data = NULL; if ( effect ) data = ( audioMasterData * ) effect->user; switch (opcode) { case audioMasterVersion: return 2400; case audioMasterCurrentId: if ( data ) return data->effect_number; break; case audioMasterGetVendorString: strncpy((char *)ptr, "NoWork, Inc.", 64); //strncpy((char *)ptr, "YAMAHA", 64); break; case audioMasterGetProductString: strncpy((char *)ptr, "VSTi Host Bridge", 64); //strncpy((char *)ptr, "SOL/SQ01", 64); break; case audioMasterGetVendorVersion: return 1000; case audioMasterGetLanguage: return kVstLangEnglish; case audioMasterVendorSpecific: /* Steinberg HACK */ if ( ptr ) { uint32_t * blah = ( uint32_t * ) ( ( ( char * ) ptr ) - 4 ); if ( *blah == 0x0737bb68 ) { *blah ^= 0x5CC8F349; blah[2] = 0x19E; return 0x1E7; } } break; case audioMasterGetDirectory: return (VstIntPtr) dll_dir; /* More crap */ case DECLARE_VST_DEPRECATED(audioMasterNeedIdle): need_idle = true; return 0; } return 0; }
mdaLoudness::mdaLoudness(audioMasterCallback audioMaster): AudioEffectX(audioMaster, NPROGS, NPARAMS) { setNumInputs(2); setNumOutputs(2); setUniqueID('mdal'); DECLARE_VST_DEPRECATED(canMono) (); canProcessReplacing(); programs = new mdaLoudnessProgram[NPROGS]; setProgram(0); suspend(); }
mdaOverdrive::mdaOverdrive(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, 1, 3) // 1 program, 3 parameters { fParam1 = 0.0f; fParam2 = 0.0f; fParam3 = 0.5f; setNumInputs(2); setNumOutputs(2); setUniqueID('mdaO'); // identify DECLARE_VST_DEPRECATED(canMono) (); canProcessReplacing(); strcpy(programName, "Soft Overdrive"); filt1 = filt2 = 0.0f; setParameter(0, 0.0f); }
//------------------------------------------------------------------------------------------------------- VstIntPtr AudioEffect::dispatcher (VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt) { VstIntPtr v = 0; switch (opcode) { case effOpen: open (); break; case effClose: close (); break; case effSetProgram: if (value < numPrograms) setProgram ((VstInt32)value); break; case effGetProgram: v = getProgram (); break; case effSetProgramName: setProgramName ((char*)ptr); break; case effGetProgramName: getProgramName ((char*)ptr); break; case effGetParamLabel: getParameterLabel (index, (char*)ptr); break; case effGetParamDisplay: getParameterDisplay (index, (char*)ptr); break; case effGetParamName: getParameterName (index, (char*)ptr); break; case effSetSampleRate: setSampleRate (opt); break; case effSetBlockSize: setBlockSize ((VstInt32)value); break; case effMainsChanged: if (!value) suspend (); else resume (); break; #if !VST_FORCE_DEPRECATED case effGetVu: v = (VstIntPtr)(getVu () * 32767.); break; #endif //---Editor------------ case effEditGetRect: if (editor) v = editor->getRect ((ERect**)ptr) ? 1 : 0; break; case effEditOpen: if (editor) v = editor->open (ptr) ? 1 : 0; break; case effEditClose: if (editor) editor->close (); break; case effEditIdle: if (editor) editor->idle (); break; #if (TARGET_API_MAC_CARBON && !VST_FORCE_DEPRECATED) case effEditDraw: if (editor) editor->draw ((ERect*)ptr); break; case effEditMouse: if (editor) v = editor->mouse (index, value); break; case effEditKey: if (editor) v = editor->key (value); break; case effEditTop: if (editor) editor->top (); break; case effEditSleep: if (editor) editor->sleep (); break; #endif case DECLARE_VST_DEPRECATED (effIdentify): v = CCONST ('N', 'v', 'E', 'f'); break; //---Persistence------- case effGetChunk: v = getChunk ((void**)ptr, index ? true : false); break; case effSetChunk: v = setChunk (ptr, (VstInt32)value, index ? true : false); break; } return v; }
mdaImage::mdaImage(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, 1, 6) // programs, parameters { fParam1 = 0.6f; //mode fParam2 = 0.75f; //width fParam3 = 0.5f; //skew fParam4 = 0.75f; //centre fParam5 = 0.5f; //balance fParam6 = 0.5f; //output setNumInputs(2); setNumOutputs(2); setUniqueID('mdaI'); // identify here DECLARE_VST_DEPRECATED(canMono) (); canProcessReplacing(); strcpy(programName, "Stereo Image / MS Matrix"); setParameter(0, 0.6f); //go and set initial values! }
mdaSplitter::mdaSplitter(audioMasterCallback audioMaster): AudioEffectX(audioMaster, NPROGS, NPARAMS) { setNumInputs(2); setNumOutputs(2); setUniqueID('mda7'); ///identify plug-in here DECLARE_VST_DEPRECATED(canMono) (); canProcessReplacing(); env = buf0 = buf1 = buf2 = buf3 = 0.0f; ///differences from default program... programs[1].param[2] = 0.50f; programs[1].param[4] = 0.25f; strcpy(programs[1].name,"Pass Peaks Only"); programs[2].param[0] = 0.60f; strcpy(programs[2].name,"Stereo Crossover"); setProgram(0); }
wolfBoostComp::wolfBoostComp(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, 1, 6) // programs, parameters { //inits here! fParam1 = (float) 0.25f; // Drive fParam2 = (float) 0.25f; // Threshold fParam3 = (float) 0.25f; // Gain fParam4 = (float) 0.50f; // Linearity fParam5 = (float) 0.50f; // Asymmetry fParam6 = (float) 1.00f; // Wet setNumInputs(2); setNumOutputs(2); setUniqueID('wlBC'); // identify here DECLARE_VST_DEPRECATED(canMono) (); canProcessReplacing(); strcpy(programName, "Boost-Compressor Fx"); adj1 = 1.f; adj2 = 1.f; adj3 = 1.f; adj4 = 0.f; adj5 = 0.f; asymKonst = boostcomp(adj5, adj1, adj2, adj3, adj4, fParam6); }
VstIntPtr PluginHost::gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt) { /* warning: VST headers compiled with DECLARE_VST_DEPRECATED. */ switch (opcode) { /* 0 - Called after a control has changed in the editor and when * the associated parameter should be automated. Index contains the * param, opt the value. Thanks, but we don't need it now. It will * be useful when recording actions from VST (in the future). */ case audioMasterAutomate: return 0; /* 1 - host version (2.4) */ case audioMasterVersion: return kVstVersion; /* 3 - Give idle time to Host application, e.g. if plug-in editor is * doing mouse tracking in a modal loop. This a is multithread app, * we don't need it. */ case audioMasterIdle: return 0; /* 6 - tells the host that the plugin is an instrument. Deprecated. */ case DECLARE_VST_DEPRECATED(audioMasterWantMidi): return 0; /* 7 - time infos */ case audioMasterGetTime: vstTimeInfo.samplePos = G_Mixer.actualFrame; vstTimeInfo.sampleRate = G_Conf.samplerate; vstTimeInfo.tempo = G_Mixer.bpm; vstTimeInfo.timeSigNumerator = G_Mixer.beats; vstTimeInfo.timeSigDenominator = G_Mixer.bars; vstTimeInfo.ppqPos = (G_Mixer.actualFrame / (float) G_Conf.samplerate) * (float) G_Mixer.bpm / 60.0f; return (VstIntPtr) &vstTimeInfo; /* ? - requires a pointer to VstEvents. No vstEvents so far (v0.5.4) */ case audioMasterProcessEvents: return 0; /* 13 - tells that numInputs/numOutputs are changed. Not supported and * not needed. */ case audioMasterIOChanged: return false; /* 14 - plugin needs idle calls (outside its editor window). Deprecated */ case DECLARE_VST_DEPRECATED(audioMasterNeedIdle): return 0; /* 15 - requests to resize the editor window. w = index, h = value*/ case audioMasterSizeWindow: { gWindow *window = NULL; for (unsigned i=0; i<masterOut.size && !window; i++) if (masterOut.at(i)->getPlugin() == effect) window = masterOut.at(i)->window; for (unsigned i=0; i<masterIn.size && !window; i++) if (masterIn.at(i)->getPlugin() == effect) window = masterIn.at(i)->window; for (unsigned i=0; i<G_Mixer.channels.size && !window; i++) { Channel *ch = G_Mixer.channels.at(i); for (unsigned j=0; j<ch->plugins.size && !window; j++) if (ch->plugins.at(j)->getPlugin() == effect) window = ch->plugins.at(j)->window; } if (window) { gLog("[pluginHost] audioMasterSizeWindow: resizing window from plugin %p\n", (void*) effect); if (index == 1 || value == 1) gLog("[pluginHost] warning: non-sense values!\n"); else window->size((int)index, (int)value); return 1; } else { gLog("[pluginHost] audioMasterSizeWindow: window from plugin %p not found\n", (void*) effect); return 0; } } /* 16 - sample rate */ case audioMasterGetSampleRate: return G_Conf.samplerate; /* ?? - buffer size */ case audioMasterGetBlockSize: return kernelAudio::realBufsize; case audioMasterGetInputLatency: gLog("[pluginHost] requested opcode 'audioMasterGetInputLatency' (%d)\n", opcode); return 0; case audioMasterGetOutputLatency: gLog("[pluginHost] requested opcode 'audioMasterGetOutputLatency' (%d)\n", opcode); return 0; /* 23 - wants to know what kind of process is that. * kVstProcessLevelRealtime = currently in audio thread (where * process is called). */ case audioMasterGetCurrentProcessLevel: return kVstProcessLevelRealtime; /* 32 - vendor name */ case audioMasterGetVendorString: strcpy((char*)ptr, "Monocasual"); return 1; /* 32 - product name */ case audioMasterGetProductString: strcpy((char*)ptr, "Giada"); return 1; /* 33 - product version */ case audioMasterGetVendorVersion: return (int) VERSIONE_FLOAT * 100; /* 37 - Plugin asks Host if it implements the feature text. */ case audioMasterCanDo: gLog("[pluginHost] audioMasterCanDo: %s\n", (char*)ptr); if (!strcmp((char*)ptr, "sizeWindow") || !strcmp((char*)ptr, "sendVstTimeInfo") || !strcmp((char*)ptr, "sendVstMidiEvent") || !strcmp((char*)ptr, "sendVstMidiEventFlagIsRealtime")) return 1; // we can do all of that else return 0; /* 42 - Something has changed, update the host's 'multi-fx' display. * Not supported right now, return 0. This opcode deals with the program * changes, more infos http://www.asseca.com/vst-24-specs/amUpdateDisplay.html */ case audioMasterUpdateDisplay: return 0; case audioMasterGetLanguage: return kVstLangEnglish; /* ?? */ case audioMasterGetAutomationState: gLog("[pluginHost] requested opcode 'audioMasterGetAutomationState' (%d)\n", opcode); return 0; /* 43 - It tells the Host that if it needs to, it has to record * automation data for this control. In other words this opcode is fired * when the user starts to tweak a parameter with the mouse. * Useful when the plugin actions will be recorded. */ case audioMasterBeginEdit: return 0; /* 44 - no more interaction for the user, started with the previous * opcode. */ case audioMasterEndEdit: return 0; default: gLog("[pluginHost] FIXME: host callback called with opcode %d\n", opcode); return 0; } }
int CALLBACK _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) { int argc = 0; LPWSTR * argv = CommandLineToArgvW( GetCommandLineW(), &argc ); if ( argv == NULL || argc != 3 ) return 1; wchar_t * end_char = 0; unsigned in_sum = wcstoul( argv[ 2 ], &end_char, 16 ); if ( end_char == argv[ 2 ] || *end_char ) return 2; unsigned test_sum = 0; end_char = argv[ 1 ]; while ( *end_char ) { test_sum += (TCHAR)( *end_char++ * 820109 ); } #ifdef NDEBUG if ( test_sum != in_sum ) return 3; #endif unsigned code = 0; HMODULE hDll = NULL; main_func pMain = NULL; AEffect * pEffect[3] = {0, 0, 0}; audioMasterData effectData[3] = { { 0 }, { 1 }, { 2 } }; std::vector<uint8_t> blState; uint32_t max_num_outputs = 2; uint32_t sample_rate = 44100; std::vector<uint8_t> chunk; std::vector<float> sample_buffer; null_file = CreateFile( _T("NUL"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); pipe_in = GetStdHandle( STD_INPUT_HANDLE ); pipe_out = GetStdHandle( STD_OUTPUT_HANDLE ); SetStdHandle( STD_INPUT_HANDLE, null_file ); SetStdHandle( STD_OUTPUT_HANDLE, null_file ); { INITCOMMONCONTROLSEX icc; icc.dwSize = sizeof(icc); icc.dwICC = ICC_WIN95_CLASSES | ICC_COOL_CLASSES | ICC_STANDARD_CLASSES; if ( !InitCommonControlsEx( &icc ) ) return 4; } if ( FAILED( CoInitialize( NULL ) ) ) return 5; #ifndef _DEBUG SetUnhandledExceptionFilter( myExceptFilterProc ); #endif size_t dll_name_len = wcslen( argv[ 1 ] ); dll_dir = ( char * ) malloc( dll_name_len + 1 ); wcstombs( dll_dir, argv[ 1 ], dll_name_len ); dll_dir[ dll_name_len ] = '\0'; char * slash = strrchr( dll_dir, '\\' ); *slash = '\0'; hDll = LoadLibraryW( argv[ 1 ] ); if ( !hDll ) { code = 6; goto exit; } pMain = (main_func) GetProcAddress( hDll, "main" ); if ( !pMain ) { code = 7; goto exit; } #if 0 MessageBox( GetDesktopWindow(), argv[ 1 ], _T("HUUUURRRRRR"), 0 ); #endif pEffect[ 0 ] = pMain( &audioMaster ); if ( !pEffect[ 0 ] || pEffect[ 0 ]->magic != kEffectMagic ) { code = 8; goto exit; } pEffect[ 0 ]->user = &effectData[ 0 ]; pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effOpen, 0, 0, 0, 0 ); if ( pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effGetPlugCategory, 0, 0, 0, 0 ) != kPlugCategSynth || pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effCanDo, 0, 0, "sendVstMidiEvent", 0 ) == 0 ) { code = 9; goto exit; } max_num_outputs = min( pEffect[ 0 ]->numOutputs, 2 ); { char name_string[256] = { 0 }; char vendor_string[256] = { 0 }; char product_string[256] = { 0 }; uint32_t name_string_length; uint32_t vendor_string_length; uint32_t product_string_length; uint32_t vendor_version; uint32_t unique_id; pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effGetEffectName, 0, 0, &name_string, 0 ); pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effGetVendorString, 0, 0, &vendor_string, 0 ); pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effGetProductString, 0, 0, &product_string, 0 ); name_string_length = strlen( name_string ); vendor_string_length = strlen( vendor_string ); product_string_length = strlen( product_string ); vendor_version = pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effGetVendorVersion, 0, 0, 0, 0 ); unique_id = pEffect[ 0 ]->uniqueID; put_code( 0 ); put_code( name_string_length ); put_code( vendor_string_length ); put_code( product_string_length ); put_code( vendor_version ); put_code( unique_id ); put_code( max_num_outputs ); if ( name_string_length ) put_bytes( name_string, name_string_length ); if ( vendor_string_length ) put_bytes( vendor_string, vendor_string_length ); if ( product_string_length ) put_bytes( product_string, product_string_length ); } float ** float_list_in; float ** float_list_out; float * float_null; float * float_out; for (;;) { uint32_t command = get_code(); if ( !command ) break; switch ( command ) { case 1: // Get Chunk getChunk( pEffect[ 0 ], chunk ); put_code( 0 ); put_code( chunk.size() ); put_bytes( chunk.data(), chunk.size() ); break; case 2: // Set Chunk { uint32_t size = get_code(); chunk.resize( size ); if ( size ) get_bytes( chunk.data(), size ); setChunk( pEffect[ 0 ], chunk ); setChunk( pEffect[ 1 ], chunk ); setChunk( pEffect[ 2 ], chunk ); put_code( 0 ); } break; case 3: // Has Editor { uint32_t has_editor = ( pEffect[ 0 ]->flags & effFlagsHasEditor ) ? 1 : 0; put_code( 0 ); put_code( has_editor ); } break; case 4: // Display Editor Modal { if ( pEffect[ 0 ]->flags & effFlagsHasEditor ) { MyDLGTEMPLATE t; t.style = WS_POPUPWINDOW | WS_DLGFRAME | DS_MODALFRAME | DS_CENTER; DialogBoxIndirectParam ( 0, &t, GetDesktopWindow(), (DLGPROC)EditorProc, (LPARAM)( pEffect[ 0 ] ) ); getChunk( pEffect[ 0 ], chunk ); setChunk( pEffect[ 1 ], chunk ); setChunk( pEffect[ 2 ], chunk ); } put_code( 0 ); } break; case 5: // Set Sample Rate { uint32_t size = get_code(); if ( size != sizeof(sample_rate) ) { code = 10; goto exit; } sample_rate = get_code(); put_code( 0 ); } break; case 6: // Reset { if ( pEffect[ 2 ] ) { if ( blState.size() ) pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effStopProcess, 0, 0, 0, 0 ); pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effClose, 0, 0, 0, 0 ); pEffect[ 2 ] = NULL; } if ( pEffect[ 1 ] ) { if ( blState.size() ) pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effStopProcess, 0, 0, 0, 0 ); pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effClose, 0, 0, 0, 0 ); pEffect[ 1 ] = NULL; } if ( blState.size() ) pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effStopProcess, 0, 0, 0, 0 ); pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effClose, 0, 0, 0, 0 ); blState.resize( 0 ); freeChain(); pEffect[ 0 ] = pMain( &audioMaster ); if ( !pEffect[ 0 ] ) { code = 8; goto exit; } pEffect[ 0 ]->user = &effectData[ 0 ]; pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effOpen, 0, 0, 0, 0 ); setChunk( pEffect[ 0 ], chunk ); put_code( 0 ); } break; case 7: // Send MIDI Event { myVstEvent * ev = ( myVstEvent * ) calloc( sizeof( myVstEvent ), 1 ); if ( evTail ) evTail->next = ev; evTail = ev; if ( !evChain ) evChain = ev; uint32_t b = get_code(); ev->port = (b & 0x7F000000) >> 24; if (ev->port > 2) ev->port = 2; ev->ev.midiEvent.type = kVstMidiType; ev->ev.midiEvent.byteSize = sizeof(ev->ev.midiEvent); memcpy(&ev->ev.midiEvent.midiData, &b, 3); put_code( 0 ); } break; case 8: // Send System Exclusive Event { myVstEvent * ev = ( myVstEvent * ) calloc( sizeof( myVstEvent ), 1 ); if ( evTail ) evTail->next = ev; evTail = ev; if ( !evChain ) evChain = ev; uint32_t size = get_code(); uint32_t port = size >> 24; size &= 0xFFFFFF; ev->port = port; if (ev->port > 2) ev->port = 2; ev->ev.sysexEvent.type = kVstSysExType; ev->ev.sysexEvent.byteSize = sizeof(ev->ev.sysexEvent); ev->ev.sysexEvent.dumpBytes = size; ev->ev.sysexEvent.sysexDump = (char*) malloc( size ); get_bytes( ev->ev.sysexEvent.sysexDump, size ); put_code( 0 ); } break; case 9: // Render Samples { if ( !pEffect[ 1 ] ) { pEffect[ 1 ] = pMain( &audioMaster ); if ( !pEffect[ 1 ] ) { code = 11; goto exit; } pEffect[ 1 ]->user = &effectData[ 1 ]; pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effOpen, 0, 0, 0, 0 ); setChunk( pEffect[ 1 ], chunk ); } if ( !pEffect[ 2 ] ) { pEffect[ 2 ] = pMain( &audioMaster ); if ( !pEffect[ 2 ] ) { code = 11; goto exit; } pEffect[ 2 ]->user = &effectData[ 2 ]; pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effOpen, 0, 0, 0, 0 ); setChunk( pEffect[ 2 ], chunk ); } if ( !blState.size() ) { pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effSetSampleRate, 0, 0, 0, float(sample_rate) ); pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effSetBlockSize, 0, BUFFER_SIZE, 0, 0 ); pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effMainsChanged, 0, 1, 0, 0 ); pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effStartProcess, 0, 0, 0, 0 ); pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effSetSampleRate, 0, 0, 0, float(sample_rate) ); pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effSetBlockSize, 0, BUFFER_SIZE, 0, 0 ); pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effMainsChanged, 0, 1, 0, 0 ); pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effStartProcess, 0, 0, 0, 0 ); pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effSetSampleRate, 0, 0, 0, float(sample_rate) ); pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effSetBlockSize, 0, BUFFER_SIZE, 0, 0 ); pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effMainsChanged, 0, 1, 0, 0 ); pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effStartProcess, 0, 0, 0, 0 ); size_t buffer_size = sizeof(float*) * ( pEffect[ 0 ]->numInputs + pEffect[ 0 ]->numOutputs * 3 ); // float lists buffer_size += sizeof(float) * BUFFER_SIZE; // null input buffer_size += sizeof(float) * BUFFER_SIZE * pEffect[ 0 ]->numOutputs * 3; // outputs blState.resize( buffer_size ); float_list_in = (float**) blState.data(); float_list_out = float_list_in + pEffect[ 0 ]->numInputs; float_null = (float*) ( float_list_out + pEffect[ 0 ]->numOutputs * 3 ); float_out = float_null + BUFFER_SIZE; for ( unsigned i = 0; i < pEffect[ 0 ]->numInputs; ++i ) float_list_in [ i ] = float_null; for ( unsigned i = 0; i < pEffect[ 0 ]->numOutputs * 3; ++i ) float_list_out[ i ] = float_out + BUFFER_SIZE * i; memset( float_null, 0, sizeof(float) * BUFFER_SIZE ); sample_buffer.resize( BUFFER_SIZE * max_num_outputs ); } if ( need_idle ) { pEffect[ 0 ]->dispatcher( pEffect[ 0 ], DECLARE_VST_DEPRECATED (effIdle), 0, 0, 0, 0 ); pEffect[ 1 ]->dispatcher( pEffect[ 1 ], DECLARE_VST_DEPRECATED (effIdle), 0, 0, 0, 0 ); pEffect[ 2 ]->dispatcher( pEffect[ 2 ], DECLARE_VST_DEPRECATED (effIdle), 0, 0, 0, 0 ); if ( !idle_started ) { unsigned idle_run = BUFFER_SIZE * 128; while ( idle_run ) { unsigned count_to_do = min( idle_run, BUFFER_SIZE ); unsigned num_outputs = pEffect[ 0 ]->numOutputs; pEffect[ 0 ]->processReplacing( pEffect[ 0 ], float_list_in, float_list_out, count_to_do ); pEffect[ 1 ]->processReplacing( pEffect[ 1 ], float_list_in, float_list_out + num_outputs, count_to_do ); pEffect[ 2 ]->processReplacing( pEffect[ 2 ], float_list_in, float_list_out + num_outputs * 2, count_to_do ); pEffect[ 0 ]->dispatcher( pEffect[ 0 ], DECLARE_VST_DEPRECATED (effIdle), 0, 0, 0, 0 ); pEffect[ 1 ]->dispatcher( pEffect[ 1 ], DECLARE_VST_DEPRECATED (effIdle), 0, 0, 0, 0 ); pEffect[ 2 ]->dispatcher( pEffect[ 2 ], DECLARE_VST_DEPRECATED (effIdle), 0, 0, 0, 0 ); idle_run -= count_to_do; } } } VstEvents * events[ 3 ] = {0}; if ( evChain ) { unsigned event_count[ 3 ] = {0}; myVstEvent * ev = evChain; while ( ev ) { event_count[ ev->port ]++; ev = ev->next; } if ( event_count[ 0 ] ) { events[ 0 ] = ( VstEvents * ) malloc( sizeof(long) + sizeof(long) + sizeof(VstEvent*) * event_count[ 0 ] ); events[ 0 ]->numEvents = event_count[ 0 ]; events[ 0 ]->reserved = 0; ev = evChain; for ( unsigned i = 0; ev; ) { if ( !ev->port ) events[ 0 ]->events[ i++ ] = (VstEvent*) &ev->ev; ev = ev->next; } pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effProcessEvents, 0, 0, events[ 0 ], 0 ); } if ( event_count[ 1 ] ) { events[ 1 ] = ( VstEvents * ) malloc( sizeof(long) + sizeof(long) + sizeof(VstEvent*) * event_count[ 1 ] ); events[ 1 ]->numEvents = event_count[ 1 ]; events[ 1 ]->reserved = 0; ev = evChain; for ( unsigned i = 0; ev; ) { if ( ev->port == 1 ) events[ 1 ]->events[ i++ ] = (VstEvent*) &ev->ev; ev = ev->next; } pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effProcessEvents, 0, 0, events[ 1 ], 0 ); } if ( event_count[ 2 ] ) { events[ 2 ] = ( VstEvents * ) malloc( sizeof(long) + sizeof(long) + sizeof(VstEvent*) * event_count[ 2 ] ); events[ 2 ]->numEvents = event_count[ 2 ]; events[ 2 ]->reserved = 0; ev = evChain; for ( unsigned i = 0; ev; ) { if ( ev->port == 2 ) events[ 2 ]->events[ i++ ] = (VstEvent*) &ev->ev; ev = ev->next; } pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effProcessEvents, 0, 0, events[ 2 ], 0 ); } } if ( need_idle ) { pEffect[ 0 ]->dispatcher( pEffect[ 0 ], DECLARE_VST_DEPRECATED (effIdle), 0, 0, 0, 0 ); pEffect[ 1 ]->dispatcher( pEffect[ 1 ], DECLARE_VST_DEPRECATED (effIdle), 0, 0, 0, 0 ); pEffect[ 2 ]->dispatcher( pEffect[ 2 ], DECLARE_VST_DEPRECATED (effIdle), 0, 0, 0, 0 ); if ( !idle_started ) { if ( events[ 0 ] ) pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effProcessEvents, 0, 0, events[ 0 ], 0 ); if ( events[ 1 ] ) pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effProcessEvents, 0, 0, events[ 1 ], 0 ); if ( events[ 2 ] ) pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effProcessEvents, 0, 0, events[ 2 ], 0 ); idle_started = true; } } uint32_t count = get_code(); put_code( 0 ); while( count ) { unsigned count_to_do = min( count, BUFFER_SIZE ); unsigned num_outputs = pEffect[ 0 ]->numOutputs; pEffect[ 0 ]->processReplacing( pEffect[ 0 ], float_list_in, float_list_out, count_to_do ); pEffect[ 1 ]->processReplacing( pEffect[ 1 ], float_list_in, float_list_out + num_outputs, count_to_do ); pEffect[ 2 ]->processReplacing( pEffect[ 2 ], float_list_in, float_list_out + num_outputs * 2, count_to_do ); float * out = sample_buffer.data(); if ( max_num_outputs == 2 ) { for ( unsigned i = 0; i < count_to_do; ++i ) { float sample = ( float_out[ i ] + float_out[ i + BUFFER_SIZE * num_outputs ] + float_out[ i + BUFFER_SIZE * num_outputs * 2 ] ); out[ 0 ] = sample; sample = ( float_out[ i + BUFFER_SIZE ] + float_out[ i + BUFFER_SIZE + BUFFER_SIZE * num_outputs ] + float_out[ i + BUFFER_SIZE + BUFFER_SIZE * num_outputs * 2 ] ); out[ 1 ] = sample; out += 2; } } else { for ( unsigned i = 0; i < count_to_do; ++i ) { float sample = ( float_out[ i ] + float_out[ i + BUFFER_SIZE * num_outputs ] + float_out[ i + BUFFER_SIZE * num_outputs * 2 ] ); out[ 0 ] = sample; out++; } } put_bytes( sample_buffer.data(), sizeof(float) * count_to_do * max_num_outputs ); count -= count_to_do; } if ( events[ 0 ] ) free( events[ 0 ] ); if ( events[ 1 ] ) free( events[ 1 ] ); if ( events[ 2 ] ) free( events[ 2 ] ); freeChain(); } break; default: code = 12; goto exit; break; } } exit: if ( pEffect[ 2 ] ) { if ( blState.size() ) pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effStopProcess, 0, 0, 0, 0 ); pEffect[ 2 ]->dispatcher( pEffect[ 2 ], effClose, 0, 0, 0, 0 ); } if ( pEffect[ 1 ] ) { if ( blState.size() ) pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effStopProcess, 0, 0, 0, 0 ); pEffect[ 1 ]->dispatcher( pEffect[ 1 ], effClose, 0, 0, 0, 0 ); } if ( pEffect[ 0 ] ) { if ( blState.size() ) pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effStopProcess, 0, 0, 0, 0 ); pEffect[ 0 ]->dispatcher( pEffect[ 0 ], effClose, 0, 0, 0, 0 ); } freeChain(); if ( hDll ) FreeLibrary( hDll ); CoUninitialize(); if ( argv ) LocalFree( argv ); put_code( code ); if ( null_file ) { CloseHandle( null_file ); SetStdHandle( STD_INPUT_HANDLE, pipe_in ); SetStdHandle( STD_OUTPUT_HANDLE, pipe_out ); } return code; }
VstIntPtr hostCallback(AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt) { Q_UNUSED(effect); Q_UNUSED(opt); //qDebug() << "hostCallback in thread" << QThread::currentThreadId(); VstIntPtr result = 0; // Filter idle calls... bool filtered = false; if (opcode == audioMasterIdle) { static bool wasIdle = false; if (wasIdle) filtered = true; else { //printf ("(Future idle calls will not be displayed!)\n"); wasIdle = true; } } //qDebug("audioMasterGetCurrentProcessLevel is %d", audioMasterGetCurrentProcessLevel); if (!filtered) //qDebug("PLUG> HostCallback (opcode %d)\n index = %d, value = %p, ptr = %p, opt = %f", opcode, index, FromVstPtr<void> (value), ptr, opt); switch (opcode) { case audioMasterVersion: result = kVstVersion; break; case DECLARE_VST_DEPRECATED (audioMasterPinConnected): //qDebug() << "pin connected"; break; case DECLARE_VST_DEPRECATED (audioMasterWantMidi): break; case audioMasterGetTime: result = (VstIntPtr)&s_vstTimeInfo; break; case audioMasterGetCurrentProcessLevel: result = kVstProcessLevelUser; break; case audioMasterCanDo: { QString canDoQuery((char*)ptr); QMap<QString, int> canDos; canDos["sendVstEvents"] = 1; canDos["sendVstMidiEvent"] = 1; canDos["sendVstTimeInfo"] = 1; canDos["sizeWindow"] = 1; QMap<QString, int>::iterator it = canDos.find(canDoQuery); if (it == canDos.end()) { result = 0; // don't know qDebug() << "unknown audioMasterCanDo:" << canDoQuery; } else { result = *it; } break; } case audioMasterSizeWindow: { // TODO: handle this! int width = index; int height = value; qDebug() << "SIZE WINDOW" << width << height; break; } default: //qDebug() << "UNHANDLED HOST OPCODE" << opcode; //Q_ASSERT(false); break; } return result; }