/******************************************/ /* playsaw.cpp by Gary P. Scavone, 2006 This program will output sawtooth waveforms of different frequencies on each channel. */ /******************************************/ #include "RtAudio.h" #include #include #include #include #include #include #include #include "UGens.h" #include "RtMidi.h" using namespace std; typedef double SAMPLE; #define FORMAT RTAUDIO_FLOAT64 #define SCALE 1.0 #define BASE_RATE 0.005 #define TIME 1.0 #define CHANNELS 1 #define PI 3.14159265358979 #define SAMPLE_RATE 44100 #define NOT_IMPLEMENTED cout << "Not implemented!\n"; exit(-1) RtAudio::StreamOptions g_options; KarplusPatch** strings; #define NOTE_ON 144 void usage_and_exit() { cout << "usage:\n\n"; exit(0); } void midi_callback( double deltatime, std::vector< unsigned char > *message, void *userData ) { unsigned int nBytes = message->size(); for ( unsigned int i=0; i 0 ) std::cout << "stamp = " << deltatime << std::endl; if (message->at(0) == NOTE_ON) { cout << "sending midi " << (int)message->at(1) << endl; int index = (int)message->at(1) - 57; if (index < 0 || index > 15) return; strings[index]->pluck(); } } int audio_callback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void* user_data) { SAMPLE * obuffy = (SAMPLE *)outputBuffer; // discard the input //SAMPLE * ibuffy = (SAMPLE *)inputBuffer; for( unsigned i = 0; i < nBufferFrames; i++ ) { // sum up the result of passing a sample through each synth // (yeah, this is horribly inefficient) obuffy[i] = 0; for (int j = 0; j < 16; j++) { obuffy[i] += strings[j]->sendSample(0); } // clipping //if (obuffy[i] > 1) obuffy[i] = 1; //if (obuffy[i] < -1) obuffy[i] = -1; } return 0; } int stream_audio() { unsigned int buffer_frames, offset = 0; RtAudio dac; if ( dac.getDeviceCount() < 1 ) { std::cout << "No audio devices found!\n"; exit( 1 ); } // Let RtAudio print messages to stderr. dac.showWarnings( true ); // send one sample through the audio patch // // obuffy[i] = patch->sendSample(ibuffy[i]); buffer_frames = 512; RtAudio::StreamParameters iParams; iParams.deviceId = dac.getDefaultInputDevice(); iParams.nChannels = CHANNELS; iParams.firstChannel = offset; RtAudio::StreamParameters oParams; oParams.deviceId = dac.getDefaultOutputDevice(); oParams.nChannels = CHANNELS; oParams.firstChannel = offset; try { dac.openStream( &oParams, &iParams, FORMAT, SAMPLE_RATE, &buffer_frames, audio_callback, NULL, &g_options ); dac.startStream(); } catch ( RtError& e ) { e.printMessage(); goto cleanup; } char input; //std::cout << "Stream latency = " << dac.getStreamLatency() << "\n" << std::endl; cout << "Playing ... press to quit. (buffer size = " << buffer_frames << ")\n"; std::cin.get( input ); try { dac.stopStream(); } catch ( RtError& e ) { e.printMessage(); } cleanup: if ( dac.isStreamOpen() ) dac.closeStream(); return 0; } void init_midi(int port) { RtMidiIn *midiin = 0; // warning memory leak // RtMidiIn constructor try { midiin = new RtMidiIn(); } catch ( RtError &error ) { error.printMessage(); exit( EXIT_FAILURE ); } try { midiin->openPort( port ); } catch ( RtError &error ) { error.printMessage(); exit( EXIT_FAILURE ); } // Set our callback function. This should be done immediately after // opening the port to avoid having incoming messages written to the // queue instead of sent to the callback function. midiin->setCallback( &midi_callback ); // Don't ignore sysex, timing, or active sensing messages. midiin->ignoreTypes( false, false, false ); std::cout << "\nReading MIDI input ...\n"; } int main( int argc, char* argv[] ) { cout << "\n=== Karplus Synth ===\n\n"; // set up patch srand(time(NULL)); strings = new KarplusPatch*[16]; for (int i = 0; i < 16; i++) { strings[i] = new KarplusPatch(110 * pow(2, double(i)/12)); } init_midi(0); return stream_audio(); }