Tutorial: Add a custom processor
The primary way to add functionality to the GUI is through custom processors. Processors are wired together inside the ProcessorGraph, which handles the application's data processing stream. Processors that generate data are known as Sources, those that modify data are called Filters, and those that send data outside the ProcessorGraph are called Sinks. Ideally, each processor should have a simple, well-defined function, and should be compatible with any type of input (even if it just ignores it).
The creation of new processors is simplified by the fact that they are all derived from the GenericProcessor class, which is itself a subclass of the JUCE AudioProcessor class. Processors only need to have a handful of methods defined in order to operate within the ProcessorGraph. Of course, it's likely that more complex processors will end up implementing a number of private methods. But this isn't necessary.
A new processor can be easily created as a processor plugin and then loaded into the GUI without the need to build the whole program each time. Once you have downloaded the GUI source code and compiled it following the appropriate instructions you can build and test separately your plugin.
How to create a new processor plugin
- Prepare your plugin source files. Create a new folder under Source/Plugins with the name of your plugin. Copy the ExampleProcessor.cpp and ExampleProcessor.h files from Source/Plugins/ExampleProcessor to your folder and rename them with your processor name. If your processor is going to use a custom Editor for its controls do the same with the ExampleEditor files. If it's just going to use the simple default controls or no controls at all you can ignore these files.
- Create the build files. If the plugin is going to be compiled under Linux, copy the Makefile.example under Source/Plugins/ExampleProcessor into your processor folder renaming it as just "Makefile". If the plugin is going to be compiled on Windows, you can use the ExampleProcessor project as base. You'd need to copy the ExampleProcessor project folder located in Builds/VisualStudio2013/Plugins to another folder with your plugin name, renaming the project files inside, open the project file (either standalone or adding it to the Plugins Solution), remove the ExampleProcessor files from it and add your own. Alternatively you could create your own project file from scratch. If the plugin is going to be compiled on Mac OS X, you need to create an Xcode project for it. Detailed information on how these build files work can be found here.
- Change the processor name where appropriate. In both the .h and .cpp file, find all the instances of "ExampleProcessor" and replace them with the name of your file. In the class constructor, change the "Example Processor" string into the name you want to be visible to users. It doesn't have to match the name of your file, although it's more convenient if they're similar. If you're using the custom editor files, do the same with them.
- Specify the type of processor. If your processor is a filter, you don't have to do anything for this step. If it's a source or a sink, change the return value of the isSource() or isSink() method to `true` (but never both).
- Edit the OpenEphysLib file. This file allows the GUI to obtain information about the plugin. Replace the ExampleProcessor.h header with yours, all instances of ExampleProcessor with your processor name, and any other information that might be relevant. The OpenEphysLib.cpp copied from the ExampleProcessor is extensively documented via comments, but more information can be found here.
- Try to build the plugin. At this point, the plugin should compile. If using the default build settings the build process should put your newly created plugin in the same place as all the other plugins, so just running the GUI should load it and let you drag it from the list to the signal chain. If it doesn't, go back and check steps 1-5. Looking at the GUI console output (running it with --console argument on Windows) might give you additional ideas of why it has failed, since it logs every plugin it tries to load at startup.
- Add functionality! This is the fun part. By updating your processor's "process" method, you'll determine how it manipulates incoming data, or introduces new data into the signal chain. Look at the code in existing processors for examples.