|
- /************** Effects Program *********************/
-
- #include "Skini.h"
- #include "SKINImsg.h"
- #include "Envelope.h"
- #include "PRCRev.h"
- #include "JCRev.h"
- #include "NRev.h"
- #include "FreeVerb.h"
- #include "Echo.h"
- #include "PitShift.h"
- #include "LentPitShift.h"
- #include "Chorus.h"
- #include "Messager.h"
- #include "RtAudio.h"
-
- #include <signal.h>
- #include <cstring>
- #include <iostream>
- #include <algorithm>
- using std::min;
-
- using namespace stk;
-
- void usage(void) {
- // Error function in case of incorrect command-line argument specifications
- std::cout << "\nuseage: effects flags \n";
- std::cout << " where flag = -s RATE to specify a sample rate,\n";
- std::cout << " flag = -ip for realtime SKINI input by pipe\n";
- std::cout << " (won't work under Win95/98),\n";
- std::cout << " and flag = -is <port> for realtime SKINI input by socket.\n";
- exit(0);
- }
-
- bool done;
- static void finish(int ignore){ done = true; }
-
- // The TickData structure holds all the class instances and data that
- // are shared by the various processing functions.
- struct TickData {
- unsigned int effectId;
- PRCRev prcrev;
- JCRev jcrev;
- NRev nrev;
- FreeVerb frev;
- Echo echo;
- PitShift shifter;
- LentPitShift lshifter;
- Chorus chorus;
- Envelope envelope;
- Messager messager;
- Skini::Message message;
- StkFloat lastSample;
- StkFloat t60;
- int counter;
- bool settling;
- bool haveMessage;
-
- // Default constructor.
- TickData()
- : effectId(0), t60(1.0), counter(0),
- settling( false ), haveMessage( false ) {}
- };
-
- #define DELTA_CONTROL_TICKS 64 // default sample frames between control input checks
-
- // The processMessage() function encapsulates the handling of control
- // messages. It can be easily relocated within a program structure
- // depending on the desired scheduling scheme.
- void processMessage( TickData* data )
- {
- register unsigned int value1 = data->message.intValues[0];
- register StkFloat value2 = data->message.floatValues[1];
- register StkFloat temp = value2 * ONE_OVER_128;
-
- switch( data->message.type ) {
-
- case __SK_Exit_:
- if ( data->settling == false ) goto settle;
- done = true;
- return;
-
- case __SK_NoteOn_:
- if ( value2 == 0.0 ) // velocity is zero ... really a NoteOff
- data->envelope.setTarget( 0.0 );
- else // a NoteOn
- data->envelope.setTarget( 1.0 );
- break;
-
- case __SK_NoteOff_:
- data->envelope.setTarget( 0.0 );
- break;
-
- case __SK_ControlChange_:
- // Change all effect values so they are "synched" to the interface.
- switch ( value1 ) {
-
- case 20: { // effect type change
- int type = data->message.intValues[1];
- data->effectId = (unsigned int) type;
- break;
- }
-
- case 22: // effect parameter change 1
- data->echo.setDelay( (unsigned long) (temp * Stk::sampleRate() * 0.95) );
- data->lshifter.setShift( 1.4 * temp + 0.3 );
- data->shifter.setShift( 1.4 * temp + 0.3 );
- data->chorus.setModFrequency( temp );
- data->prcrev.setT60( temp * 10.0 );
- data->jcrev.setT60( temp * 10.0 );
- data->nrev.setT60( temp * 10.0 );
- data->frev.setDamping( temp );
- break;
-
- case 23: // effect parameter change 2
- data->chorus.setModDepth( temp * 0.2 );
- data->frev.setRoomSize( temp );
- break;
-
- case 44: // effect mix
- data->echo.setEffectMix( temp );
- data->shifter.setEffectMix( temp );
- data->lshifter.setEffectMix( temp );
- data->chorus.setEffectMix( temp );
- data->prcrev.setEffectMix( temp );
- data->jcrev.setEffectMix( temp );
- data->nrev.setEffectMix( temp );
- data->frev.setEffectMix( temp );
- break;
-
- default:
- break;
- }
-
- } // end of type switch
-
- data->haveMessage = false;
- return;
-
- settle:
- // Exit and program change messages are preceeded with a short settling period.
- data->envelope.setTarget( 0.0 );
- data->counter = (int) (0.3 * data->t60 * Stk::sampleRate());
- data->settling = true;
- }
-
- // The tick() function handles sample computation and scheduling of
- // control updates. It will be called automatically by RtAudio when
- // the system needs a new buffer of audio samples.
- int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
- double streamTime, RtAudioStreamStatus status, void *dataPointer )
- {
- TickData *data = (TickData *) dataPointer;
- register StkFloat *oSamples = (StkFloat *) outputBuffer, *iSamples = (StkFloat *) inputBuffer;
- register StkFloat sample;
- Effect *effect;
- int i, counter, nTicks = (int) nBufferFrames;
-
- while ( nTicks > 0 && !done ) {
-
- if ( !data->haveMessage ) {
- data->messager.popMessage( data->message );
- if ( data->message.type > 0 ) {
- data->counter = (long) (data->message.time * Stk::sampleRate());
- data->haveMessage = true;
- }
- else
- data->counter = DELTA_CONTROL_TICKS;
- }
-
- counter = min( nTicks, data->counter );
- data->counter -= counter;
- for ( i=0; i<counter; i++ ) {
- if ( data->effectId < 3 ) { // Echo, PitShift and LentPitShift ... mono output
- if ( data->effectId == 0 )
- sample = data->envelope.tick() * data->echo.tick( *iSamples++ );
- else if ( data->effectId == 1 )
- sample = data->envelope.tick() * data->shifter.tick( *iSamples++ );
- else
- sample = data->envelope.tick() * data->lshifter.tick( *iSamples++ );
- *oSamples++ = sample; // two channels interleaved
- *oSamples++ = sample;
- }
- else { // Chorus or a reverb ... stereo output
- if ( data->effectId == 3 ) {
- data->chorus.tick( *iSamples++ );
- effect = (Effect *) &(data->chorus);
- }
- else if ( data->effectId == 4 ) {
- data->prcrev.tick( *iSamples++ );
- effect = (Effect *) &(data->prcrev);
- }
- else if ( data->effectId == 5 ) {
- data->jcrev.tick( *iSamples++ );
- effect = (Effect *) &(data->jcrev);
- }
- else if ( data->effectId == 6 ) {
- data->nrev.tick( *iSamples++ );
- effect = (Effect *) &(data->nrev);
- }
- else {
- data->frev.tick( *iSamples++ );
- effect = (Effect *) &(data->frev);
- }
- const StkFrames& samples = effect->lastFrame();
- *oSamples++ = data->envelope.tick() * samples[0];
- *oSamples++ = data->envelope.lastOut() * samples[1];
- }
- nTicks--;
- }
- if ( nTicks == 0 ) break;
-
- // Process control messages.
- if ( data->haveMessage ) processMessage( data );
- }
-
- return 0;
- }
-
- int main( int argc, char *argv[] )
- {
- TickData data;
- RtAudio adac;
- int i;
-
- if ( argc < 2 || argc > 6 ) usage();
-
- // If you want to change the default sample rate (set in Stk.h), do
- // it before instantiating any objects! If the sample rate is
- // specified in the command line, it will override this setting.
- Stk::setSampleRate( 44100.0 );
-
- // Parse the command-line arguments.
- unsigned int port = 2001;
- for ( i=1; i<argc; i++ ) {
- if ( !strcmp( argv[i], "-is" ) ) {
- if ( i+1 < argc && argv[i+1][0] != '-' ) port = atoi(argv[++i]);
- data.messager.startSocketInput( port );
- }
- else if (!strcmp( argv[i], "-ip" ) )
- data.messager.startStdInput();
- else if ( !strcmp( argv[i], "-s" ) && ( i+1 < argc ) && argv[i+1][0] != '-')
- Stk::setSampleRate( atoi(argv[++i]) );
- else
- usage();
- }
-
- // Allocate the adac here.
- RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
- RtAudio::StreamParameters oparameters, iparameters;
- oparameters.deviceId = adac.getDefaultOutputDevice();
- oparameters.nChannels = 2;
- iparameters.deviceId = adac.getDefaultInputDevice();
- iparameters.nChannels = 1;
- unsigned int bufferFrames = RT_BUFFER_SIZE;
- try {
- adac.openStream( &oparameters, &iparameters, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&data );
- }
- catch ( RtAudioError& error ) {
- error.printMessage();
- goto cleanup;
- }
-
- data.envelope.setRate( 0.001 );
-
- // Install an interrupt handler function.
- (void) signal( SIGINT, finish );
-
- // If realtime output, set our callback function and start the dac.
- try {
- adac.startStream();
- }
- catch ( RtAudioError &error ) {
- error.printMessage();
- goto cleanup;
- }
-
- // Setup finished.
- while ( !done ) {
- // Periodically check "done" status.
- Stk::sleep( 50 );
- }
-
- // Shut down the output stream.
- try {
- adac.closeStream();
- }
- catch ( RtAudioError& error ) {
- error.printMessage();
- }
-
- cleanup:
-
- std::cout << "\neffects finished ... goodbye.\n\n";
- return 0;
- }
|