How to manage custom DSP effects
The purpose of custom DSP effects, implemented through a set of methods of the CustomDSP COM object, is to give the developer the possibility to apply DSP algorithms to the sound under playback: the concept of DSP effects is quite similar to the concept of Steinberg's Virtual Studio Technology (VST) effects but with some simplification and with more expansion possibilities.
As for VST effects, the main purpose of custom DSP effects is to take a stream of audio data, apply a process to the audio and return the result to the container application: as a secondary purpose, custom DSP effects can be used to perform sound analysis in real time, allowing for example the display of visual feedbacks or separation of stereo audio channels into different output files.
The core functionality of DSP effects is the callback function: this function is called by the DSP system and receives a buffer, containing sound samples, a parameter which tells the size in bytes of the buffer and a third parameter that allows passing to the callback a user-defined value. Samples inside the buffer can be in the following formats:
|•||If loaded sound file is 8 bits per sample, each sample is represented by a signed integer on 1 byte whose value could be in the range from -127 to 127|
|•||If loaded sound file is 16 bits per sample, each sample is represented by a signed integer on 2 bytes whose value can be in the range from -32768 to 32767|
|•||Whichever the resolution of the loaded sound file, after a call to the CustomDSP.UseFloatSamples method each sample is represented by a floating point on 4 bytes whose value can be in the range from -1.0 to 1.0; values are not automatically capped so you could also get values outside of this range|
In all cases described above, for stereo files the sequence of samples will be left channel first followed by right channel. See below a C++ sample of a callback that, after a call to the CustomDSP.UseFloatSamples method, will process a stereo file in order to swap the left channel with the right channel:
void WINAPI fnSwapStereoChannels (void *bufferSamples, DWORD bufferSamplesLength, DWORD dwUserData)
// cast the buffer to floating point
float *buffTemp = (float *) bufferSamples;
// calculate total number of samples passed to the callback
DWORD nTotalSamples = bufferSamplesLength / sizeof (float);
// loop through the buffer
for (index = 0; index < nTotalSamples; index +=2)
// swap left channel sample with right channel sample
float fSample = buffTemp[index];
buffTemp[index] = buffTemp[index+1];
buffTemp[index+1] = fSample;
In case you should apply more than one custom DSP at the same time, it's important to remember that the type used for managing samples must always match: it's not allowed applying custom DSPs using floating point samples and custom DSPs using integer samples at the same time.
There are two types of custom DSP effects:
|•||Internal DSP effects|
The code of these effects is inserted directly inside the code of the container application: usually the DSP code will be limited to a callback function containing the DSP algorithm and to some variable that will store parameters used by the DSP algorithm itself.
In order to initialize an internal DSP effect, you need to create a unique identifier for the internal DSP effect: this task can be achieved through a call to the CustomDSP.InternalLoad method: the return value of this call will be a 32 bits value that will identify the internal DSP effect.
At this point you need to set the callback function that will apply the DSP algorithm to incoming sound data: for this purpose you need to create a specific callback function inside your code and then to pass this function to Active DJ Studio calling the CustomDSP.InternalSetFunction method. It's important to remember that the algorithm of the DSP effect inside the callback function must be as quick as possible and should never call functions or APIs that could require user's interaction like message boxes and similar.
During our tests we have found that the use of internal callbacks, although being a common practice, is quite heavy for Visual Basic 6 and could sometime cause unpredictable GPFs or dead-lock situations when setting a breakpoint inside the callback function: it's important to note that the EXE file of the container application, compiled by Visual Basic 6 itself and run outside of the development environment, will not suffer the problem.
|•||External DSP effects|
The code of external DSP effects is inserted inside external dynamic-link library (DLL) files which need to export one or more pre-defined functions.
In order to initialize an external DSP effect, you need to create a unique identifier for the external DSP effect: this task can be achieved through a call to the CustomDSP.ExternalLoad method which will receive the filename or the absolute pathname of the external DLL file and will return a 32 bits value that will identify the external DSP effect: this method can be considered a specialized version of the LoadLibrary Windows API.
Once we have successfully loaded the external DSP and obtained its unique identifier, we can gain access to its exported functions through the CustomDSP.ExternalSetFunction method which can be considered a specialized version of the GetProcAddress Windows API.
Functions exported by the dynamic-link library (DLL) containing the DSP effect should be one or more of the following:
|•||The callback function used to apply the DSP algorithm to incoming sound data: the presence of this function should be considered as mandatory. The callback function is called internally after invoking the CustomDSP.Enable method: it's important to note that the code of the callback function must be as quick as possible and should never call functions or APIs that could require user's interaction like message boxes and similar.|
|•||Two function used to obtain and set parameters used by the algorithm of the external DSP effect. Calls to these functions at runtime are wrapped within calls to the CustomDSP.ExternalGetParameters and CustomDSP.ExternalSetParameters methods. As you may understand, each DSP effect will come with its own set of parameters so they will need to be defined by the DSP developer himself and made public in order to be managed by our container application: just to make a comparison with the Microsoft's SDK, the developer that will write a DSP effect will have to deliver a sort of ".h" include file containing the definition of all of the needed data structures allowing their use from within the container application.|
|•||The function used to send custom commands to the external DSP. This is an optional function and its call at runtime is wrapped within a call to the CustomDSP.ExternalSendCommand method. This function allows the container application sending pre-defined custom commands to the DSP effect in form of a string of characters: as you may understand this gives great flexibility and allows the developer of the DSP effect to define a "dialect" of custom commands. There is no limitation to the way these custom commands could be defined or used: they could be seen as a sort of "command line" where you could define your own set of options and parameters or as a XML formatted string containing both commands and parameters: parsing contents of these commands will be obviously responsibility of the external custom DSP effect. After receiving a custom command, the DSP effect will have the possibility to immediately reply through the return value of the CustomDSP.ExternalSendCommand method or, in case of a lengthy operation managed inside a secondary thread, at a later time through the use of the PostMessage Windows API, sending a user-defined message to the window (HWND) of the container form or dialog box.|
|•||The function used to display or hide the editor (user interface) of the external DSP: editors can be useful in order to display custom user interfaces which allows modifying the algorithm parameters through user's interaction: its presence can be certainly considered as optional. The call to this function at runtime is wrapped within a call to the CustomDSP.ExternalEditorShow method.|
|•||The function used to obtain information about the editor (if available) of the external DSP. The call to this function at runtime is wrapped within a call to the CustomDSP.ExternalEditorGetInfo method. Typical editor's parameters could be its visibility state, its coordinates and dimensions respect to the client area of the parent window but also colors for customizing the appearance of the editor.|
It's certainly worth to mention that an external dynamic-link library (DLL) could contain more than one DSP effect: in this case, for each of the available DSP effects you will have to call the CustomDSP.ExternalLoad method (this will obviously generate a specific unique identifier) and the CustomDSP.ExternalSetFunction method for setting the specific callback function.
During playback both internal and external custom DSP effects can be enabled/disabled through the CustomDSP.Enable method: through this method you can not only create a chain of DSP effects but, through its nPriority parameter, you can establish which DSP effect will be processed first.
IMPORTANT NOTICE ABOUT EFFECTS APPLIED TO THE OUTPUT OF A STREAM MIXER BEING SENT TO A CASTING SERVER OR TO THE RECORDER
DSP effects can be applied to the output of a custom stream mixer by using the unique identifier of the custom stream mixer itself for the nPlayer parameter of the effect to apply; if you want that these effects are reflected to the stream going to the casting server or to the recorder control also, you need to set the nPriority parameter of the DSP to a value higher than 0.
Both internal and external custom DSP effects can be discarded from memory using the CustomDSP.Free method.
In order to have a better understanding about the use and implementation of custom DSP effects, you will find some sample of usage of these internal and external DSP effects inside the CustomDSP and CustomDSPWithUI samples installed by the product's setup package. You will also find two projects, written in Visual C++ 6, that demonstrate the implementation of two external custom DSP effects, one containing an editor (named MyCustomDspWithUI) that will implement a simple "Bass Boost" effect and one without any editor (named MyCustomDsp) that will implement two different effects: a simple "Reverb" effect and a simple "Balance" effect.