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