You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
4.4KB

  1. // threebees.cpp STK tutorial program
  2. #include "BeeThree.h"
  3. #include "RtAudio.h"
  4. #include "Messager.h"
  5. #include "Voicer.h"
  6. #include "SKINImsg.h"
  7. #include <algorithm>
  8. using std::min;
  9. using namespace stk;
  10. // The TickData structure holds all the class instances and data that
  11. // are shared by the various processing functions.
  12. struct TickData {
  13. Voicer voicer;
  14. Messager messager;
  15. Skini::Message message;
  16. int counter;
  17. bool haveMessage;
  18. bool done;
  19. // Default constructor.
  20. TickData()
  21. : counter(0), haveMessage(false), done( false ) {}
  22. };
  23. #define DELTA_CONTROL_TICKS 64 // default sample frames between control input checks
  24. // The processMessage() function encapsulates the handling of control
  25. // messages. It can be easily relocated within a program structure
  26. // depending on the desired scheduling scheme.
  27. void processMessage( TickData* data )
  28. {
  29. register StkFloat value1 = data->message.floatValues[0];
  30. register StkFloat value2 = data->message.floatValues[1];
  31. switch( data->message.type ) {
  32. case __SK_Exit_:
  33. data->done = true;
  34. return;
  35. case __SK_NoteOn_:
  36. if ( value2 == 0.0 ) // velocity is zero ... really a NoteOff
  37. data->voicer.noteOff( value1, 64.0 );
  38. else { // a NoteOn
  39. data->voicer.noteOn( value1, value2 );
  40. }
  41. break;
  42. case __SK_NoteOff_:
  43. data->voicer.noteOff( value1, value2 );
  44. break;
  45. case __SK_ControlChange_:
  46. data->voicer.controlChange( (int) value1, value2 );
  47. break;
  48. case __SK_AfterTouch_:
  49. data->voicer.controlChange( 128, value1 );
  50. case __SK_PitchChange_:
  51. data->voicer.setFrequency( value1 );
  52. break;
  53. case __SK_PitchBend_:
  54. data->voicer.pitchBend( value1 );
  55. } // end of switch
  56. data->haveMessage = false;
  57. return;
  58. }
  59. // This tick() function handles sample computation and scheduling of
  60. // control updates. It will be called automatically when the system
  61. // needs a new buffer of audio samples.
  62. int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
  63. double streamTime, RtAudioStreamStatus status, void *dataPointer )
  64. {
  65. TickData *data = (TickData *) dataPointer;
  66. register StkFloat *samples = (StkFloat *) outputBuffer;
  67. int counter, nTicks = (int) nBufferFrames;
  68. while ( nTicks > 0 && !data->done ) {
  69. if ( !data->haveMessage ) {
  70. data->messager.popMessage( data->message );
  71. if ( data->message.type > 0 ) {
  72. data->counter = (long) (data->message.time * Stk::sampleRate());
  73. data->haveMessage = true;
  74. }
  75. else
  76. data->counter = DELTA_CONTROL_TICKS;
  77. }
  78. counter = min( nTicks, data->counter );
  79. data->counter -= counter;
  80. for ( int i=0; i<counter; i++ ) {
  81. *samples++ = data->voicer.tick();
  82. nTicks--;
  83. }
  84. if ( nTicks == 0 ) break;
  85. // Process control messages.
  86. if ( data->haveMessage ) processMessage( data );
  87. }
  88. return 0;
  89. }
  90. int main()
  91. {
  92. // Set the global sample rate and rawwave path before creating class instances.
  93. Stk::setSampleRate( 44100.0 );
  94. Stk::setRawwavePath( "../../rawwaves/" );
  95. int i;
  96. TickData data;
  97. RtAudio dac;
  98. Instrmnt *instrument[3];
  99. for ( i=0; i<3; i++ ) instrument[i] = 0;
  100. // Figure out how many bytes in an StkFloat and setup the RtAudio stream.
  101. RtAudio::StreamParameters parameters;
  102. parameters.deviceId = dac.getDefaultOutputDevice();
  103. parameters.nChannels = 1;
  104. RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
  105. unsigned int bufferFrames = RT_BUFFER_SIZE;
  106. try {
  107. dac.openStream( &parameters, NULL, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&data );
  108. }
  109. catch ( RtAudioError &error ) {
  110. error.printMessage();
  111. goto cleanup;
  112. }
  113. try {
  114. // Define and load the BeeThree instruments
  115. for ( i=0; i<3; i++ )
  116. instrument[i] = new BeeThree();
  117. }
  118. catch ( StkError & ) {
  119. goto cleanup;
  120. }
  121. // "Add" the instruments to the voicer.
  122. for ( i=0; i<3; i++ )
  123. data.voicer.addInstrument( instrument[i] );
  124. if ( data.messager.startStdInput() == false )
  125. goto cleanup;
  126. try {
  127. dac.startStream();
  128. }
  129. catch ( RtAudioError &error ) {
  130. error.printMessage();
  131. goto cleanup;
  132. }
  133. // Block waiting until callback signals done.
  134. while ( !data.done )
  135. Stk::sleep( 100 );
  136. // Shut down the callback and output stream.
  137. try {
  138. dac.closeStream();
  139. }
  140. catch ( RtAudioError &error ) {
  141. error.printMessage();
  142. }
  143. cleanup:
  144. for ( i=0; i<3; i++ ) delete instrument[i];
  145. return 0;
  146. }