The STK is developed by the Center for Computer Research in Music and Acoustics and has been used in the development of audio processing software for approximately 15 years. The toolkit requires no external library support, making it highly flexible and portable between platforms. The STK comes with a wide variety of code examples based on its popularity for use in education and development. Because of this, I decided that I would analyse the granular synthesis and DSP processing capabilities of the STK first. Using the STK granular synthesis example, I hacked together a working prototype in openFrameworks that enabled me to tweak parameters using a GUI during run-time. I then experimented with combining the output from the granular synthesis with the ToolKits reverb, delay and flange DSP code. Although the resulting prototype contained the required granular synthesis and signal processing, I found the signal processing of the STK lacked the crisp level of sonic detail I was searching for.
Maximillian
The next framework I tested was a recently released audio synthesis library called Maximilian. Maximilian came packaged with a similar collection of signal processing functionality to that of the STK. The library contains a C++ wrapper that integrates with openFrameworks, making it easy to immediately start developing prototypes. Granular synthesis is implemented with multiple methods for utilising various functionalities such as time stretching and pitch shifting. Methods that handle sample loading, playback and looping are also well implemented, making it easy to develop the initial version of the granular synthesis engine for the prototypes. The granular implementation of Maximilian was superior to the STK with respect to the sound produced and the ease of integration within openFrameworks. For this reason I decided to use Maximilian to begin granular synthesis integration within the prototypes. I needed to make my own additions and customisations to the Maximilian code during development to synchronise the granular windowing envelopes with the visual grains. This involved converting local floating-point values to pointers that could be retrieved by reference higher up in the application.
Tonic
Tonic was released in 2013 as a C++ alternative to popular synthesis environments such as Max/MSP, SuperCollider and Pure Data. Tonic lacks sample playback and spectral granular processing, but features an impressive set of synthesis functionalities. I had been using the synthesis functionality of Maximilian for the development of my FM synthesis engine (described later in section 6.1.5), but decided to implement the Tonic-based one instead because of the quality of its sound oscillators. During tests, Tonic seemed to run more efficiently than Maximilian during run-time, making it an
even more attractive option for the FM synthesis component.
After a month of developing an early FM synthesis prototype using Tonic, I intended to start synchronising the audio oscillators with real-time graphics. However, I discovered there were no ‘getter’ methods to retrieve the current value of an oscillator. I contacted the primary developer of Tonic, Morgan Packard, to discuss this issue. He gave the following response to my inquiry:
!
! Tonic by design doesn't output single values. It always operates on buffers of floats. This is much more efficient (though a little more complicated) than sample-at-a-time calculation, which is how Maximilian does it. Eventually, the audio hardware needs buffers of values, not individual values anyway. So somewhere those individual values being output by Maximilian are getting rolled in to a buffer. This stage might be the most logical spot to mix your signals. (Packard, 2013, pers.com)!
Although I had developed a decent-sounding FM synthesis prototype using Tonic, I abandoned it and continued searching for an alternative synthesis library based on Morgan’s confirmation that I would be unable to retrieve the values from Tonic to use for tight graphics synchronisation.
Gamma
The final framework I tested was Gamma. Gamma is a lightweight generic synthesis library that excels in the spectral processing and filtering of audio signals. After downloading Gamma, the user is required to build the source using the ‘make’ command via terminal. Initially, I was unable to progress past this stage and subsequently contacted Lance Putnam, the developer of Gamma, for assistance to compile the source. With Lance’s help I was able to compile Gamma and to test and run the examples via the command line. Of the four synthesis libraries, Gamma was the hardest to integrate with openFrameworks. I was reluctant to use Gamma as the synthesis engine for the prototypes due to the amount of work involved in wrapping the library to be compatible with openFrameworks. Nevertheless, the sound quality of Gamma far surpassed that of Maximilian, STK or Tonic, and Gamma allows one to retrieve the current phase and frequency values of its oscillators. Because of its superior sound quality and ability to replace the missing value retrieval functionality of Tonic, I decided that Gamma would be the ideal library with which to build my FM synthesis engine, while Maximilian would be used to integrate granular synthesis functionality.
Table 3 below highlights the main strengths and weaknesses of each of the four audio synthesis libraries discussed above.
Table 3: Comparison of open source audio synthesis libraries
6.1.3 Technology
As previously noted, Kortex was developed on OSX using openFrameworks (2014). OpenFrameworks is a collection of functional components that help the user achieve specific tasks. It has components that are used to draw 2D and 3D graphics, display images and video, synthesise and play back audio, and interface with low-level APIs. Several open-source libraries were used for the various functionalities of the instrument. They included the Maximilian and Gamma audio synthesis libraries, ofxTimeline for timeline parameter automation, ofxUI for GUI support, and ofxMidi for MIDI controller interfacing.