SDK » Documentation » Upgrading from SDK Version 2


You should now be able to re-open SynthEdit and insert your new module. (It is not functional yet because it has an empty sub-process method).
Back in Visual Studio you can inspect the new project files. There are a handful of SDK files, plus the actual module files: Gain.h, Gain.cpp, and Gain.xml.
Open Gain2.cpp, inside is the minimal code for your plugin, including a basic subProcess method.
void Gain2::subProcess( int bufferOffset, int sampleFrames )
{
// get pointers to in/output buffers.
float* input = bufferOffset + pinInput.getBuffer();
float* input2 = bufferOffset + pinInput2.getBuffer();
float* output = bufferOffset + pinOutput.getBuffer();
for( int s = sampleFrames; s > 0; --s )
{
// TODO: Signal processing goes here.
// Increment buffer pointers.
++input;
++input2;
++output;
}
}
Note the name has changed from 'sub_process' to 'subProcess', this is an example of the updated coding conventions. Also the buffer pointers are retrieved differently. Otherwise the method is the same as before.
The TODO is a reminder to copy your signal processing code from your old module...
for( int s = sampleFrames; s > 0; --s )
{
float in1 = *input; // get the sample 'POINTED TO' by in1
float in2 = *input2;
// do the actual processing (multiplying the two input samples together)
float result = in1 * in2;
*output = result; // store the result in the output buffer
// Increment buffer pointers.
++input;
++input2;
++output;
}
In the old SDK you had 2 methods to provide your module name and pin names and properties...
// describe your module
bool Module::getModuleProperties (SEModuleProperties* properties)
{
// describe the plugin, this is the name the end-user will see.
properties->name = "Gain Example";
// return a unique string 32 characters max
properties->id = "SynthEdit Gain Example";
properties->about = "by Jeff M (MS)" ;
return true;
}
// describe the pins (plugs)
bool Module::getPinProperties (long index, SEPinProperties* properties)
{
switch( index )
{
// typical input plug (inputs are listed first)
case 0:
properties->name = "Input";
properties->variable_address = &input1_buffer;
properties->direction = DR_IN;
properties->datatype = DT_FSAMPLE;
properties->default_value = "0";
break;
case 1:
properties->name = "Input";
properties->variable_address = &input2_buffer;
properties->direction = DR_IN;
properties->datatype = DT_FSAMPLE;
properties->default_value = "5";
break;
// typical output plug
case 2:
properties->name = "Output";
properties->variable_address = &output1_buffer;
properties->direction = DR_OUT;
properties->datatype = DT_FSAMPLE;
break;
default:
returnfalse; // host will ask for plugs 0,1,2,3 etc. return false to signal when done
};
return true;
}
These methods are gone. In their place is a simple text file - Gain2.xml.
<?xml version="1.0" encoding="utf-8" ?> <PluginList> <Plugin id="My Gain2" name="Gain2" category="MyModules" graphicsApi="HWND" helpUrl="Gain2.htm"> <Audio> <Pin id="0" name="Input" direction="in" datatype="float" rate="audio"/> <Pin id="1" name="Input 2" direction="in" datatype="float" rate="audio" default="0.5"/> <Pin id="2" name="Output" direction="out" datatype="float" rate="audio"/> </Audio> </Plugin> </PluginList>
As you can see this is less typing and easy to edit. It also results in faster compilation, less code generated and smaller SEM files.
This method was called anytime a pin was updated.
void Module::OnPlugStateChange(SEPin *pin)
{
state_type in_stat1 = getPin(PN_INPUT1)->getStatus();
SDK3 replaces OnPlugStateChange() with onSetPins().
void Gain2::onSetPins(void)
{
// Check which pins are updated.
if( pinInput.isStreaming() )
{
}
Rather than check inputs for a status of ST_RUN, you now use the isStreaming() method.
Rather than check non-audio pins for ST_ONE_OFF, you now use the isUpdated() method.
void Gain2::onSetPins(void)
{
// Check which pins are updated.
if( pinInput.isUpdated() && pinInput2.isUpdated() )
{
// They both changed at the same time.
}
The functionality is the same as before, just a more readable syntax.
The only substantial difference is - When two pins are updated at the same time, onSetPins() is called only once (with both pins flagged). It was very difficult before to detect simultaneous updates on two pins, now it's easy.
Likewise, when the audio engine starts SynthEdit flags all your input pins as 'updated' and calls onSetPins() just the once. This results in less function call overhead and faster SEMs.
This has been updated. Search-and-Replace your old code with the new look. Don't forget the '&' (address-of) symbol.
Old.
SET_PROCESS_FUNC(Module::sub_process);
New.
SET_PROCESS(&Gain2::subProcess);
TransmitStatusChange() has been replaced with setStreaming(). Less typing, more readable...
Old
getPin(PN_OUTPUT1)->TransmitStatusChange( SampleClock(), ST_RUN );
New
pinOutput.setStreaming(true);
Old
getPin(PN_OUTPUT1)->TransmitStatusChange( SampleClock(), ST_STATIC );
New
pinOutput.setStreaming(false);
Previously, after checking your input pins were silent, you implemented sleep mode with a special process method to filled the output buffers with silent samples. Once that was done you asked the host to put the module to sleep...
// every module has an output buffer of approx. 100 samples.
// before deactivating module, need to fill that buffer with silence.
// "static_count" is counting out those 100 samples.
void Module::sub_process_static(long buffer_offset, long sampleFrames )
{
sub_process(buffer_offset, sampleFrames);
static_count = static_count - sampleFrames;
if( static_count <= 0 )
{
CallHost(seaudioMasterSleepMode);
}
}
Although this is still necessary. The new SDK does it for you. Your module no longer needs any special code. You don't need to port that code to SDK V3.
If you don't want automatic sleep mode, or need to handle it manually you can disable automatic sleep mode...
setSleep(false);
That was the quick guide to porting to SDK3. Any further questions please post to the SynthEdit SDK group at yahoo.