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.

297 lines
8.4KB

  1. /************** Effects Program *********************/
  2. #include "Skini.h"
  3. #include "SKINImsg.h"
  4. #include "Envelope.h"
  5. #include "PRCRev.h"
  6. #include "JCRev.h"
  7. #include "NRev.h"
  8. #include "FreeVerb.h"
  9. #include "Echo.h"
  10. #include "PitShift.h"
  11. #include "LentPitShift.h"
  12. #include "Chorus.h"
  13. #include "Messager.h"
  14. #include "RtAudio.h"
  15. #include <signal.h>
  16. #include <cstring>
  17. #include <iostream>
  18. #include <algorithm>
  19. using std::min;
  20. using namespace stk;
  21. void usage(void) {
  22. // Error function in case of incorrect command-line argument specifications
  23. std::cout << "\nuseage: effects flags \n";
  24. std::cout << " where flag = -s RATE to specify a sample rate,\n";
  25. std::cout << " flag = -ip for realtime SKINI input by pipe\n";
  26. std::cout << " (won't work under Win95/98),\n";
  27. std::cout << " and flag = -is <port> for realtime SKINI input by socket.\n";
  28. exit(0);
  29. }
  30. bool done;
  31. static void finish(int ignore){ done = true; }
  32. // The TickData structure holds all the class instances and data that
  33. // are shared by the various processing functions.
  34. struct TickData {
  35. unsigned int effectId;
  36. PRCRev prcrev;
  37. JCRev jcrev;
  38. NRev nrev;
  39. FreeVerb frev;
  40. Echo echo;
  41. PitShift shifter;
  42. LentPitShift lshifter;
  43. Chorus chorus;
  44. Envelope envelope;
  45. Messager messager;
  46. Skini::Message message;
  47. StkFloat lastSample;
  48. StkFloat t60;
  49. int counter;
  50. bool settling;
  51. bool haveMessage;
  52. // Default constructor.
  53. TickData()
  54. : effectId(0), t60(1.0), counter(0),
  55. settling( false ), haveMessage( false ) {}
  56. };
  57. #define DELTA_CONTROL_TICKS 64 // default sample frames between control input checks
  58. // The processMessage() function encapsulates the handling of control
  59. // messages. It can be easily relocated within a program structure
  60. // depending on the desired scheduling scheme.
  61. void processMessage( TickData* data )
  62. {
  63. register unsigned int value1 = data->message.intValues[0];
  64. register StkFloat value2 = data->message.floatValues[1];
  65. register StkFloat temp = value2 * ONE_OVER_128;
  66. switch( data->message.type ) {
  67. case __SK_Exit_:
  68. if ( data->settling == false ) goto settle;
  69. done = true;
  70. return;
  71. case __SK_NoteOn_:
  72. if ( value2 == 0.0 ) // velocity is zero ... really a NoteOff
  73. data->envelope.setTarget( 0.0 );
  74. else // a NoteOn
  75. data->envelope.setTarget( 1.0 );
  76. break;
  77. case __SK_NoteOff_:
  78. data->envelope.setTarget( 0.0 );
  79. break;
  80. case __SK_ControlChange_:
  81. // Change all effect values so they are "synched" to the interface.
  82. switch ( value1 ) {
  83. case 20: { // effect type change
  84. int type = data->message.intValues[1];
  85. data->effectId = (unsigned int) type;
  86. break;
  87. }
  88. case 22: // effect parameter change 1
  89. data->echo.setDelay( (unsigned long) (temp * Stk::sampleRate() * 0.95) );
  90. data->lshifter.setShift( 1.4 * temp + 0.3 );
  91. data->shifter.setShift( 1.4 * temp + 0.3 );
  92. data->chorus.setModFrequency( temp );
  93. data->prcrev.setT60( temp * 10.0 );
  94. data->jcrev.setT60( temp * 10.0 );
  95. data->nrev.setT60( temp * 10.0 );
  96. data->frev.setDamping( temp );
  97. break;
  98. case 23: // effect parameter change 2
  99. data->chorus.setModDepth( temp * 0.2 );
  100. data->frev.setRoomSize( temp );
  101. break;
  102. case 44: // effect mix
  103. data->echo.setEffectMix( temp );
  104. data->shifter.setEffectMix( temp );
  105. data->lshifter.setEffectMix( temp );
  106. data->chorus.setEffectMix( temp );
  107. data->prcrev.setEffectMix( temp );
  108. data->jcrev.setEffectMix( temp );
  109. data->nrev.setEffectMix( temp );
  110. data->frev.setEffectMix( temp );
  111. break;
  112. default:
  113. break;
  114. }
  115. } // end of type switch
  116. data->haveMessage = false;
  117. return;
  118. settle:
  119. // Exit and program change messages are preceeded with a short settling period.
  120. data->envelope.setTarget( 0.0 );
  121. data->counter = (int) (0.3 * data->t60 * Stk::sampleRate());
  122. data->settling = true;
  123. }
  124. // The tick() function handles sample computation and scheduling of
  125. // control updates. It will be called automatically by RtAudio when
  126. // the system needs a new buffer of audio samples.
  127. int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
  128. double streamTime, RtAudioStreamStatus status, void *dataPointer )
  129. {
  130. TickData *data = (TickData *) dataPointer;
  131. register StkFloat *oSamples = (StkFloat *) outputBuffer, *iSamples = (StkFloat *) inputBuffer;
  132. register StkFloat sample;
  133. Effect *effect;
  134. int i, counter, nTicks = (int) nBufferFrames;
  135. while ( nTicks > 0 && !done ) {
  136. if ( !data->haveMessage ) {
  137. data->messager.popMessage( data->message );
  138. if ( data->message.type > 0 ) {
  139. data->counter = (long) (data->message.time * Stk::sampleRate());
  140. data->haveMessage = true;
  141. }
  142. else
  143. data->counter = DELTA_CONTROL_TICKS;
  144. }
  145. counter = min( nTicks, data->counter );
  146. data->counter -= counter;
  147. for ( i=0; i<counter; i++ ) {
  148. if ( data->effectId < 3 ) { // Echo, PitShift and LentPitShift ... mono output
  149. if ( data->effectId == 0 )
  150. sample = data->envelope.tick() * data->echo.tick( *iSamples++ );
  151. else if ( data->effectId == 1 )
  152. sample = data->envelope.tick() * data->shifter.tick( *iSamples++ );
  153. else
  154. sample = data->envelope.tick() * data->lshifter.tick( *iSamples++ );
  155. *oSamples++ = sample; // two channels interleaved
  156. *oSamples++ = sample;
  157. }
  158. else { // Chorus or a reverb ... stereo output
  159. if ( data->effectId == 3 ) {
  160. data->chorus.tick( *iSamples++ );
  161. effect = (Effect *) &(data->chorus);
  162. }
  163. else if ( data->effectId == 4 ) {
  164. data->prcrev.tick( *iSamples++ );
  165. effect = (Effect *) &(data->prcrev);
  166. }
  167. else if ( data->effectId == 5 ) {
  168. data->jcrev.tick( *iSamples++ );
  169. effect = (Effect *) &(data->jcrev);
  170. }
  171. else if ( data->effectId == 6 ) {
  172. data->nrev.tick( *iSamples++ );
  173. effect = (Effect *) &(data->nrev);
  174. }
  175. else {
  176. data->frev.tick( *iSamples++ );
  177. effect = (Effect *) &(data->frev);
  178. }
  179. const StkFrames& samples = effect->lastFrame();
  180. *oSamples++ = data->envelope.tick() * samples[0];
  181. *oSamples++ = data->envelope.lastOut() * samples[1];
  182. }
  183. nTicks--;
  184. }
  185. if ( nTicks == 0 ) break;
  186. // Process control messages.
  187. if ( data->haveMessage ) processMessage( data );
  188. }
  189. return 0;
  190. }
  191. int main( int argc, char *argv[] )
  192. {
  193. TickData data;
  194. RtAudio adac;
  195. int i;
  196. if ( argc < 2 || argc > 6 ) usage();
  197. // If you want to change the default sample rate (set in Stk.h), do
  198. // it before instantiating any objects! If the sample rate is
  199. // specified in the command line, it will override this setting.
  200. Stk::setSampleRate( 44100.0 );
  201. // Parse the command-line arguments.
  202. unsigned int port = 2001;
  203. for ( i=1; i<argc; i++ ) {
  204. if ( !strcmp( argv[i], "-is" ) ) {
  205. if ( i+1 < argc && argv[i+1][0] != '-' ) port = atoi(argv[++i]);
  206. data.messager.startSocketInput( port );
  207. }
  208. else if (!strcmp( argv[i], "-ip" ) )
  209. data.messager.startStdInput();
  210. else if ( !strcmp( argv[i], "-s" ) && ( i+1 < argc ) && argv[i+1][0] != '-')
  211. Stk::setSampleRate( atoi(argv[++i]) );
  212. else
  213. usage();
  214. }
  215. // Allocate the adac here.
  216. RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
  217. RtAudio::StreamParameters oparameters, iparameters;
  218. oparameters.deviceId = adac.getDefaultOutputDevice();
  219. oparameters.nChannels = 2;
  220. iparameters.deviceId = adac.getDefaultInputDevice();
  221. iparameters.nChannels = 1;
  222. unsigned int bufferFrames = RT_BUFFER_SIZE;
  223. try {
  224. adac.openStream( &oparameters, &iparameters, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&data );
  225. }
  226. catch ( RtAudioError& error ) {
  227. error.printMessage();
  228. goto cleanup;
  229. }
  230. data.envelope.setRate( 0.001 );
  231. // Install an interrupt handler function.
  232. (void) signal( SIGINT, finish );
  233. // If realtime output, set our callback function and start the dac.
  234. try {
  235. adac.startStream();
  236. }
  237. catch ( RtAudioError &error ) {
  238. error.printMessage();
  239. goto cleanup;
  240. }
  241. // Setup finished.
  242. while ( !done ) {
  243. // Periodically check "done" status.
  244. Stk::sleep( 50 );
  245. }
  246. // Shut down the output stream.
  247. try {
  248. adac.closeStream();
  249. }
  250. catch ( RtAudioError& error ) {
  251. error.printMessage();
  252. }
  253. cleanup:
  254. std::cout << "\neffects finished ... goodbye.\n\n";
  255. return 0;
  256. }