static int _testNewPluginVst2xIdWithNullStringId(void) { PluginVst2xId id = newPluginVst2xIdWithStringId(NULL); assertUnsignedLongEquals(ZERO_UNSIGNED_LONG, id->id); assertCharStringEquals(PLUGIN_VST2X_ID_UNKNOWN, id->idString); freePluginVst2xId(id); return 0; }
static int _testNewPluginVst2xIdWithZeroIntId(void) { PluginVst2xId id = newPluginVst2xIdWithId(0); assertUnsignedLongEquals(ZERO_UNSIGNED_LONG, id->id); assertCharStringEquals(EMPTY_STRING, id->idString); freePluginVst2xId(id); return 0; }
static int _testNewPluginVst2xIdWithIntId(void) { PluginVst2xId id = newPluginVst2xIdWithId(0x61626364); assertUnsignedLongEquals(0x61626364l, id->id); assertCharStringEquals("abcd", id->idString); freePluginVst2xId(id); return 0; }
static int _testNewPluginVst2xIdWithInvalidStringId(void) { CharString c = newCharStringWithCString("a"); PluginVst2xId id = newPluginVst2xIdWithStringId(c); assertUnsignedLongEquals(ZERO_UNSIGNED_LONG, id->id); assertCharStringEquals(PLUGIN_VST2X_ID_UNKNOWN, id->idString); freePluginVst2xId(id); freeCharString(c); return 0; }
static int _testNewPluginVst2xIdWithEmptyStringId(void) { CharString empty = newCharStringWithCString(EMPTY_STRING); PluginVst2xId id = newPluginVst2xIdWithStringId(empty); assertUnsignedLongEquals(ZERO_UNSIGNED_LONG, id->id); assertCharStringEquals(PLUGIN_VST2X_ID_UNKNOWN, id->idString); freePluginVst2xId(id); freeCharString(empty); return 0; }
static int _testNewPluginVst2xIdWithStringId(void) { CharString c = newCharStringWithCString("abcd"); PluginVst2xId id = newPluginVst2xIdWithStringId(c); assertUnsignedLongEquals(0x61626364l, id->id); assertCharStringEquals(c->data, id->idString); freePluginVst2xId(id); freeCharString(c); return 0; }
VstIntPtr VSTCALLBACK pluginVst2xHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *dataPtr, float opt) { // This string is used in a bunch of logging calls below PluginVst2xId pluginId; if(effect != NULL) { pluginId = newPluginVst2xIdWithId(effect->uniqueID); } else { // During plugin initialization, the dispatcher can be called without a // valid plugin instance, as the AEffect* struct is still not fully constructed // at that point. pluginId = newPluginVst2xId(); } const char* pluginIdString = pluginId->idString->data; VstIntPtr result = 0; logDebug("Plugin '%s' called host dispatcher with %d, %d, %d", pluginIdString, opcode, index, value); switch(opcode) { case audioMasterAutomate: // The plugin will call this if a parameter has changed via MIDI or the GUI, so the host can update // itself accordingly. We don't care about this (for the time being), and as we don't support either // GUI's or live MIDI, this opcode can be ignored. break; case audioMasterVersion: // We are a VST 2.4 compatible host result = 2400; break; case audioMasterCurrentId: // Use the current plugin ID, needed by VST shell plugins to determine which sub-plugin to load result = currentPluginUniqueId; break; case audioMasterIdle: // Ignore result = 1; break; case audioMasterPinConnected: logDeprecated("audioMasterPinConnected", pluginIdString); break; case audioMasterWantMidi: // This (deprecated) call is sometimes made by VST2.3 instruments to tell // the host that it is an instrument. We can safely ignore it. result = 1; break; case audioMasterGetTime: { AudioClock audioClock = getAudioClock(); // These values are always valid vstTimeInfo.samplePos = audioClock->currentFrame; vstTimeInfo.sampleRate = getSampleRate(); // Set flags for transport state vstTimeInfo.flags = 0; vstTimeInfo.flags |= audioClock->transportChanged ? kVstTransportChanged : 0; vstTimeInfo.flags |= audioClock->isPlaying ? kVstTransportPlaying : 0; // Fill values based on other flags which may have been requested if(value & kVstNanosValid) { // It doesn't make sense to return this value, as the plugin may try to calculate // something based on the current system time. As we are running offline, anything // the plugin calculates here will probably be wrong given the way we are running. // However, for realtime mode, this flag should be implemented in that case. logWarn("Plugin '%s' asked for time in nanoseconds (unsupported)", pluginIdString); } if(value & kVstPpqPosValid) { // TODO: Move calculations to AudioClock double samplesPerBeat = (60.0 / getTempo()) * getSampleRate(); // Musical time starts with 1, not 0 vstTimeInfo.ppqPos = (vstTimeInfo.samplePos / samplesPerBeat) + 1.0; logDebug("Current PPQ position is %g", vstTimeInfo.ppqPos); vstTimeInfo.flags |= kVstPpqPosValid; } if(value & kVstTempoValid) { vstTimeInfo.tempo = getTempo(); vstTimeInfo.flags |= kVstTempoValid; } if(value & kVstBarsValid) { if(!(value & kVstPpqPosValid)) { logError("Plugin requested position in bars, but not PPQ"); } // TODO: Move calculations to AudioClock double currentBarPos = floor(vstTimeInfo.ppqPos / (double)getTimeSignatureBeatsPerMeasure()); vstTimeInfo.barStartPos = currentBarPos * (double)getTimeSignatureBeatsPerMeasure() + 1.0; logDebug("Current bar is %g", vstTimeInfo.barStartPos); vstTimeInfo.flags |= kVstBarsValid; } if(value & kVstCyclePosValid) { // We don't support cycling, so this is always 0 } if(value & kVstTimeSigValid) { vstTimeInfo.timeSigNumerator = getTimeSignatureBeatsPerMeasure(); vstTimeInfo.timeSigDenominator = getTimeSignatureNoteValue(); vstTimeInfo.flags |= kVstTimeSigValid; } if(value & kVstSmpteValid) { logUnsupportedFeature("Current time in SMPTE format"); } if(value & kVstClockValid) { logUnsupportedFeature("Sample frames until next clock"); } result = (VstIntPtr)&vstTimeInfo; break; } case audioMasterProcessEvents: logUnsupportedFeature("VST master opcode audioMasterProcessEvents"); break; case audioMasterSetTime: logDeprecated("audioMasterSetTime", pluginIdString); break; case audioMasterTempoAt: logDeprecated("audioMasterTempoAt", pluginIdString); break; case audioMasterGetNumAutomatableParameters: logDeprecated("audioMasterGetNumAutomatableParameters", pluginIdString); break; case audioMasterGetParameterQuantization: logDeprecated("audioMasterGetParameterQuantization", pluginIdString); break; case audioMasterIOChanged: { PluginChain pluginChain = getPluginChain(); logDebug("Number of inputs: %d", effect->numInputs); logDebug("Number of outputs: %d", effect->numOutputs); logDebug("Number of parameters: %d", effect->numParams); logDebug("Initial Delay: %d", effect->initialDelay); result = -1; for(unsigned int i = 0; i < pluginChain->numPlugins; ++i){ if((unsigned long)effect->uniqueID == pluginVst2xGetUniqueId(pluginChain->plugins[i])){ logDebug("Updating plugin"); pluginVst2xAudioMasterIOChanged(pluginChain->plugins[i], effect); result = 0; break;//Only one plugin will match anyway. } } break; } case audioMasterNeedIdle: logDeprecated("audioMasterNeedIdle", pluginIdString); break; case audioMasterSizeWindow: logWarn("Plugin '%s' asked us to resize window (unsupported)", pluginIdString); break; case audioMasterGetSampleRate: result = (int)getSampleRate(); break; case audioMasterGetBlockSize: result = getBlocksize(); break; case audioMasterGetInputLatency: // Input latency is not used, and is always 0 result = 0; break; case audioMasterGetOutputLatency: // Output latency is not used, and is always 0 result = 0; break; case audioMasterGetPreviousPlug: logDeprecated("audioMasterGetPreviousPlug", pluginIdString); break; case audioMasterGetNextPlug: logDeprecated("audioMasterGetNextPlug", pluginIdString); break; case audioMasterWillReplaceOrAccumulate: logDeprecated("audioMasterWillReplaceOrAccumulate", pluginIdString); break; case audioMasterGetCurrentProcessLevel: // We are not a multithreaded app and have no GUI, so this is unsupported. result = kVstProcessLevelUnknown; break; case audioMasterGetAutomationState: // Automation is also not supported (for now) result = kVstAutomationUnsupported; break; case audioMasterOfflineStart: logWarn("Plugin '%s' asked us to start offline processing (unsupported)", pluginIdString); break; case audioMasterOfflineRead: logWarn("Plugin '%s' asked to read offline data (unsupported)", pluginIdString); break; case audioMasterOfflineWrite: logWarn("Plugin '%s' asked to write offline data (unsupported)", pluginIdString); break; case audioMasterOfflineGetCurrentPass: logWarn("Plugin '%s' asked for current offline pass (unsupported)", pluginIdString); break; case audioMasterOfflineGetCurrentMetaPass: logWarn("Plugin '%s' asked for current offline meta pass (unsupported)", pluginIdString); break; case audioMasterSetOutputSampleRate: logDeprecated("audioMasterSetOutputSampleRate", pluginIdString); break; case audioMasterGetOutputSpeakerArrangement: logDeprecated("audioMasterGetOutputSpeakerArrangement", pluginIdString); break; case audioMasterGetVendorString: strncpy((char*)dataPtr, VENDOR_NAME, kVstMaxVendorStrLen); result = 1; break; case audioMasterGetProductString: strncpy((char*)dataPtr, PROGRAM_NAME, kVstMaxProductStrLen); result = 1; break; case audioMasterGetVendorVersion: // Return our version as a single string, in the form ABCC, which corresponds to version A.B.C // Often times the patch can reach double-digits, so it gets two decimal places. result = VERSION_MAJOR * 1000 + VERSION_MINOR * 100 + VERSION_PATCH; break; case audioMasterVendorSpecific: logWarn("Plugin '%s' made a vendor specific call (unsupported). Arguments: %d, %d, %f", pluginIdString, index, value, opt); break; case audioMasterCanDo: result = _canHostDo(pluginIdString, (char*)dataPtr); break; case audioMasterSetIcon: logDeprecated("audioMasterSetIcon", pluginIdString); break; case audioMasterGetLanguage: result = kVstLangEnglish; break; case audioMasterOpenWindow: logDeprecated("audioMasterOpenWindow", pluginIdString); break; case audioMasterCloseWindow: logDeprecated("audioMasterCloseWindow", pluginIdString); break; case audioMasterGetDirectory: logWarn("Plugin '%s' asked for directory pointer (unsupported)", pluginIdString); break; case audioMasterUpdateDisplay: // Ignore break; case audioMasterBeginEdit: logWarn("Plugin '%s' asked to begin parameter automation (unsupported)", pluginIdString); break; case audioMasterEndEdit: logWarn("Plugin '%s' asked to end parameter automation (unsupported)", pluginIdString); break; case audioMasterOpenFileSelector: logWarn("Plugin '%s' asked us to open file selector (unsupported)", pluginIdString); break; case audioMasterCloseFileSelector: logWarn("Plugin '%s' asked us to close file selector (unsupported)", pluginIdString); break; case audioMasterEditFile: logDeprecated("audioMasterEditFile", pluginIdString); break; case audioMasterGetChunkFile: logDeprecated("audioMasterGetChunkFile", pluginIdString); break; case audioMasterGetInputSpeakerArrangement: logDeprecated("audioMasterGetInputSpeakerArrangement", pluginIdString); break; default: logWarn("Plugin '%s' asked if host can do unknown opcode %d", pluginIdString, opcode); break; } freePluginVst2xId(pluginId); return result; }