SynthLab SDK
|
Programming the SynthEngine from the client-side (from your plugin framework) was designed to be as simple as possible, requiring only a handful of function calls. The most important code that you will need to write involves setting up the SynthBlockProc structure that contains your audio buffers and MIDI messages for a single block process render cycle. Note that this code is going to be extremely dependent on your plugin framework and you will need to know how to access your client's audio and MIDI data buffers.
The SynthProcessInfo structure is covered in Block Audio Processing and this is key to the engine's operation as it is the argument that is passed during the render() call to service MIDI events and to fill buffers with synthesized audio. In my implementations, the framework's processing object creates a static instance of the structure, initializes it, and then loads it with MIDI events prior to calling the render function.
Setting up and initializing your SynthProcessInfo struct is simple:
MIDI Events
You will need to push the MIDI events that occurred during the time in the audio block into the structure prior to calling the render() method on the synth. There are two functions to help; one which clears out the last set of MIDI events and another to push a new event on the FIFO stack (which is really just a std::vector). See the MIDI Note Events section for information on MIDI event structures and Enqueueing MIDI Events section for more information about adding MIDI events to the SynthProcessInfo's queue. You code will look like this:
The rest of the SynthEngine operation is simple, as long as you have the SynthProcessInfo structure initialized and ready to be loaded with MIDI events. There are four operational phases plus creation:
Creation
The SynthEngine needs to know the audio block processing size from the very beginning of its existence. Once set, this size should not change. You have two options for declaring the SynthEngine:
Reset and Initialize
The reset and intialize phases are simple requiring one function all each and described in SynthEngine Template Code; note that these should normally be called in succession, startint with the reset() function. One of the reasons for the ordering here involves the location of the path variable for the initialize() function, which may not be known at construction time on the framework processing object. Since it is likely you will instantiate the engine as part of construction, the initialize() function must not be called until you have the path to send it. See SynthEngine Template Code for more information on this path.
GUI Parameter Updates
Details about the GUI update cycle and example code are avaialble in Updating GUI Parameters. You get the parameter structure pointers, alter variables with them, then call the update function.
Render Audio and Access Buffers
With the SynthProcessInfo structure (named synthBlockProcInfo here) prepared and loaded with one block's worth of MIDI events, you then call the render() method, passing in this single structure as the argument. Once render() returns, you can access the audio data in the buffers and send them to your framework's output buffers.
Engine Destruction
In the example here using smart pointers, there is nothing to do but let the smart pointer delete itself. If you declare the engine statically, it will be destroyed in a likewise manner in your processing object's destructor. If you use old fashioned allocation and pointers, you need to call the delete operator manually. There are numerous data arrays to clear, and for the SynthLab-PCM synth, around 1.4GB of PCM samples to delete, so the destruction phase is quite important!