d1953b6ca164c0a14ffc3ef136b08d60f5072c26
[rtaudio-cdist.git] / tests / playsaw.cpp
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( __WINDOWS_ASIO__ ) || defined( __WINDOWS_DS__ ) || defined( __WINDOWS_WASAPI__ )
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 }