1 /************************************************************************/
\r
2 /*! \brief Interactively Test RtAudio parameters.
\r
4 RtAudio is a command-line utility that allows users to enumerate
\r
5 installed devices, and to test input, output and duplex operation
\r
6 of RtAudio devices with various buffer and buffer-size
\r
9 Copyright (c) 2005 Robin Davies.
\r
11 Permission is hereby granted, free of charge, to any person
\r
12 obtaining a copy of this software and associated documentation files
\r
13 (the "Software"), to deal in the Software without restriction,
\r
14 including without limitation the rights to use, copy, modify, merge,
\r
15 publish, distribute, sublicense, and/or sell copies of the Software,
\r
16 and to permit persons to whom the Software is furnished to do so,
\r
17 subject to the following conditions:
\r
19 The above copyright notice and this permission notice shall be
\r
20 included in all copies or substantial portions of the Software.
\r
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
\r
25 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
\r
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
\r
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\r
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
30 /************************************************************************/
\r
32 #include "RtAudio.h"
\r
33 #include "FileWvOut.h"
\r
39 using namespace std;
\r
40 using namespace stdopt;
\r
43 // Correct windows.h standards violation.
\r
50 RtAudio::RtAudioApi rtApi = RtAudio::WINDOWS_DS;
\r
52 void DisplayHelp(std::ostream &os)
\r
55 << "rtaudiotest - Test rtaudio devices." << endl
\r
57 << "Syntax:" << endl
\r
58 << " rtaudiotest [options]* enum" << endl
\r
59 << " - Display installed devices." << endl
\r
60 << " rtaudiotest [options]* inputtest <devicenum> [<filename>]" << endl
\r
61 << " - Capture audio to a .wav file." << endl
\r
62 << " rtaudiotest [options]* outputtest <devicenum>" << endl
\r
63 << " - Generate a test signal on the device.." << endl
\r
64 << " rtaudiotest [options]* duplextest <inputDevicenum> <outputdevicenum>" << endl
\r
65 << " - Echo input to output." << endl
\r
67 << "Options:" << endl
\r
68 << " -h -? Display this message." << endl
\r
69 << " -dsound Use DirectX drivers." << endl
\r
70 << " -asio Use ASIO drivers." << endl
\r
71 << " -buffers N Use N buffers." << endl
\r
72 << " -size N Use buffers of size N." << endl
\r
73 << " -srate N Use a sample-rate of N (defaults to 44100)." << endl
\r
74 << " -channels N Use N channels (defaults to 2)." << endl
\r
75 << " -seconds N Run the test for N seconds (default 5)." << endl
\r
76 << "Description: " << endl
\r
77 << " RtAudio is a command-line utility that allows users to enumerate " << endl
\r
78 << " installed devices, and to test input, output and duplex operation " << endl
\r
79 << " of RtAudio devices with various buffer and buffer-size " << endl
\r
80 << " configurations." << endl
\r
81 << "Examples:" << endl
\r
82 << " rtaudio -asio enum" << endl
\r
83 << " rtaudio -dsound -buffers 4 -size 128 -seconds 3 inputtest 0 test.wav" << endl
\r
88 void EnumerateDevices(RtAudio::RtAudioApi api)
\r
91 for (int i = 1; i <= rt.getDeviceCount(); ++i)
\r
93 RtAudioDeviceInfo info = rt.getDeviceInfo(i);
\r
94 cout << "Device " << i << ": " << info.name << endl;
\r
98 struct TestConfiguration
\r
108 bool DisplayStats(RtAudio::RtAudioApi api)
\r
110 #ifdef __WINDOWS_DS__
\r
111 // Display latency results for Windows DSound drivers.
\r
112 if (api == RtAudio::WINDOWS_DS)
\r
114 RtApiDs::RtDsStatistics s = RtApiDs::getDsStatistics();
\r
116 cout << " Latency: " << s.latency*1000.0 << "ms" << endl;
\r
117 if (s.inputFrameSize)
\r
119 cout << " Read overruns: " << s.numberOfReadOverruns << endl;
\r
121 if (s.outputFrameSize)
\r
123 cout << " Write underruns: " << s.numberOfWriteUnderruns << endl;
\r
126 if (s.inputFrameSize)
\r
128 cout << " Read lead time in sample frames (device): " << s.readDeviceSafeLeadBytes/ s.inputFrameSize << endl;
\r
130 if (s.outputFrameSize)
\r
132 cout << " Write lead time in sample frames (device): " << s.writeDeviceSafeLeadBytes / s.outputFrameSize << endl;
\r
133 cout << " Write lead time in sample frames (buffer): " << s.writeDeviceBufferLeadBytes / s.outputFrameSize << endl;
\r
142 void InputTest( RtAudio::RtAudioApi api,
\r
144 const std::string &fileName,
\r
145 TestConfiguration &configuration )
\r
149 int bufferSize = configuration.bufferSize;
\r
151 RtAudioDeviceInfo info = rt.getDeviceInfo(inputDevice);
\r
152 cout << "Reading from device " << inputDevice << " (" << info.name << ")\n";
\r
154 rt.openStream(0,0,inputDevice,configuration.channels, RTAUDIO_SINT16, configuration.srate,&bufferSize,configuration.buffers);
\r
155 if (bufferSize != configuration.bufferSize)
\r
157 cout << "The buffer size was changed to " << bufferSize << " by the device." << endl;
\r
158 configuration.bufferSize = bufferSize;
\r
162 int nTicks = (int)ceil((configuration.srate* configuration.seconds)*1.0/configuration.bufferSize);
\r
164 if (fileName.length() == 0)
\r
166 // just run the stream.
\r
168 for (int i = 0; i < nTicks; ++i)
\r
175 if (configuration.seconds > 10) {
\r
176 throw CommandLineException("Capture of more than 10 seconds of data is not supported.");
\r
178 std::vector<short> data;
\r
179 // we could be smarter, but the point here is to capture data without interfering with the stream.
\r
180 // File writes while ticking the stream is not cool.
\r
181 data.resize(nTicks*configuration.bufferSize*configuration.channels); // potentially very big. That's why we restrict capture to 10 seconds.
\r
182 short *pData = &data[0];
\r
186 for (i = 0; i < nTicks; ++i)
\r
189 short *streamBuffer = (short*)rt.getStreamBuffer();
\r
190 for (int samples = 0; samples < configuration.bufferSize; ++samples)
\r
192 for (int channel = 0; channel < configuration.channels; ++channel)
\r
194 *pData ++ = *streamBuffer++;
\r
199 remove(fileName.c_str());
\r
201 wvOut.openFile( fileName.c_str(), configuration.channels, FileWrite::FILE_WAV );
\r
203 StkFrames frame(1,configuration.channels,false);
\r
206 for (i = 0; i < nTicks; ++i) {
\r
207 for (int samples = 0; samples < configuration.bufferSize; ++samples) {
\r
208 for (int channel = 0; channel < configuration.channels; ++channel) {
\r
209 frame[channel] = (float)( *pData++*( 1.0 / 32768.0 ) );
\r
211 wvOut.tickFrame(frame);
\r
218 if (DisplayStats(api)) {
\r
219 cout << "Test succeeded." << endl;
\r
223 void OutputTest( RtAudio::RtAudioApi api,
\r
225 TestConfiguration &configuration )
\r
228 int bufferSize = configuration.bufferSize;
\r
230 RtAudioDeviceInfo info = rt.getDeviceInfo(outputDevice);
\r
231 cout << "Writing to " << info.name << "...\n";
\r
233 rt.openStream(outputDevice,configuration.channels, 0,0, RTAUDIO_SINT16, configuration.srate,&bufferSize,configuration.buffers);
\r
234 if (bufferSize != configuration.bufferSize) {
\r
235 cout << "The buffer size was changed to " << bufferSize << " by the device." << endl;
\r
236 configuration.bufferSize = bufferSize;
\r
240 short *pBuffer = (short*)rt.getStreamBuffer();
\r
241 int nTicks = (int)ceil((configuration.srate* configuration.seconds)*1.0/configuration.bufferSize);
\r
244 double deltaPhase = 880.0/configuration.srate;
\r
245 for (int i = 0; i < nTicks; ++i) {
\r
246 short *p = pBuffer;
\r
247 for (int samp = 0; samp < configuration.bufferSize; ++samp) {
\r
248 short val = (short)(sin(phase)*(32768/4)); // sin()*0.25 magnitude. Audible, but not damaging to ears or speakers.
\r
249 phase += deltaPhase;
\r
251 for (int chan = 0; chan < configuration.channels; ++chan) {
\r
260 if ( DisplayStats(api) ) {
\r
261 cout << "Test succeeded." << endl;
\r
265 void DuplexTest( RtAudio::RtAudioApi api,
\r
268 TestConfiguration &configuration )
\r
271 int bufferSize = configuration.bufferSize;
\r
273 RtAudioDeviceInfo info = rt.getDeviceInfo(inputDevice);
\r
274 cout << "Reading from " << info.name << ", " << endl;
\r
275 info = rt.getDeviceInfo(outputDevice);
\r
276 cout << "Writing to " << info.name << "..." << endl;
\r
278 rt.openStream(outputDevice,configuration.channels, inputDevice,configuration.channels, RTAUDIO_SINT16, configuration.srate,&bufferSize,configuration.buffers);
\r
279 if (bufferSize != configuration.bufferSize)
\r
281 cout << "The buffer size was changed to " << bufferSize << " by the device." << endl;
\r
282 configuration.bufferSize = bufferSize;
\r
286 short *pBuffer = (short*)rt.getStreamBuffer();
\r
287 int nTicks = (int)ceil((configuration.srate* configuration.seconds)*1.0/configuration.bufferSize);
\r
289 for (int i = 0; i < nTicks; ++i) {
\r
295 if ( DisplayStats(api) ) {
\r
296 cout << "Test succeeded." << endl;
\r
300 int main(int argc, char **argv)
\r
304 CommandLine commandLine;
\r
306 TestConfiguration configuration;
\r
311 commandLine.AddOption("h",&displayHelp);
\r
312 commandLine.AddOption("?",&displayHelp);
\r
313 commandLine.AddOption("dsound",&useDsound);
\r
314 commandLine.AddOption("asio",&useAsio);
\r
315 commandLine.AddOption("srate",&configuration.srate,44100L);
\r
316 commandLine.AddOption("channels",&configuration.channels,2);
\r
317 commandLine.AddOption("seconds",&configuration.seconds,5);
\r
318 commandLine.AddOption("buffers",&configuration.buffers,2);
\r
319 commandLine.AddOption("size",&configuration.bufferSize,128);
\r
321 commandLine.ProcessCommandLine(argc,argv);
\r
323 if (displayHelp || commandLine.GetArguments().size() == 0)
\r
330 rtApi = RtAudio::WINDOWS_DS;
\r
331 } else if (useAsio)
\r
333 rtApi = RtAudio::WINDOWS_ASIO;
\r
335 throw CommandLineException("Please specify an API to use: '-dsound', or '-asio'");
\r
338 std::string testName;
\r
339 commandLine.GetArgument(0,&testName);
\r
340 if (testName == "enum")
\r
342 EnumerateDevices(rtApi);
\r
343 } else if (testName == "inputtest")
\r
346 std::string fileName;
\r
347 commandLine.GetArgument(1,&inputDevice);
\r
348 if (commandLine.GetArguments().size() >= 2)
\r
350 commandLine.GetArgument(2,&fileName);
\r
352 InputTest(rtApi,inputDevice,fileName,configuration);
\r
353 } else if (testName == "outputtest")
\r
356 commandLine.GetArgument(1,&inputDevice);
\r
357 OutputTest(rtApi,inputDevice,configuration);
\r
358 } else if (testName == "duplextest")
\r
362 commandLine.GetArgument(1,&inputDevice);
\r
363 commandLine.GetArgument(2,&outputDevice);
\r
364 DuplexTest(rtApi,inputDevice,outputDevice,configuration);
\r
366 throw CommandLineException("Not a valid test name.");
\r
369 } catch (CommandLineException &e)
\r
371 cerr << e.what() << endl << endl;
\r
372 cerr << "Run 'rtaudiotest -h' to see the commandline syntax." << endl;
\r
374 } catch (RtError &e)
\r
376 cerr << e.getMessage() << endl;
\r
379 } catch (std::exception &e)
\r
381 cerr << "Error: " << e.what() << endl;
\r