Check for '#if defined( WIN32 )' in test apps
[rtaudio-cdist.git] / tests / record.cpp
1 /******************************************/
2 /*
3   record.cpp
4   by Gary P. Scavone, 2007
5
6   This program records audio from a device and writes it to a
7   header-less binary file.  Use the 'playraw', with the same
8   parameters and format settings, to playback the audio.
9 */
10 /******************************************/
11
12 #include "RtAudio.h"
13 #include <iostream>
14 #include <cstdlib>
15 #include <cstring>
16 #include <stdio.h>
17
18 /*
19 typedef char MY_TYPE;
20 #define FORMAT RTAUDIO_SINT8
21 */
22
23 typedef signed short MY_TYPE;
24 #define FORMAT RTAUDIO_SINT16
25
26 /*
27 typedef S24 MY_TYPE;
28 #define FORMAT RTAUDIO_SINT24
29
30 typedef signed long MY_TYPE;
31 #define FORMAT RTAUDIO_SINT32
32
33 typedef float MY_TYPE;
34 #define FORMAT RTAUDIO_FLOAT32
35
36 typedef double MY_TYPE;
37 #define FORMAT RTAUDIO_FLOAT64
38 */
39
40 // Platform-dependent sleep routines.
41 #if defined( WIN32 )
42   #include <windows.h>
43   #define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds ) 
44 #else // Unix variants
45   #include <unistd.h>
46   #define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) )
47 #endif
48
49 void usage( void ) {
50   // Error function in case of incorrect command-line
51   // argument specifications
52   std::cout << "\nuseage: record N fs <duration> <device> <channelOffset>\n";
53   std::cout << "    where N = number of channels,\n";
54   std::cout << "    fs = the sample rate,\n";
55   std::cout << "    duration = optional time in seconds to record (default = 2.0),\n";
56   std::cout << "    device = optional device to use (default = 0),\n";
57   std::cout << "    and channelOffset = an optional channel offset on the device (default = 0).\n\n";
58   exit( 0 );
59 }
60
61 struct InputData {
62   MY_TYPE* buffer;
63   unsigned long bufferBytes;
64   unsigned long totalFrames;
65   unsigned long frameCounter;
66   unsigned int channels;
67 };
68
69 // Interleaved buffers
70 int input( void * /*outputBuffer*/, void *inputBuffer, unsigned int nBufferFrames,
71            double /*streamTime*/, RtAudioStreamStatus /*status*/, void *data )
72 {
73   InputData *iData = (InputData *) data;
74
75   // Simply copy the data to our allocated buffer.
76   unsigned int frames = nBufferFrames;
77   if ( iData->frameCounter + nBufferFrames > iData->totalFrames ) {
78     frames = iData->totalFrames - iData->frameCounter;
79     iData->bufferBytes = frames * iData->channels * sizeof( MY_TYPE );
80   }
81
82   unsigned long offset = iData->frameCounter * iData->channels;
83   memcpy( iData->buffer+offset, inputBuffer, iData->bufferBytes );
84   iData->frameCounter += frames;
85
86   if ( iData->frameCounter >= iData->totalFrames ) return 2;
87   return 0;
88 }
89
90 int main( int argc, char *argv[] )
91 {
92   unsigned int channels, fs, bufferFrames, device = 0, offset = 0;
93   double time = 2.0;
94   FILE *fd;
95
96   // minimal command-line checking
97   if ( argc < 3 || argc > 6 ) usage();
98
99   RtAudio adc;
100   if ( adc.getDeviceCount() < 1 ) {
101     std::cout << "\nNo audio devices found!\n";
102     exit( 1 );
103   }
104
105   channels = (unsigned int) atoi( argv[1] );
106   fs = (unsigned int) atoi( argv[2] );
107   if ( argc > 3 )
108     time = (double) atof( argv[3] );
109   if ( argc > 4 )
110     device = (unsigned int) atoi( argv[4] );
111   if ( argc > 5 )
112     offset = (unsigned int) atoi( argv[5] );
113
114   // Let RtAudio print messages to stderr.
115   adc.showWarnings( true );
116
117   // Set our stream parameters for input only.
118   bufferFrames = 512;
119   RtAudio::StreamParameters iParams;
120   if ( device == 0 )
121     iParams.deviceId = adc.getDefaultInputDevice();
122   else
123     iParams.deviceId = device;
124   iParams.nChannels = channels;
125   iParams.firstChannel = offset;
126
127   InputData data;
128   data.buffer = 0;
129   try {
130     adc.openStream( NULL, &iParams, FORMAT, fs, &bufferFrames, &input, (void *)&data );
131   }
132   catch ( RtAudioError& e ) {
133     std::cout << '\n' << e.getMessage() << '\n' << std::endl;
134     goto cleanup;
135   }
136
137   data.bufferBytes = bufferFrames * channels * sizeof( MY_TYPE );
138   data.totalFrames = (unsigned long) (fs * time);
139   data.frameCounter = 0;
140   data.channels = channels;
141   unsigned long totalBytes;
142   totalBytes = data.totalFrames * channels * sizeof( MY_TYPE );
143
144   // Allocate the entire data buffer before starting stream.
145   data.buffer = (MY_TYPE*) malloc( totalBytes );
146   if ( data.buffer == 0 ) {
147     std::cout << "Memory allocation error ... quitting!\n";
148     goto cleanup;
149   }
150
151   try {
152     adc.startStream();
153   }
154   catch ( RtAudioError& e ) {
155     std::cout << '\n' << e.getMessage() << '\n' << std::endl;
156     goto cleanup;
157   }
158
159   std::cout << "\nRecording for " << time << " seconds ... writing file 'record.raw' (buffer frames = " << bufferFrames << ")." << std::endl;
160   while ( adc.isStreamRunning() ) {
161     SLEEP( 100 ); // wake every 100 ms to check if we're done
162   }
163
164   // Now write the entire data to the file.
165   fd = fopen( "record.raw", "wb" );
166   fwrite( data.buffer, sizeof( MY_TYPE ), data.totalFrames * channels, fd );
167   fclose( fd );
168
169  cleanup:
170   if ( adc.isStreamOpen() ) adc.closeStream();
171   if ( data.buffer ) free( data.buffer );
172
173   return 0;
174 }