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.

224 lines
6.3KB

  1. /******************************************/
  2. /*
  3. playsaw.cpp
  4. by Gary P. Scavone, 2006
  5. This program will output sawtooth waveforms
  6. of different frequencies on each channel.
  7. */
  8. /******************************************/
  9. #include "RtAudio.h"
  10. #include <iostream>
  11. #include <cstdlib>
  12. /*
  13. typedef char MY_TYPE;
  14. #define FORMAT RTAUDIO_SINT8
  15. #define SCALE 127.0
  16. */
  17. typedef signed short MY_TYPE;
  18. #define FORMAT RTAUDIO_SINT16
  19. #define SCALE 32767.0
  20. /*
  21. typedef S24 MY_TYPE;
  22. #define FORMAT RTAUDIO_SINT24
  23. #define SCALE 8388607.0
  24. typedef signed long MY_TYPE;
  25. #define FORMAT RTAUDIO_SINT32
  26. #define SCALE 2147483647.0
  27. typedef float MY_TYPE;
  28. #define FORMAT RTAUDIO_FLOAT32
  29. #define SCALE 1.0
  30. typedef double MY_TYPE;
  31. #define FORMAT RTAUDIO_FLOAT64
  32. #define SCALE 1.0
  33. */
  34. // Platform-dependent sleep routines.
  35. #if defined( WIN32 )
  36. #include <windows.h>
  37. #define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds )
  38. #else // Unix variants
  39. #include <unistd.h>
  40. #define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) )
  41. #endif
  42. #define BASE_RATE 0.005
  43. #define TIME 1.0
  44. void usage( void ) {
  45. // Error function in case of incorrect command-line
  46. // argument specifications
  47. std::cout << "\nuseage: playsaw N fs <device> <channelOffset> <time>\n";
  48. std::cout << " where N = number of channels,\n";
  49. std::cout << " fs = the sample rate,\n";
  50. std::cout << " device = optional device to use (default = 0),\n";
  51. std::cout << " channelOffset = an optional channel offset on the device (default = 0),\n";
  52. std::cout << " and time = an optional time duration in seconds (default = no limit).\n\n";
  53. exit( 0 );
  54. }
  55. void errorCallback( RtAudioErrorType /*type*/, const std::string &errorText )
  56. {
  57. // This example error handling function simply outputs the error message to stderr.
  58. std::cerr << "\nerrorCallback: " << errorText << "\n\n";
  59. }
  60. unsigned int channels;
  61. RtAudio::StreamOptions options;
  62. unsigned int frameCounter = 0;
  63. bool checkCount = false;
  64. unsigned int nFrames = 0;
  65. const unsigned int callbackReturnValue = 1; // 1 = stop and drain, 2 = abort
  66. double streamTimePrintIncrement = 1.0; // seconds
  67. double streamTimePrintTime = 1.0; // seconds
  68. #define USE_INTERLEAVED
  69. #if defined( USE_INTERLEAVED )
  70. // Interleaved buffers
  71. int saw( void *outputBuffer, void * /*inputBuffer*/, unsigned int nBufferFrames,
  72. double streamTime, RtAudioStreamStatus status, void *data )
  73. {
  74. unsigned int i, j;
  75. extern unsigned int channels;
  76. MY_TYPE *buffer = (MY_TYPE *) outputBuffer;
  77. double *lastValues = (double *) data;
  78. if ( status )
  79. std::cout << "Stream underflow detected!" << std::endl;
  80. if ( streamTime >= streamTimePrintTime ) {
  81. std::cout << "streamTime = " << streamTime << std::endl;
  82. streamTimePrintTime += streamTimePrintIncrement;
  83. }
  84. for ( i=0; i<nBufferFrames; i++ ) {
  85. for ( j=0; j<channels; j++ ) {
  86. *buffer++ = (MY_TYPE) (lastValues[j] * SCALE * 0.5);
  87. lastValues[j] += BASE_RATE * (j+1+(j*0.1));
  88. if ( lastValues[j] >= 1.0 ) lastValues[j] -= 2.0;
  89. }
  90. }
  91. frameCounter += nBufferFrames;
  92. if ( checkCount && ( frameCounter >= nFrames ) ) return callbackReturnValue;
  93. return 0;
  94. }
  95. #else // Use non-interleaved buffers
  96. int saw( void *outputBuffer, void * /*inputBuffer*/, unsigned int nBufferFrames,
  97. double streamTime, RtAudioStreamStatus status, void *data )
  98. {
  99. unsigned int i, j;
  100. extern unsigned int channels;
  101. MY_TYPE *buffer = (MY_TYPE *) outputBuffer;
  102. double *lastValues = (double *) data;
  103. if ( status )
  104. std::cout << "Stream underflow detected!" << std::endl;
  105. if ( streamTime >= streamTimePrintTime ) {
  106. std::cout << "streamTime = " << streamTime << std::endl;
  107. streamTimePrintTime += streamTimePrintIncrement;
  108. }
  109. double increment;
  110. for ( j=0; j<channels; j++ ) {
  111. increment = BASE_RATE * (j+1+(j*0.1));
  112. for ( i=0; i<nBufferFrames; i++ ) {
  113. *buffer++ = (MY_TYPE) (lastValues[j] * SCALE * 0.5);
  114. lastValues[j] += increment;
  115. if ( lastValues[j] >= 1.0 ) lastValues[j] -= 2.0;
  116. }
  117. }
  118. frameCounter += nBufferFrames;
  119. if ( checkCount && ( frameCounter >= nFrames ) ) return callbackReturnValue;
  120. return 0;
  121. }
  122. #endif
  123. int main( int argc, char *argv[] )
  124. {
  125. unsigned int bufferFrames, fs, device = 0, offset = 0;
  126. // minimal command-line checking
  127. if (argc < 3 || argc > 6 ) usage();
  128. RtAudio dac;
  129. if ( dac.getDeviceCount() < 1 ) {
  130. std::cout << "\nNo audio devices found!\n";
  131. exit( 1 );
  132. }
  133. channels = (unsigned int) atoi( argv[1] );
  134. fs = (unsigned int) atoi( argv[2] );
  135. if ( argc > 3 )
  136. device = (unsigned int) atoi( argv[3] );
  137. if ( argc > 4 )
  138. offset = (unsigned int) atoi( argv[4] );
  139. if ( argc > 5 )
  140. nFrames = (unsigned int) (fs * atof( argv[5] ));
  141. if ( nFrames > 0 ) checkCount = true;
  142. double *data = (double *) calloc( channels, sizeof( double ) );
  143. // Specify our own error callback function and tell RtAudio to
  144. // output all messages, even warnings.
  145. dac.setErrorCallback( &errorCallback );
  146. dac.showWarnings( true );
  147. // Set our stream parameters for output only.
  148. bufferFrames = 512;
  149. RtAudio::StreamParameters oParams;
  150. oParams.deviceId = device;
  151. oParams.nChannels = channels;
  152. oParams.firstChannel = offset;
  153. if ( device == 0 )
  154. oParams.deviceId = dac.getDefaultOutputDevice();
  155. options.flags = RTAUDIO_HOG_DEVICE;
  156. options.flags |= RTAUDIO_SCHEDULE_REALTIME;
  157. #if !defined( USE_INTERLEAVED )
  158. options.flags |= RTAUDIO_NONINTERLEAVED;
  159. #endif
  160. // An error in the openStream() function can be detected either by
  161. // checking for a non-zero return value OR by a subsequent call to
  162. // isStreamOpen().
  163. if ( dac.openStream( &oParams, NULL, FORMAT, fs, &bufferFrames, &saw, (void *)data, &options ) )
  164. goto cleanup;
  165. if ( dac.isStreamOpen() == false ) goto cleanup;
  166. // Stream is open ... now start it.
  167. if ( dac.startStream() ) goto cleanup;
  168. if ( checkCount ) {
  169. while ( dac.isStreamRunning() == true ) SLEEP( 100 );
  170. }
  171. else {
  172. char input;
  173. //std::cout << "Stream latency = " << dac.getStreamLatency() << "\n" << std::endl;
  174. std::cout << "\nPlaying ... press <enter> to quit (buffer size = " << bufferFrames << ").\n";
  175. std::cin.get( input );
  176. // Block released ... stop the stream
  177. dac.stopStream(); // or could call dac.abortStream();
  178. }
  179. cleanup:
  180. if ( dac.isStreamOpen() ) dac.closeStream();
  181. free( data );
  182. return 0;
  183. }