Synthesis ToolKit Introduction:

The Synthesis ToolKit in C++ (STK) is a set of open source audio signal processing and algorithmic synthesis classes written in C++. STK was designed to facilitate rapid development of music synthesis and audio processing software, with an emphasis on cross-platform functionality, realtime control, ease of use, and educational example code. STK currently runs with "realtime" support (audio and MIDI) on Linux, Macintosh OS X, and Windows computer platforms.

In this course, we will make use of STK to gain hands-on experience implementing acoustic and audio algorithms.

Getting Started

Installation and Compiling (Macintosh OS-X)

Inheritance

Nearly all STK classes inherit from the Stk abstract base class, which provides common functionality related to error reporting, sample rate control, and byte swapping. Several other base classes exist that roughly group many of the classes according to function as follows:

A Simple Example

"Ticking"

Audio File Input/Output

STK Filters

Realtime Audio and MIDI Input/Output

Blocking Functionality

Below is an example realtime audio ouput program that uses the RtWvOut class in a blocking context.
// rtsine.cpp STK tutorial program using blocking audio output.

#include "SineWave.h"
#include "RtWvOut.h"

using namespace stk;

int main()
{
  // Set the global sample rate before creating class instances.
  Stk::setSampleRate( 44100.0 );
  Stk::showWarnings( true );
  int nFrames = 100000;

  try {

    SineWave sine;
    // Define and open the default realtime output device for one-channel playback
    RtWvOut dac( 1 );

    sine.setFrequency( 441.0 );

    // Option 1: Use StkFrames
    /*
    StkFrames frames( nFrames, 1 );
    dac.tick( sine.tick( frames ) );
    */

    // Option 2: Single-sample computations
    for ( int i=0; i<nFrames; i++ ) {
      dac.tick( sine.tick() );
    }
  }
  catch ( StkError & ) {
    exit( 1 );
  }

  return 0;
}

This example can be compiled on a Macintosh OS-X system with the following syntax:

g++ -I/Users/me/Desktop/stk/include/ -L/Users/me/Desktop/stk/src/ -D__MACOSX_CORE__ rtsine.cpp -lstk -lpthread -framework CoreAudio -framework CoreMIDI -framework CoreFoundation

Callback Functionality

Below are two examples of realtime audio ouput using the RtAudio class in a callback context.
// rtex1.cpp
//
// Realtime audio output example using callback functionality.

#include "RtAudio.h"
#include <iostream>
#include <cmath>

const double PI     = 3.14159265359;
const double TWO_PI = 2 * PI;
const double frequency = 440.0;
const int sampleRate = 44100;
const double samplePeriod = 1.0 / sampleRate;
const double phaseIncrement = TWO_PI * frequency * samplePeriod;
double phase = 0;

int sin( void *outputBuffer, void *, unsigned int nBufferFrames,
         double, RtAudioStreamStatus, void * )
{
  // Cast the buffer to the correct data type.
  double *my_data = (double *) outputBuffer;

  // We know we only have 1 sample per frame here.
  for ( int i=0; i<nBufferFrames; i++ ) {
    my_data[i] = std::sin( phase );
    phase += phaseIncrement;
    if ( phase > TWO_PI ) phase -= TWO_PI;
  }

  return 0;
}

int main()
{
  unsigned int nBufferFrames = 256;  // 256 sample frames
  unsigned int sampleRate = 44100;
  unsigned int nChannels = 1;
  RtAudio dac;

  // Open the default realtime output device.
  RtAudio::StreamParameters parameters;
  parameters.deviceId = dac.getDefaultOutputDevice();
  parameters.nChannels = nChannels;
  try {
    dac.openStream( &parameters, NULL, RTAUDIO_FLOAT64, sampleRate, &nBufferFrames, &sin );
  }
  catch ( RtAudioError &error ) {
    error.printMessage();
    exit( EXIT_FAILURE );
  }

  try {
    dac.startStream();
  }
  catch ( RtAudioError &error ) {
    error.printMessage();
    exit( EXIT_FAILURE );
  }

  char input;
  std::cin.get( input ); // block until user hits return

  // Stop the stream.
  try {
    dac.stopStream();
  }
  catch ( RtAudioError &error ) {
    error.printMessage();
  }

  return 0;
}

This example can be compiled on a Macintosh OS-X system with the following syntax:

g++ -I/Users/me/Desktop/stk/include/ -L/Users/me/Desktop/stk/src/ -D__MACOSX_CORE__ rtex1.cpp -lstk -lpthread -framework CoreAudio -framework CoreMIDI -framework CoreFoundation

The previous example can be easily modified to take realtime input from a soundcard, pass it through a comb filter, and send it back out to the soundcard as follows:

// rtex2.cpp
//
// Realtime audio input/output example with comb filter using callback functionality.
#include "RtAudio.h"
#include <iostream>
#include "Delay.h"
using namespace stk;

Delay delay;

int comb( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
          double, RtAudioStreamStatus, void * )
{
  // Cast the buffers to the correct data type.
  double *idata = (double *) inputBuffer;
  double *odata = (double *) outputBuffer;

  // We know we only have 1 sample per frame here.
  for ( int i=0; i<nBufferFrames; i++ ) {
    odata[i] = idata[i] + 0.98 * delay.lastOut(); // feedback comb
//    odata[i] = idata[i] + delay.tick( idata[i] ); // feedforward comb
    odata[i] *= 0.45;
    delay.tick( odata[i] );  // feedback comb
  }

  return 0;
}

int main()
{
  unsigned int nBufferFrames = 256;  // 256 sample frames
  unsigned int sampleRate = 44100;
  unsigned int nChannels = 1;
  RtAudio adac;

  delay.setDelay( 1000 );

  // Open the default realtime output device.
  RtAudio::StreamParameters oParameters, iParameters;
  oParameters.deviceId = adac.getDefaultOutputDevice();
  iParameters.deviceId = adac.getDefaultInputDevice();
  oParameters.nChannels = nChannels;
  iParameters.nChannels = nChannels;
  try {
    adac.openStream( &oParameters, &iParameters, RTAUDIO_FLOAT64, sampleRate, &nBufferFrames, &comb );
  }
  catch ( RtAudioError &error ) {
    error.printMessage();
    exit( EXIT_FAILURE );
  }

  try {
    adac.startStream();
  }
  catch ( RtAudioError &error ) {
    error.printMessage();
    exit( EXIT_FAILURE );
  }

  char input;
  std::cin.get( input ); // block until user hits return

  // Stop the stream.
  try {
    adac.stopStream();
  }
  catch ( RtAudioError &error ) {
    error.printMessage();
  }

  return 0;
}

McGill ©2004-2017 McGill University. All Rights Reserved.
Maintained by Gary P. Scavone.