//------------------------------------------------------------------------------------------------------- // VST Plug-Ins SDK // Version 2.4 $Date: 2006/11/13 09:08:27 $ // // Category : VST 2.x SDK Samples // Filename : vstxsynth.cpp // Created by : Steinberg Media Technologies // Description : Example VstXSynth // // A simple 2 oscillators test 'synth', // Each oscillator has waveform, frequency, and volume // // *very* basic monophonic 'synth' example. you should not attempt to use this // example 'algorithm' to start a serious virtual instrument; it is intended to demonstrate // how VstEvents ('MIDI') are handled, but not how a virtual analog synth works. // there are numerous much better examples on the web which show how to deal with // bandlimited waveforms etc. // // © 2006, Steinberg Media Technologies, All Rights Reserved //------------------------------------------------------------------------------------------------------- #include "vstxsynth.h" #include "gmnames.h" //------------------------------------------------------------------------------------------------------- AudioEffect* createEffectInstance (audioMasterCallback audioMaster) { return new VstXSynth (audioMaster); } //----------------------------------------------------------------------------------------- // VstXSynthProgram //----------------------------------------------------------------------------------------- VstXSynthProgram::VstXSynthProgram () { // Default Program Values fWaveform1 = 0.f; // saw fFreq1 =.0f; fVolume1 = .33f; fWaveform2 = 1.f; // pulse fFreq2 = .05f; // slightly higher fVolume2 = .33f; fVolume = .9f; vst_strncpy (name, "Basic", kVstMaxProgNameLen); } //----------------------------------------------------------------------------------------- // VstXSynth //----------------------------------------------------------------------------------------- VstXSynth::VstXSynth (audioMasterCallback audioMaster) : AudioEffectX (audioMaster, kNumPrograms, kNumParams) { // initialize programs programs = new VstXSynthProgram[kNumPrograms]; for (VstInt32 i = 0; i < 16; i++) channelPrograms[i] = i; if (programs) setProgram (0); if (audioMaster) { setNumInputs (0); // no inputs setNumOutputs (kNumOutputs); // 2 outputs, 1 for each oscillator canProcessReplacing (); isSynth (); setUniqueID ('VxS2'); // <<= kNumPrograms) return; VstXSynthProgram *ap = &programs[program]; curProgram = program; fWaveform1 = ap->fWaveform1; fFreq1 = ap->fFreq1; fVolume1 = ap->fVolume1; fWaveform2 = ap->fWaveform2; fFreq2 = ap->fFreq2; fVolume2 = ap->fVolume2; fVolume = ap->fVolume; } //----------------------------------------------------------------------------------------- void VstXSynth::setProgramName (char* name) { vst_strncpy (programs[curProgram].name, name, kVstMaxProgNameLen); } //----------------------------------------------------------------------------------------- void VstXSynth::getProgramName (char* name) { vst_strncpy (name, programs[curProgram].name, kVstMaxProgNameLen); } //----------------------------------------------------------------------------------------- void VstXSynth::getParameterLabel (VstInt32 index, char* label) { switch (index) { case kWaveform1: case kWaveform2: vst_strncpy (label, "Shape", kVstMaxParamStrLen); break; case kFreq1: case kFreq2: vst_strncpy (label, "Hz", kVstMaxParamStrLen); break; case kVolume1: case kVolume2: case kVolume: vst_strncpy (label, "dB", kVstMaxParamStrLen); break; } } //----------------------------------------------------------------------------------------- void VstXSynth::getParameterDisplay (VstInt32 index, char* text) { text[0] = 0; switch (index) { case kWaveform1: if (fWaveform1 < .5) vst_strncpy (text, "Sawtooth", kVstMaxParamStrLen); else vst_strncpy (text, "Pulse", kVstMaxParamStrLen); break; case kFreq1: float2string (fFreq1, text, kVstMaxParamStrLen); break; case kVolume1: dB2string (fVolume1, text, kVstMaxParamStrLen); break; case kWaveform2: if (fWaveform2 < .5) vst_strncpy (text, "Sawtooth", kVstMaxParamStrLen); else vst_strncpy (text, "Pulse", kVstMaxParamStrLen); break; case kFreq2: float2string (fFreq2, text, kVstMaxParamStrLen); break; case kVolume2: dB2string (fVolume2, text, kVstMaxParamStrLen); break; case kVolume: dB2string (fVolume, text, kVstMaxParamStrLen); break; } } //----------------------------------------------------------------------------------------- void VstXSynth::getParameterName (VstInt32 index, char* label) { switch (index) { case kWaveform1: vst_strncpy (label, "Wave 1", kVstMaxParamStrLen); break; case kFreq1: vst_strncpy (label, "Freq 1", kVstMaxParamStrLen); break; case kVolume1: vst_strncpy (label, "Levl 1", kVstMaxParamStrLen); break; case kWaveform2: vst_strncpy (label, "Wave 2", kVstMaxParamStrLen); break; case kFreq2: vst_strncpy (label, "Freq 2", kVstMaxParamStrLen); break; case kVolume2: vst_strncpy (label, "Levl 2", kVstMaxParamStrLen); break; case kVolume: vst_strncpy (label, "Volume", kVstMaxParamStrLen); break; } } //----------------------------------------------------------------------------------------- void VstXSynth::setParameter (VstInt32 index, float value) { VstXSynthProgram *ap = &programs[curProgram]; switch (index) { case kWaveform1: fWaveform1 = ap->fWaveform1 = value; break; case kFreq1: fFreq1 = ap->fFreq1 = value; break; case kVolume1: fVolume1 = ap->fVolume1 = value; break; case kWaveform2: fWaveform2 = ap->fWaveform2 = value; break; case kFreq2: fFreq2 = ap->fFreq2 = value; break; case kVolume2: fVolume2 = ap->fVolume2 = value; break; case kVolume: fVolume = ap->fVolume = value; break; } } //----------------------------------------------------------------------------------------- float VstXSynth::getParameter (VstInt32 index) { float value = 0; switch (index) { case kWaveform1: value = fWaveform1; break; case kFreq1: value = fFreq1; break; case kVolume1: value = fVolume1; break; case kWaveform2: value = fWaveform2; break; case kFreq2: value = fFreq2; break; case kVolume2: value = fVolume2; break; case kVolume: value = fVolume; break; } return value; } //----------------------------------------------------------------------------------------- bool VstXSynth::getOutputProperties (VstInt32 index, VstPinProperties* properties) { if (index < kNumOutputs) { vst_strncpy (properties->label, "Vstx ", 63); char temp[11] = {0}; int2string (index + 1, temp, 10); vst_strncat (properties->label, temp, 63); properties->flags = kVstPinIsActive; if (index < 2) properties->flags |= kVstPinIsStereo; // make channel 1+2 stereo return true; } return false; } //----------------------------------------------------------------------------------------- bool VstXSynth::getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text) { if (index < kNumPrograms) { vst_strncpy (text, programs[index].name, kVstMaxProgNameLen); return true; } return false; } //----------------------------------------------------------------------------------------- bool VstXSynth::getEffectName (char* name) { vst_strncpy (name, "VstXSynth", kVstMaxEffectNameLen); return true; } //----------------------------------------------------------------------------------------- bool VstXSynth::getVendorString (char* text) { vst_strncpy (text, "Steinberg Media Technologies", kVstMaxVendorStrLen); return true; } //----------------------------------------------------------------------------------------- bool VstXSynth::getProductString (char* text) { vst_strncpy (text, "Vst Test Synth", kVstMaxProductStrLen); return true; } //----------------------------------------------------------------------------------------- VstInt32 VstXSynth::getVendorVersion () { return 1000; } //----------------------------------------------------------------------------------------- VstInt32 VstXSynth::canDo (char* text) { if (!strcmp (text, "receiveVstEvents")) return 1; if (!strcmp (text, "receiveVstMidiEvent")) return 1; if (!strcmp (text, "midiProgramNames")) return 1; return -1; // explicitly can't do; 0 => don't know } //----------------------------------------------------------------------------------------- VstInt32 VstXSynth::getNumMidiInputChannels () { return 1; // we are monophonic } //----------------------------------------------------------------------------------------- VstInt32 VstXSynth::getNumMidiOutputChannels () { return 0; // no MIDI output back to Host app } // midi program names: // as an example, GM names are used here. in fact, VstXSynth doesn't even support // multi-timbral operation so it's really just for demonstration. // a 'real' instrument would have a number of voices which use the // programs[channelProgram[channel]] parameters when it receives // a note on message. //------------------------------------------------------------------------ VstInt32 VstXSynth::getMidiProgramName (VstInt32 channel, MidiProgramName* mpn) { VstInt32 prg = mpn->thisProgramIndex; if (prg < 0 || prg >= 128) return 0; fillProgram (channel, prg, mpn); if (channel == 9) return 1; return 128L; } //------------------------------------------------------------------------ VstInt32 VstXSynth::getCurrentMidiProgram (VstInt32 channel, MidiProgramName* mpn) { if (channel < 0 || channel >= 16 || !mpn) return -1; VstInt32 prg = channelPrograms[channel]; mpn->thisProgramIndex = prg; fillProgram (channel, prg, mpn); return prg; } //------------------------------------------------------------------------ void VstXSynth::fillProgram (VstInt32 channel, VstInt32 prg, MidiProgramName* mpn) { mpn->midiBankMsb = mpn->midiBankLsb = -1; mpn->reserved = 0; mpn->flags = 0; if (channel == 9) // drums { vst_strncpy (mpn->name, "Standard", 63); mpn->midiProgram = 0; mpn->parentCategoryIndex = 0; } else { vst_strncpy (mpn->name, GmNames[prg], 63); mpn->midiProgram = (char)prg; mpn->parentCategoryIndex = -1; // for now for (VstInt32 i = 0; i < kNumGmCategories; i++) { if (prg >= GmCategoriesFirstIndices[i] && prg < GmCategoriesFirstIndices[i + 1]) { mpn->parentCategoryIndex = i; break; } } } } //------------------------------------------------------------------------ VstInt32 VstXSynth::getMidiProgramCategory (VstInt32 channel, MidiProgramCategory* cat) { cat->parentCategoryIndex = -1; // -1:no parent category cat->flags = 0; // reserved, none defined yet, zero. VstInt32 category = cat->thisCategoryIndex; if (channel == 9) { vst_strncpy (cat->name, "Drums", 63); return 1; } if (category >= 0 && category < kNumGmCategories) vst_strncpy (cat->name, GmCategories[category], 63); else cat->name[0] = 0; return kNumGmCategories; } //------------------------------------------------------------------------ bool VstXSynth::hasMidiProgramsChanged (VstInt32 channel) { return false; // updateDisplay () } //------------------------------------------------------------------------ bool VstXSynth::getMidiKeyName (VstInt32 channel, MidiKeyName* key) // struct will be filled with information for 'thisProgramIndex' and 'thisKeyNumber' // if keyName is "" the standard name of the key will be displayed. // if false is returned, no MidiKeyNames defined for 'thisProgramIndex'. { // key->thisProgramIndex; // >= 0. fill struct for this program index. // key->thisKeyNumber; // 0 - 127. fill struct for this key number. key->keyName[0] = 0; key->reserved = 0; // zero key->flags = 0; // reserved, none defined yet, zero. return false; }