public void LoadChannelPreset(VstPluginChannel channel, ChannelPreset channelPreset) { // First load instrument if (channelPreset.InstrumentVstPreset.State != PluginState.Empty) { channel.InstrumentPlugin.AttachVstPluginContext(GetVstPluginContext(channelPreset.InstrumentVstPreset.Name), channelPreset.InstrumentVstPreset.Name); } // Then load all effects for (int i = 0; i < VstPluginChannel.NumberOfEffectPlugins; i++) { if (channelPreset.EffectVstPresets[i].State != PluginState.Empty) { channel.EffectPlugins[i].AttachVstPluginContext(GetVstPluginContext(channelPreset.EffectVstPresets[i].Name), channelPreset.EffectVstPresets[i].Name); } } channel.ImportChannelPreset(channelPreset); }
/// <summary> /// Constructor /// </summary> /// <param name="settingsMgr"></param> /// <param name="channels"></param> public AudioPluginEngine(SettingsManager settingsMgr, VuMeter[] meters, Panel hostScrollPanel) { // Add editor panel to host to allow scrolling mHostScrollPanel = hostScrollPanel; Panel hostEditorPanel = new Panel(); hostScrollPanel.Controls.Add(hostEditorPanel); PluginChannels = new VstPluginChannel[NrOfPluginChannels]; mMidiPanic = new bool[NrOfPluginChannels]; // Create all channel, effect and master effect plugins for (int i = 0; i < NrOfPluginChannels; i++) { PluginChannels[i] = new VstPluginChannel(settingsMgr.Settings.AsioBufferSize); mMidiPanic[i] = false; } MasterEffectPluginChannel = new VstPluginChannel(settingsMgr.Settings.AsioBufferSize); foreach (VstPlugin plugin in PluginChannels.SelectMany(x => x.AllPlugins)) { plugin.EditorPanel = hostEditorPanel; // Let controls know if other control loaded an editor plugin.OnEditorOpening += chCtrl_OnEditorOpen; plugin.OnEditorOpened += chCtrl_OnEditorOpened; plugin.OnEditorClosed += chCtrl_OnEditorClose; } mSettingsMgr = settingsMgr; mVUMeters = meters; if (mSettingsMgr.Settings.VSTPluginFolders != null) { foreach (string path in mSettingsMgr.Settings.VSTPluginFolders) { addPath(path); } } MasterPan = mSettingsMgr.Settings.MasterPan; // Send all notes off on midi channel 1 byte[] midiData = new byte[4]; // http://www.midi.org/techspecs/midimessages.php midiData[0] = 176; // Send all notes off on midi channel 1 midiData[1] = 123; // All Notes Off midiData[2] = 0; midiData[3] = 0; VstMidiEvent midiPanicEvent = new VstMidiEvent( /*DeltaFrames*/ 0, /*NoteLength*/ 0, /*NoteOffset*/ 0, midiData, /*Detune*/ 0, /*NoteOffVelocity*/ 127); mMidiPanicEvents = new VstEvent[1]; mMidiPanicEvents[0] = midiPanicEvent; mMidiDevice = new MidiDevice(); }
/// <summary> /// Handle ASIO update event /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void asio_BufferUpdateHandler(object sender, EventArgs e) { mCpuLoadStopWatch.Restart(); //long elapsedticksoutsidehandler = mCpuLoadStopWatch.ElapsedTicks; //ticksArray[ticksArrayIndex++] = elapsedticksoutsidehandler - prevTicks; //if (ticksArrayIndex == 344) //{ // ticksArrayIndex = 0; //} //prevTicks = elapsedticksoutsidehandler; #endif if (mFirstAsioBufferUpdateHandlerCall) { uint taskIndex; Thread.CurrentThread.Priority = ThreadPriority.Highest; IntPtr handle = AvSetMmThreadCharacteristics("Pro Audio", out taskIndex); mFirstAsioBufferUpdateHandlerCall = false; } // Clear output buffer for (int index = 0; index < mAsioBuffSize; index++) { mAsioOutputLeft[index] = 0.0f; mAsioOutputRight[index] = 0.0f; } // Dequeue all midi in messages int midiInCount = mMidiDevice.MidiInMessagesCount(); // Expand array if required if (midiInCount > mMidiInMessages.Length) { mMidiInMessages = new MidiMessage[midiInCount]; } // Now dequeue midi messages midiInCount = mMidiDevice.DequeueMidiInMessages(mMidiInMessages, 0, midiInCount); for (int i = 0; i < NrOfPluginChannels; i++) { bool midiPanic = mMidiPanic[i]; mMidiPanic[i] = false; VstPluginChannel channel = PluginChannels[i]; // Copy Asio input to channel input // todo: [JBK] point the VstChannel input buffer directly tot the input buffer from the asio driver to prevent all the copying. // For now just try this if it works if (channel.InputBuffers.Count > 0) { for (int n = 0; n < mAsioBuffSize; ++n) { channel.InputBuffers.Raw[0][n] = mAsioInputLeft[n]; channel.InputBuffers.Raw[1][n] = mAsioInputRight[n]; } } if (channel.InstrumentPlugin.State == PluginState.Empty) { continue; } else if (channel.InstrumentPlugin.State == PluginState.Unloading) { channel.InstrumentPlugin.FinishUnloading(); continue; } // Activated OR deactivated (still receiving note-off messages): VstEvent[] filteredMidiEvents = filterMidiInMessages(midiInCount, channel.InstrumentPlugin); if (midiPanic) { channel.InstrumentPlugin.VstPluginContext.PluginCommandStub.ProcessEvents(mMidiPanicEvents); } else { channel.InstrumentPlugin.VstPluginContext.PluginCommandStub.ProcessEvents(filteredMidiEvents); } // Get audio from the instrument plugin channel.InstrumentPlugin.VstPluginContext.PluginCommandStub.ProcessReplacing(channel.InstrumentPlugin.InputBuffers.Buffers, channel.InstrumentPlugin.OutputBuffers.Buffers); bool swappedBuffers = false; // Effect plugins for (int n = 0; n < VstPluginChannel.NumberOfEffectPlugins; n++) { VstPlugin effectPlugin = channel.EffectPlugins[n]; if (effectPlugin.State == PluginState.Empty) { continue; } else if (effectPlugin.State == PluginState.Unloading) { effectPlugin.FinishUnloading(); continue; } else if (effectPlugin.State == PluginState.Activated) { if (midiPanic) { channel.InstrumentPlugin.VstPluginContext.PluginCommandStub.ProcessEvents(mMidiPanicEvents); } else { channel.InstrumentPlugin.VstPluginContext.PluginCommandStub.ProcessEvents(filteredMidiEvents); } if (!swappedBuffers) { // Take outputbuffer of the previous 'process replacing' as input, and write output to the other (input) buffer. effectPlugin.VstPluginContext.PluginCommandStub.ProcessReplacing(effectPlugin.OutputBuffers.Buffers, effectPlugin.InputBuffers.Buffers); swappedBuffers = true; } else { // Take inputbuffer of the previous 'process replacing' as input, and write output to the other (output) buffer. effectPlugin.VstPluginContext.PluginCommandStub.ProcessReplacing(effectPlugin.InputBuffers.Buffers, effectPlugin.OutputBuffers.Buffers); swappedBuffers = false; } } } // Now copy to mix for (int index = 0; index < mAsioBuffSize; index++) { if (swappedBuffers) { // todo: Pan mAsioOutputLeft[index] += channel.InputBuffers.Raw[0][index] * channel.InstrumentPlugin.Volume; mAsioOutputRight[index] += channel.InputBuffers.Raw[1][index] * channel.InstrumentPlugin.Volume; } else { // todo: Pan mAsioOutputLeft[index] += channel.OutputBuffers.Raw[0][index] * channel.InstrumentPlugin.Volume; mAsioOutputRight[index] += channel.OutputBuffers.Raw[1][index] * channel.InstrumentPlugin.Volume; } } } //mMidiEventsAll.Free (midiEventsAllCount ); //mMidiEventsAllExceptNoteOn.Free(midiEventsAllExceptNoteOnCount); // Master pan + measure max volume levels + mMaxVolLeft = 0.0f; mMaxVolRight = 0.0f; for (int index = 0; index < mAsioBuffSize; index++) { // Master pan mAsioOutputLeft[index] *= mPanLeft; mAsioOutputRight[index] *= mPanRight; // Get max volume levels if (mAsioOutputLeft[index] > mMaxVolLeft) { mMaxVolLeft = mAsioOutputLeft[index]; } if (mAsioOutputRight[index] > mMaxVolRight) { mMaxVolRight = mAsioOutputRight[index]; } } mVUMeters[0].Value = mMaxVolLeft; mVUMeters[1].Value = mMaxVolRight; lock (mMP3RecorderLockObj) { if (mMp3Recorder != null) { mMp3Recorder.WriteSamples(mAsioOutputLeft, mAsioOutputRight, mAsioBuffSize); } } #if NAUDIO_ASIO // Copy mix for (int index = 0; index < mMixLeft.Length; index++) { // First copy left sample Buffer.BlockCopy(sampleToInt32Bytes(mMixLeft[index]), 0, mAsioLeftInt32LSBBuff, index * 4, 4); // Then copy right sample Buffer.BlockCopy(sampleToInt32Bytes(mMixRight[index]), 0, mAsioRightInt32LSBBuff, index * 4, 4); } // Copy left buff Marshal.Copy(mAsioLeftInt32LSBBuff, 0, e.OutputBuffers[0], e.SamplesPerBuffer * 4); // Copy right buff Marshal.Copy(mAsioRightInt32LSBBuff, 0, e.OutputBuffers[1], e.SamplesPerBuffer * 4); mVstTimeInfo.SamplePosition++; e.WrittenToOutputBuffers = true; #else // Start buffer calculations for next asio call. VstTimeInfo.SamplePosition++; #endif int cpuLoad = 0; long elapsedTicksDuringHandler = mCpuLoadStopWatch.ElapsedTicks; cpuLoad = (int)(elapsedTicksDuringHandler * 100 / stopWatchTicksForOneAsioBuffer); if (cpuLoad > mMaxCpuLoad) { mMaxCpuLoad = cpuLoad; } }