Next revision
|
Previous revision
|
the_plugin_processor [2017/08/30 17:25] shane created |
the_plugin_processor [2017/08/30 17:47] (current) shane |
}; | }; |
</code> | </code> |
| |
| Many of the member functions are trivial, so I won't cover them in any detail here. |
| |
| ===== Constructor and Destructor ===== |
| |
The constructor instantiates all other required objects and connects them as required: | The constructor instantiates all other required objects and connects them as required: |
<code cpp> | <code cpp> |
The destructor is actually empty. It's not necessary to call **delete** on the created //SynthVoice// and //SynthSound// objects, because the //synth// object takes ownership of them via the //add...()// calls, and will delete them itself when its destructor gets called. | The destructor is actually empty. It's not necessary to call **delete** on the created //SynthVoice// and //SynthSound// objects, because the //synth// object takes ownership of them via the //add...()// calls, and will delete them itself when its destructor gets called. |
| |
Many of the other member functions are trivial, so I'll just skip over them. | ===== setCurrentProgram() ===== |
| |
The //setCurrentProgram()// function gets called whenever the user changes the current preset through the plugin host: | The //setCurrentProgram()// function gets called whenever the user changes the current preset through the plugin host: |
This code changes the //pParams// pointer inside the shared //SynthSound// object, which propagates the change to subsequently-played notes (we don't attempt to change currently-sounding notes in response to program changes), then calls //sendChangeMessage()// to notify the GUI editor, so it can update its display accordingly. | This code changes the //pParams// pointer inside the shared //SynthSound// object, which propagates the change to subsequently-played notes (we don't attempt to change currently-sounding notes in response to program changes), then calls //sendChangeMessage()// to notify the GUI editor, so it can update its display accordingly. |
| |
The plugin host can call //getCurrentProgramStateInformation()// to get the current preset as a "blob" of binary data (which it can e.g. save to a ''.fxp'' file), or call //setCurrentProgramStateInformation()// to do the reverse operation. In an early version of VanillaJuce, I simply did a binary copy of the //SynthParameters// ''struct'', but I realized that would cause problems as I changed the structure over time, so the new code uses JUCE's XML capabilities to save and restore the data in XML format: | ===== changeProgramName() ===== |
| |
| The //changeProgramName()// function gets called whenever the user edits the name of the current preset through the plugin host: |
| <code cpp> |
| void VanillaJuceAudioProcessor::changeProgramName (int index, const String& newName) |
| { |
| newName.copyToUTF8(programBank[index].programName, kMaxProgramNameLength); |
| sendChangeMessage(); |
| } |
| </code> |
| |
| The present VanillaJuce GUI does not display program names, but I've included a call to //sendChangeMessage()// to notify the GUI anyway, so I won't forget it. If and when I do add a program-name display to the GUI, it will get updated whenever the name is changed through the plugin host. |
| |
| ===== The preset-handling functions ===== |
| |
| The plugin host can call //getCurrentProgramStateInformation()// to get the current preset as a "blob" of binary data (which it can e.g. save to a ''.fxp'' file), or call //setCurrentProgramStateInformation()// to do the reverse operation. In an early version of VanillaJuce, I simply did a binary copy of the //SynthParameters// ''struct'', but I realized that would cause problems as I changed the structure over time, so the new code uses JUCE's XML capabilities to save and restore the data in XML format. (I based my code on that in [[https://github.com/2DaT/Obxd|Obxd]].) |
<code cpp> | <code cpp> |
void VanillaJuceAudioProcessor::getCurrentProgramStateInformation(MemoryBlock& destData) | void VanillaJuceAudioProcessor::getCurrentProgramStateInformation(MemoryBlock& destData) |
} | } |
</code> | </code> |
| Note that //setCurrentProgramStateInformation()// also calls //sendChangeMessage()// because it changes the current preset, and so must notify the GUI. |
| |
Most of the details are in the //getXml()// and //putXml()// member functions of //SynthParameters//. The code is unremarkable, but serves to generate and parse XML structures like this (formatted for clarity): | Most of the details are in the //getXml()// and //putXml()// member functions of //SynthParameters//. The code is unremarkable, but serves to generate and parse XML structures like this (formatted for clarity): |
<code xml> | <code xml> |
</code> | </code> |
| |
| The //getStateInformation()// and //setStateInformation()// do the same thing for an entire bank of patches: |
| <code> |
| void VanillaJuceAudioProcessor::getStateInformation (MemoryBlock& destData) |
| { |
| XmlElement xml = XmlElement("VanillaJuce"); |
| xml.setAttribute(String("currentProgram"), currentProgram); |
| XmlElement* xprogs = new XmlElement("programs"); |
| for (int i = 0; i < kNumberOfPrograms; i++) |
| xprogs->addChildElement(programBank[i].getXml()); |
| xml.addChildElement(xprogs); |
| copyXmlToBinary(xml, destData); |
| } |
| |
| void VanillaJuceAudioProcessor::setStateInformation (const void* data, int sizeInBytes) |
| { |
| ScopedPointer<XmlElement> xml = getXmlFromBinary(data, sizeInBytes); |
| XmlElement* xprogs = xml->getFirstChildElement(); |
| if (xprogs->hasTagName(String("programs"))) |
| { |
| int i = 0; |
| forEachXmlChildElement(*xprogs, xpr) |
| { |
| programBank[i].setDefaultValues(); |
| programBank[i].putXml(xpr); |
| i++; |
| } |
| } |
| setCurrentProgram(xml->getIntAttribute(String("currentProgram"), 0)); |
| } |
| </code> |
| Note that //setStateInformation()// also calls //sendChangeMessage()// because it changes all presets, //including the current one//, and so must notify the GUI. |
| |
| The XML structure for patch banks looks like this, where each ''<program ... />'' item is structured as above: |
| <code xml> |
| <VanillaJuce currentProgram="0"> |
| <programs> |
| <program name="Default" masterLevel="0.14999999999999999445" ... /> |
| ... 127 more program objects ... |
| </programs> |
| </VanillaJuce></code> |
| |
| ===== Rendering sound: processBlock() ===== |
| |
The //processBlock()// function, which actually renders audio, simply delegates to the //Synth// object: | The //processBlock()// function, which actually renders audio, simply delegates to the //Synth// object: |