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