Music 3SI

Week 2 Online Tutorial

Introduction to Audio/Multimedia Application Programming


Announcements  |  Course Info  |  Weekly Schedule  |  Tutorials  |  Links

Week 2 Online Tutorial: Stk Programming (1)

This is the very first tutorial of Stk programming. It contains the example codes covered in class, as well as brief instructions for installing/using Stk.

0. Stk for Music 3SI

Your Mac

For this course, you need to have Apple's Xcode IDE and developer tools installed on your machine. Version 2.2.1 (the latest one as of 4/15/2006) is recommended, and can be downloaded from here (Xcode 2.2.1 (DMG)).
I also highly recommend that you install StkX (with Stk, of course). This is a framework for OS X, and will make your Stk programming easier. Here's an StkX Express Setup Guide:
  1. Download stk-4.2.1+StkX.zip, which contains Stk 4.2.1 sources and StkX files. Unzip it onto your Desktop.
  2. Open up a Terminal and go to the StkX directory (stk-4.2.1+StkX/StkX/)
  3. Run the following command:
    % sudo xcodebuild install -target StkX -configuration Release DSTROOT=/ INSTALL_PATH=/Library/Frameworks/ DEPLOYMENT_LOCATION=YES
    If necessary, type in your password when asked.
  4. Installation will be complete in a couple of minutes. You can then remove the stk-4.2.1+StkX.zip file and its unzipped folder.

CCRMA machines

Mac minis and Linux boxes at CCRMA are ready for Music 3SI. If you have any question working on any of them, please tell the instructor.

1. Generating Audio Samples

ex1.cpp generates 44,100 samples of a sine wave (440.0 [Hz]) and prints out their values. Note that we included math header to compute sine function.
ex1.cpp [download]
// Generates 44,100 samples of a sine wave
#include <iostream>
#include <math.h>

int main (int argc, char* const argv[]) {
  for ( int i=0; i<44100; i++ ) {
    float y = sin( 2 * M_PI * 440.0 * i / 44100.0 );
      std::cout << "y[" << i << "] = " << y << std::endl;
    }
  return 0;
}

Compiling

To compile ex1.cpp using terminal, type the following command (in the same directory). Here, ex1 is the name of the executable file.
g++ -g -o ex1 ex1.cpp

2. Saving Audio Samples to File

Once we have smaple data, we can save them as a sound file using Stk's FileWvOut class..
ex2.cpp [download]
// Saves 1[s] sine wave as "sine.wav"
#include "FileWvOut.h"
#include <math.h>

int main (int argc, char* const argv[]) {
  Stk::setSampleRate( 44100.0 );	// Global sample rate
  FileWvOut output;		// FileWvOut: save to file
  // Open a 16-bit, one-channel WAV formatted output file
  output.openFile( "sine.wav", 1, FileWrite::FILE_WAV, Stk::STK_SINT16 );

  for ( int i=0; i<44100; i++ ) {
    StkFloat y = sin( 2 * M_PI * 440.0 * i / 44100.0 );
    output.tick( y );
  }
  return 0;
}
[Tip]: a sawtooth wave can be generated in the following way (obviously you do not need the math header for this).
  for ( int i=0; i<44100; i++ ) {
    // Compute sawtooth wave data (440.0 [Hz])
    y = ( y >= 1.0 ? -1.0 : y + 2.0/(44100.0/440.0) );
    output.tick( y );
  }

StkX header

Generally, to use any Stk classes, it is necessary to include the corresponding header(s) (see FileWvOut.h above, for example): this must be done for every class you instantiate.
On OS X with StkX, however, you just need to include one StkX framework header StkX/StkX.h. Therefore, the headers of ex2.cpp should be like the following when used with StkX.
#include <StkX/StkX.h>
#include <math.h>

Compiling

On CCRMA Linux machines, you can use the stk headers under /usr/include/stk and pre-compiled stk static library (/usr/lib/libstk.a).
g++ -g -o ex2_sine ex2_sine.cpp -I/usr/include/stk -lstk
On the other hand, Mac OS X with StkX will require the framework name instead of the header and library info.
g++ -g -o ex2_sine ex2_sine.cpp -framework StkX

3. Wave Files As Sound Sources

Instead of computed sample data, sound files can be used as the sound source: check FileWvIn, WaveLoop, and SineWave classes.
ex3.cpp [download]
// Saves 1[s] sine wave as "sine.wav" / uses "SineWave" class.
#include "SineWave.h"
#include "FileWvOut.h"

int main (int argc, char* const argv[]) {
  Stk::setSampleRate( 44100.0 );

  SineWave sine;	// SineWave: sine wave generator
  sine.setFrequency( 440.0 );	// Set the frequency of "sine"

  FileWvOut output;
  output.openFile( "sine.wav", 1, FileWrite::FILE_WAV, Stk::STK_SINT16 );

  for ( int i=0; i<44100; i++ )
    output.tick( sine.tick() );

  return 0;
}
Again, on OS X with StkX, the headers of ex3.cpp should be replaced by this single line.
#include <StkX/StkX.h>

Command-line arguments

ex4.cpp shows how to take command-line arguments and use them as variable values. Also note the use of WaveLoop class.
ex4.cpp [download]
// Saves a sound sample file (arg. #1) looped at certain frequency (arg. #2 [Hz])
// as a wave file (arg. #3)
#include "WaveLoop.h"
#include "FileWvOut.h"

int main (int argc, char* const argv[]) {
  // Take command-line arguments
  char* waveInName = argv[1];		// First: input wavefile
  float frequency = atof( argv[2] );	// Second: frequency
  char* waveOutName = argv[3];		// Third: output wavefile

  Stk::setSampleRate( 44100.0 );

  WaveLoop input;	// WaveLoop class: wave player
  input.openFile( Stk::rawwavePath() + waveInName, true );
  input.setFrequency( frequency );
	
  FileWvOut output;
  output.openFile( waveOutName, 1, FileWrite::FILE_WAV, Stk::STK_SINT16 );

  for ( int i=0; i<44100; i++ )
    output.tick( input.tick() );

  return 0;
}
An example of running ex4 would be:
./ex4 sinewave.raw 440.0 sine.wav

4. Realtime I/O

Use RtWvIn and RtWvOut for realtime audio input from ADC (ex6.cpp) and output to DAC (ex5.cpp), respectively.
ex5.cpp [download]
// Loops a sound sample file (arg. #1) at certain frequency (arg. #2 [Hz]) to DAC
// for a given duration (arg. #3 [s])
#include "WaveLoop.h"
#include "RtWvOut.h"

int main (int argc, char* const argv[]) {
  char* waveInName = argv[1];
  float frequency = atof( argv[2] );
  float length = atof ( argv[3] );

  Stk::setSampleRate( 44100.0 );

  WaveLoop input;
  input.openFile( Stk::rawwavePath() + waveInName, true );
  input.setFrequency( frequency );

  RtWvOut dac;	// RtWvOut: realtime output to DAC

  for ( int i=0; i<(44100*length); i++ )
    dac.tick( input.tick() );

  return 0;
}
ex6.cpp [download]
// Takes ADC input for a given duration (arg. #2 [s])
// and saves it as a wave file (arg. #1)
#include "RtWvIn.h"
#include "FileWvOut.h"

int main (int argc, char* const argv[]) {
  char* waveOutName = argv[1];
  float length = atof ( argv[2] );

  Stk::setSampleRate( 44100.0 );

  RtWvIn adc;	// RtWvIn: realtime input from ADC

  FileWvOut output;
  output.openFile( waveOutName, 1, FileWrite::FILE_WAV, Stk::STK_SINT16 );

  for ( int i=0; i<(44100*length); i++ )
		output.tick( adc.tick() );

  return 0;
}

Compiling (on CCRMA Linux machines)

To compile Stk with realtime support (RtAudio), we have to use two more libraries - asound and jack.
g++ -g -o ex5 ex5.cpp -I/usr/include/lib -lstk -lasound -ljack

Duplex mode

For duplex mode (which means having realtime input and output simultaneously), you need to use the RtAudio class, which will be explored soon.

5. Callback

Here's the sample code shown in class. Details will be covered next week.
ex7.cpp [download]
// Plays a sine wave (440[Hz]) realtime, stops when "Enter" is pressed.
#include 

#include "sineWave.h"
#include "RtAudio.h"

// Callback function
int tick(char *buffer, int bufferSize, void *dataPointer) {
  SineWave *sine = (SineWave *) dataPointer;
  register StkFloat *samples = (StkFloat *) buffer;

  for ( int i=0; i<bufferSize; i++ )
    *samples++ = sine->tick();

  return 0;
}

int main (int argc, char* const argv[]) {
  Stk::setSampleRate( 44100.0 );

  SineWave* sine;
  sine = new SineWave();
  sine->setFrequency(440.0);

  RtAudio* dac = 0;
  RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
  int bufferSize = RT_BUFFER_SIZE;
  dac = new RtAudio(0, 1, 0, 0, format, (int)Stk::sampleRate(), &bufferSize, 4);
  dac->setStreamCallback(&tick, (void *)sine);
  dac->startStream();

  char keyhit;
  std::cout << "\nPlaying ... press  to quit.\n";
  std::cin.get(keyhit);

  dac->cancelStreamCallback();
  dac->closeStream();

  delete dac;
  delete sine;

  return 0;
}
Announcements  |  Course Info  |  Weekly Schedule  |  Tutorials  |  Links

Music 3SI / Spring 2006 / CCRMA, Stanford University
Woon Seung Yeo
Last updated: Wed, 24 May 2006 15:59:12 -0700