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.

330 lines
9.2KB

  1. // demo.cpp
  2. //
  3. // An example STK program that allows voice playback and control of
  4. // most of the STK instruments.
  5. #include "SKINImsg.h"
  6. #include "WvOut.h"
  7. #include "Instrmnt.h"
  8. #include "JCRev.h"
  9. #include "Voicer.h"
  10. #include "Skini.h"
  11. #include "RtAudio.h"
  12. #if defined(__STK_REALTIME__)
  13. #include "Mutex.h"
  14. #endif
  15. // Miscellaneous command-line parsing and instrument allocation
  16. // functions are defined in utilites.cpp ... specific to this program.
  17. #include "utilities.h"
  18. #include <signal.h>
  19. #include <iostream>
  20. #include <algorithm>
  21. #include <cmath>
  22. using std::min;
  23. bool done;
  24. static void finish(int ignore){ done = true; }
  25. using namespace stk;
  26. // The TickData structure holds all the class instances and data that
  27. // are shared by the various processing functions.
  28. struct TickData {
  29. WvOut **wvout;
  30. Instrmnt **instrument;
  31. Voicer *voicer;
  32. JCRev reverb;
  33. Messager messager;
  34. Skini::Message message;
  35. StkFloat volume;
  36. StkFloat t60;
  37. unsigned int nWvOuts;
  38. int nVoices;
  39. int currentVoice;
  40. int channels;
  41. int counter;
  42. bool realtime;
  43. bool settling;
  44. bool haveMessage;
  45. int frequency;
  46. // Default constructor.
  47. TickData()
  48. : wvout(0), instrument(0), voicer(0), volume(1.0), t60(0.75),
  49. nWvOuts(0), nVoices(1), currentVoice(0), channels(2), counter(0),
  50. realtime( false ), settling( false ), haveMessage( false ) {}
  51. };
  52. #define DELTA_CONTROL_TICKS 64 // default sample frames between control input checks
  53. // The processMessage() function encapsulates the handling of control
  54. // messages. It can be easily relocated within a program structure
  55. // depending on the desired scheduling scheme.
  56. void processMessage( TickData* data )
  57. {
  58. register StkFloat value1 = data->message.floatValues[0];
  59. register StkFloat value2 = data->message.floatValues[1];
  60. // If only one instrument, allow messages from all channels to control it.
  61. //int group = 1;
  62. // if ( data->nVoices > 1 ) group = data->message.channel;
  63. switch( data->message.type ) {
  64. case __SK_Exit_:
  65. if ( data->settling == false ) goto settle;
  66. done = true;
  67. return;
  68. case __SK_NoteOn_:
  69. if ( value2 > 0.0 ) { // velocity > 0
  70. data->voicer->noteOn( value1, value2 );
  71. break;
  72. }
  73. // else a note off, so continue to next case
  74. case __SK_NoteOff_:
  75. data->voicer->noteOff( value1, value2 );
  76. break;
  77. case __SK_ControlChange_:
  78. if (value1 == 44.0)
  79. data->reverb.setEffectMix(value2 * ONE_OVER_128);
  80. else if (value1 == 7.0)
  81. data->volume = value2 * ONE_OVER_128;
  82. else if (value1 == 49.0)
  83. data->voicer->setFrequency( value2 );
  84. else if (value1 == 50.0)
  85. data->voicer->controlChange( 128, value2 );
  86. else if (value1 == 51.0)
  87. data->frequency = data->message.intValues[1];
  88. else if (value1 == 52.0) {
  89. data->frequency += ( data->message.intValues[1] << 7 );
  90. // Convert to a fractional MIDI note value
  91. StkFloat note = 12.0 * log( data->frequency / 220.0 ) / log( 2.0 ) + 57.0;
  92. data->voicer->setFrequency( note );
  93. }
  94. else
  95. data->voicer->controlChange( (int) value1, value2 );
  96. break;
  97. case __SK_AfterTouch_:
  98. data->voicer->controlChange( 128, value1 );
  99. break;
  100. case __SK_PitchChange_:
  101. data->voicer->setFrequency( value1 );
  102. break;
  103. case __SK_PitchBend_:
  104. data->voicer->pitchBend( value1 );
  105. break;
  106. case __SK_Volume_:
  107. data->volume = value1 * ONE_OVER_128;
  108. break;
  109. case __SK_ProgramChange_:
  110. if ( data->currentVoice == (int) value1 ) break;
  111. // Two-stage program change process.
  112. if ( data->settling == false ) goto settle;
  113. // Stage 2: delete and reallocate new voice(s)
  114. for ( int i=0; i<data->nVoices; i++ ) {
  115. data->voicer->removeInstrument( data->instrument[i] );
  116. delete data->instrument[i];
  117. data->currentVoice = voiceByNumber( (int)value1, &data->instrument[i] );
  118. if ( data->currentVoice < 0 )
  119. data->currentVoice = voiceByNumber( 0, &data->instrument[i] );
  120. data->voicer->addInstrument( data->instrument[i] );
  121. data->settling = false;
  122. }
  123. } // end of switch
  124. data->haveMessage = false;
  125. return;
  126. settle:
  127. // Exit and program change messages are preceeded with a short settling period.
  128. data->voicer->silence();
  129. data->counter = (int) (0.3 * data->t60 * Stk::sampleRate());
  130. data->settling = true;
  131. }
  132. // The tick() function handles sample computation and scheduling of
  133. // control updates. If doing realtime audio output, it will be called
  134. // automatically when the system needs a new buffer of audio samples.
  135. int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
  136. double streamTime, RtAudioStreamStatus status, void *dataPointer )
  137. {
  138. TickData *data = (TickData *) dataPointer;
  139. register StkFloat sample, *samples = (StkFloat *) outputBuffer;
  140. int counter, nTicks = (int) nBufferFrames;
  141. while ( nTicks > 0 && !done ) {
  142. if ( !data->haveMessage ) {
  143. data->messager.popMessage( data->message );
  144. if ( data->message.type > 0 ) {
  145. data->counter = (long) (data->message.time * Stk::sampleRate());
  146. data->haveMessage = true;
  147. }
  148. else
  149. data->counter = DELTA_CONTROL_TICKS;
  150. }
  151. counter = min( nTicks, data->counter );
  152. data->counter -= counter;
  153. for ( int i=0; i<counter; i++ ) {
  154. sample = data->volume * data->reverb.tick( data->voicer->tick() );
  155. for ( unsigned int j=0; j<data->nWvOuts; j++ ) data->wvout[j]->tick(sample);
  156. if ( data->realtime )
  157. for ( int k=0; k<data->channels; k++ ) *samples++ = sample;
  158. nTicks--;
  159. }
  160. if ( nTicks == 0 ) break;
  161. // Process control messages.
  162. if ( data->haveMessage ) processMessage( data );
  163. }
  164. return 0;
  165. }
  166. int main( int argc, char *argv[] )
  167. {
  168. TickData data;
  169. int i;
  170. #if defined(__STK_REALTIME__)
  171. RtAudio dac;
  172. #endif
  173. // If you want to change the default sample rate (set in Stk.h), do
  174. // it before instantiating any objects! If the sample rate is
  175. // specified in the command line, it will override this setting.
  176. Stk::setSampleRate( 44100.0 );
  177. // Depending on how you compile STK, you may need to explicitly set
  178. // the path to the rawwave directory.
  179. Stk::setRawwavePath( "../../rawwaves/" );
  180. // By default, warning messages are not printed. If we want to see
  181. // them, we need to specify that here.
  182. Stk::showWarnings( true );
  183. // Check the command-line arguments for errors and to determine
  184. // the number of WvOut objects to be instantiated (in utilities.cpp).
  185. data.nWvOuts = checkArgs( argc, argv );
  186. data.wvout = (WvOut **) calloc( data.nWvOuts, sizeof(WvOut *) );
  187. // Instantiate the instrument(s) type from the command-line argument
  188. // (in utilities.cpp).
  189. data.nVoices = countVoices( argc, argv );
  190. data.instrument = (Instrmnt **) calloc( data.nVoices, sizeof(Instrmnt *) );
  191. data.currentVoice = voiceByName( argv[1], &data.instrument[0] );
  192. if ( data.currentVoice < 0 ) {
  193. free( data.wvout );
  194. free( data.instrument );
  195. usage(argv[0]);
  196. }
  197. // If there was no error allocating the first voice, we should be fine for more.
  198. for ( i=1; i<data.nVoices; i++ )
  199. voiceByName( argv[1], &data.instrument[i] );
  200. data.voicer = (Voicer *) new Voicer( 0.0 );
  201. for ( i=0; i<data.nVoices; i++ )
  202. data.voicer->addInstrument( data.instrument[i] );
  203. // Parse the command-line flags, instantiate WvOut objects, and
  204. // instantiate the input message controller (in utilities.cpp).
  205. try {
  206. data.realtime = parseArgs( argc, argv, data.wvout, data.messager );
  207. }
  208. catch (StkError &) {
  209. goto cleanup;
  210. }
  211. // If realtime output, allocate the dac here.
  212. #if defined(__STK_REALTIME__)
  213. if ( data.realtime ) {
  214. RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
  215. RtAudio::StreamParameters parameters;
  216. parameters.deviceId = dac.getDefaultOutputDevice();
  217. parameters.nChannels = data.channels;
  218. unsigned int bufferFrames = RT_BUFFER_SIZE;
  219. try {
  220. dac.openStream( &parameters, NULL, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&data );
  221. }
  222. catch ( RtAudioError& error ) {
  223. error.printMessage();
  224. goto cleanup;
  225. }
  226. }
  227. #endif
  228. // Set the reverb parameters.
  229. data.reverb.setT60( data.t60 );
  230. data.reverb.setEffectMix(0.2);
  231. // Install an interrupt handler function.
  232. (void) signal(SIGINT, finish);
  233. // If realtime output, set our callback function and start the dac.
  234. #if defined(__STK_REALTIME__)
  235. if ( data.realtime ) {
  236. try {
  237. dac.startStream();
  238. }
  239. catch ( RtAudioError &error ) {
  240. error.printMessage();
  241. goto cleanup;
  242. }
  243. }
  244. #endif
  245. // Setup finished.
  246. while ( !done ) {
  247. #if defined(__STK_REALTIME__)
  248. if ( data.realtime )
  249. // Periodically check "done" status.
  250. Stk::sleep( 200 );
  251. else
  252. #endif
  253. // Call the "tick" function to process data.
  254. tick( NULL, NULL, 256, 0, 0, (void *)&data );
  255. }
  256. // Shut down the output stream.
  257. #if defined(__STK_REALTIME__)
  258. if ( data.realtime ) {
  259. try {
  260. dac.closeStream();
  261. }
  262. catch ( RtAudioError& error ) {
  263. error.printMessage();
  264. }
  265. }
  266. #endif
  267. cleanup:
  268. for ( i=0; i<(int)data.nWvOuts; i++ ) delete data.wvout[i];
  269. free( data.wvout );
  270. delete data.voicer;
  271. for ( i=0; i<data.nVoices; i++ ) delete data.instrument[i];
  272. free( data.instrument );
  273. std::cout << "\nStk demo finished ... goodbye.\n\n";
  274. return 0;
  275. }