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.

177 lines
4.4KB

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