I first tried suspending the plugin but that didn’t seem to reduce cpu load. Perhaps I made a mistake but I decided to go for a full vst power-down in order to learn how to call and use custom vst behaviors from an AudioProcessorGraph.
I noticed that VSTPluginInstance already had a setPower(bool) method, but it was private. So the first thing to do was to make that public. The setPower method dispatched the bool value to the plugin, and set the isPowerOn bool to reflect the current state. I then added a public getPower method which returned the state.
Since VSTPluginInstance is an AudioProcessor, I added virtual setPower/getPower methods to it, and all who inherited from it. Then I modified the processBlock method of VSTPluginInstance and had it completely bypass the processing loop when the isPowerOn bool was false, and that causes the cpu load to go down.
After doing that I modifed the plugin host demo such that I could tell a filter to power-down. The syntax being node->getProcessor()-setPower(bool). A problem however was that if you power-down the plugin before it received its note off midi messages (for soft synths) then upon power-up it immediately began making noise again. To deal with that I decided to add the ability to command a vst plugin to insert allNotesOff messages (for all 16 midi channels) into its midiBuffer whenever I set a bool indicating it needs to be done. To do that I added bool ‘allNotesOff’ and a method to set it on the VSTPluginInstance, modified the processBlock method to notice it, reset it, then insert the noteOff messages in the midiBuffer. I then had to add the allNotesOff() method to AudioProcessor and its ancestors.
From the audio plugin host demo, when I want to power-down a plugin I first call the allNotesOff() method, wait long enough for VSTPluginInstance::processBlock to be called from the audio callback, followed by setPower(false). I don’t have any experience yet with anything other than pc/vst systems and have no idea how other platforms think of these capabilities.
A nice enhancement to the power-down cycle, which I didn’t implement yet, would be for the processBlock method to wait until the output audio falls below a certain threshold and then does the bypass. This would allow any audio-tailoff’s to complete and make for nicer transitions on-stage, between songs. I’m in the process of writing on-stage software for myself, and am going for a system whereby upon command, I can transfer from one instrument to another seamlessly, without have to wait while plugins are loaded or unloaded.
I had to change the following files:
juce_amalgamated.h
juce_amalgamated.cpp
juce_audioprocessor.h
juce_audioprocessorgraph.cpp
juce_vstpluginformat.cpp
class JUCE_API AudioProcessor - added three new virtual methods (below acceptsMidi and producesMidi)
/** Returns true if the processor wants midi messages. */
virtual bool acceptsMidi() const = 0;
/** Returns true if the processor produces midi messages. */
virtual bool producesMidi() const = 0;
/** Kurt Olsen, allows enable/disable so that unused processors don't consume cpu */
virtual void setPower (const bool on) {}
virtual bool getPower () const {return true;}
virtual void allNotesOff() {};
class VSTPluginInstance - modifed the declaration as follows, I show it in context, look for my name tagged to the changes:
//==============================================================================
void getStateInformation (MemoryBlock& destData);
void getCurrentProgramStateInformation (MemoryBlock& destData);
void setStateInformation (const void* data, int sizeInBytes);
void setCurrentProgramStateInformation (const void* data, int sizeInBytes);
//==============================================================================
void setPower (const bool on); // kurt olsen - made this public, it was private
bool getPower () const { return isPowerOn; } // kurt olsen - added this method
void allNotesOff() { bAllNotesOff = true;} // kurt olsen - added this method
void timerCallback();
void handleAsyncUpdate();
VstIntPtr handleCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt);
private:
//==============================================================================
friend class VSTPluginWindow;
friend class VSTPluginFormat;
AEffect* effect;
String name;
CriticalSection lock;
bool wantsMidiMessages, initialised, isPowerOn;
bool bAllNotesOff; // kurt olsen - added this boolean
mutable StringArray programNames;
class VSTPluginInstance - implementation, changed beginning of processBlock to check for isPowerOn:
void VSTPluginInstance::processBlock (AudioSampleBuffer& buffer,
MidiBuffer& midiMessages)
{
const int numSamples = buffer.getNumSamples();
if (initialised && isPowerOn)
Then, a little further down in the processBlock method I detect, and transmit allNotesOff when told to
if (wantsMidiMessages)
{
midiEventsToSend.clear();
midiEventsToSend.ensureSize (1);
// kurt olsen - added this
if( bAllNotesOff == true ) {
bAllNotesOff = false;
for(int im = 1; im <= 16; im++ ) {
const MidiMessage pcm = MidiMessage::allNotesOff(im);
midiMessages.addEvent(pcm,0);
}
}
MidiBuffer::Iterator iter (midiMessages);
BOTH AudioProcessorGraph and AudioProcessorGraph::AudioGraphIOProcessor needed these:
void setPower(const bool) {}; // kurt olsen - added this method
bool getPower() const { return true; } // kurt olsen - added this method
To use this from the plugin host demo, some snippets…
Class FilterComponent, i changed the paint method to denote power on/off
void paint (Graphics& g)
{
g.setColour (ColourFilterConnectionBackground);
const int x = 4;
const int y = pinSize;
const int w = getWidth() - x * 2;
const int h = getHeight() - pinSize * 2;
g.fillRect (x, y, w, h);
const AudioProcessorGraph::Node::Ptr f (graph.getNodeForId (filterID));
if( f->getProcessor()->getPower() ) {
g.setColour (Colours::black);
} else {
g.setColour (Colours::red);
}
g.setFont (font);
g.drawFittedText (getName(),
x + 4, y + 2, w - 8, h - 4,
Justification::centred, 2);
g.setColour (ColourFilterConnectionBorder);
g.drawRect (x, y, w, h);
}
I added a new popup menu item to handle power on/off and it’s handler goes like this:
bool bEnabled = node->getProcessor()->getPower();
if( bEnabled ) {
node->getProcessor()->allNotesOff();
Time::waitForMillisecondCounter( Time::getMillisecondCounter() + 100 );
DBG("Sent AllNotesOff");
}
node->getProcessor()->setPower(!bEnabled);
node->properties.set("enabled", node->getProcessor()->getPower());
Remember that you might have to modify these classes in both the amalgamated and non-amalgamated versions of the source files.
Good luck.