GetDunne Wiki

Notes from the desk of Shane Dunne, software development consultant

User Tools

Site Tools


the_plugin_processor

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
the_plugin_processor [2017/08/30 17:25]
shane created
the_plugin_processor [2017/08/30 17:47] (current)
shane
Line 55: Line 55:
 }; };
 </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>
Line 72: Line 77:
 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:
Line 85: Line 90:
 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)
Line 100: Line 120:
 } }
 </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>
Line 125: Line 147:
 </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:
the_plugin_processor.1504113934.txt.gz · Last modified: 2017/08/30 17:25 by shane