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