annotate src/portaudio/test/patest_wmme_find_best_latency_params.c @ 105:c83a7e2af39c

Ranlib
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 25 Mar 2013 16:28:19 +0000
parents 8a15ff55d9af
children
rev   line source
cannam@89 1 /*
cannam@89 2 * $Id: $
cannam@89 3 * Portable Audio I/O Library
cannam@89 4 * Windows MME low level buffer user guided parameters search
cannam@89 5 *
cannam@89 6 * Copyright (c) 2010 Ross Bencina
cannam@89 7 *
cannam@89 8 * Permission is hereby granted, free of charge, to any person obtaining
cannam@89 9 * a copy of this software and associated documentation files
cannam@89 10 * (the "Software"), to deal in the Software without restriction,
cannam@89 11 * including without limitation the rights to use, copy, modify, merge,
cannam@89 12 * publish, distribute, sublicense, and/or sell copies of the Software,
cannam@89 13 * and to permit persons to whom the Software is furnished to do so,
cannam@89 14 * subject to the following conditions:
cannam@89 15 *
cannam@89 16 * The above copyright notice and this permission notice shall be
cannam@89 17 * included in all copies or substantial portions of the Software.
cannam@89 18 *
cannam@89 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@89 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@89 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
cannam@89 22 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
cannam@89 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@89 24 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@89 25 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@89 26 */
cannam@89 27
cannam@89 28 /*
cannam@89 29 * The text above constitutes the entire PortAudio license; however,
cannam@89 30 * the PortAudio community also makes the following non-binding requests:
cannam@89 31 *
cannam@89 32 * Any person wishing to distribute modifications to the Software is
cannam@89 33 * requested to send the modifications to the original developer so that
cannam@89 34 * they can be incorporated into the canonical version. It is also
cannam@89 35 * requested that these non-binding requests be included along with the
cannam@89 36 * license above.
cannam@89 37 */
cannam@89 38
cannam@89 39 #include <stdio.h>
cannam@89 40 #include <time.h>
cannam@89 41 #include <math.h>
cannam@89 42
cannam@89 43 #define _WIN32_WINNT 0x0501 /* for GetNativeSystemInfo */
cannam@89 44 #include <windows.h> /* required when using pa_win_wmme.h */
cannam@89 45 #include <mmsystem.h> /* required when using pa_win_wmme.h */
cannam@89 46
cannam@89 47 #include <conio.h> /* for _getch */
cannam@89 48
cannam@89 49
cannam@89 50 #include "portaudio.h"
cannam@89 51 #include "pa_win_wmme.h"
cannam@89 52
cannam@89 53
cannam@89 54 #define DEFAULT_SAMPLE_RATE (44100.)
cannam@89 55
cannam@89 56 #ifndef M_PI
cannam@89 57 #define M_PI (3.14159265)
cannam@89 58 #endif
cannam@89 59
cannam@89 60 #define TABLE_SIZE (2048)
cannam@89 61
cannam@89 62 #define CHANNEL_COUNT (2)
cannam@89 63
cannam@89 64
cannam@89 65 /* seach parameters. we test all buffer counts in this range */
cannam@89 66 #define MIN_WMME_BUFFER_COUNT (2)
cannam@89 67 #define MAX_WMME_BUFFER_COUNT (12)
cannam@89 68
cannam@89 69
cannam@89 70 /*******************************************************************/
cannam@89 71 /* functions to query and print Windows version information */
cannam@89 72
cannam@89 73 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
cannam@89 74
cannam@89 75 LPFN_ISWOW64PROCESS fnIsWow64Process;
cannam@89 76
cannam@89 77 static BOOL IsWow64()
cannam@89 78 {
cannam@89 79 BOOL bIsWow64 = FALSE;
cannam@89 80
cannam@89 81 //IsWow64Process is not available on all supported versions of Windows.
cannam@89 82 //Use GetModuleHandle to get a handle to the DLL that contains the function
cannam@89 83 //and GetProcAddress to get a pointer to the function if available.
cannam@89 84
cannam@89 85 fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
cannam@89 86 GetModuleHandle(TEXT("kernel32")),"IsWow64Process" );
cannam@89 87
cannam@89 88 if(NULL != fnIsWow64Process)
cannam@89 89 {
cannam@89 90 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
cannam@89 91 {
cannam@89 92 //handle error
cannam@89 93 }
cannam@89 94 }
cannam@89 95 return bIsWow64;
cannam@89 96 }
cannam@89 97
cannam@89 98 static void printWindowsVersionInfo( FILE *fp )
cannam@89 99 {
cannam@89 100 OSVERSIONINFOEX osVersionInfoEx;
cannam@89 101 SYSTEM_INFO systemInfo;
cannam@89 102 const char *osName = "Unknown";
cannam@89 103 const char *osProductType = "";
cannam@89 104 const char *processorArchitecture = "Unknown";
cannam@89 105
cannam@89 106 memset( &osVersionInfoEx, 0, sizeof(OSVERSIONINFOEX) );
cannam@89 107 osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
cannam@89 108 GetVersionEx( &osVersionInfoEx );
cannam@89 109
cannam@89 110
cannam@89 111 if( osVersionInfoEx.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ){
cannam@89 112 switch( osVersionInfoEx.dwMinorVersion ){
cannam@89 113 case 0: osName = "Windows 95"; break;
cannam@89 114 case 10: osName = "Windows 98"; break; // could also be 98SE (I've seen code discriminate based
cannam@89 115 // on osInfo.Version.Revision.ToString() == "2222A")
cannam@89 116 case 90: osName = "Windows Me"; break;
cannam@89 117 }
cannam@89 118 }else if( osVersionInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT ){
cannam@89 119 switch( osVersionInfoEx.dwMajorVersion ){
cannam@89 120 case 3: osName = "Windows NT 3.51"; break;
cannam@89 121 case 4: osName = "Windows NT 4.0"; break;
cannam@89 122 case 5: switch( osVersionInfoEx.dwMinorVersion ){
cannam@89 123 case 0: osName = "Windows 2000"; break;
cannam@89 124 case 1: osName = "Windows XP"; break;
cannam@89 125 case 2:
cannam@89 126 if( osVersionInfoEx.wSuiteMask & 0x00008000 /*VER_SUITE_WH_SERVER*/ ){
cannam@89 127 osName = "Windows Home Server";
cannam@89 128 }else{
cannam@89 129 if( osVersionInfoEx.wProductType == VER_NT_WORKSTATION ){
cannam@89 130 osName = "Windows XP Professional x64 Edition (?)";
cannam@89 131 }else{
cannam@89 132 if( GetSystemMetrics(/*SM_SERVERR2*/89) == 0 )
cannam@89 133 osName = "Windows Server 2003";
cannam@89 134 else
cannam@89 135 osName = "Windows Server 2003 R2";
cannam@89 136 }
cannam@89 137 }break;
cannam@89 138 }break;
cannam@89 139 case 6:switch( osVersionInfoEx.dwMinorVersion ){
cannam@89 140 case 0:
cannam@89 141 if( osVersionInfoEx.wProductType == VER_NT_WORKSTATION )
cannam@89 142 osName = "Windows Vista";
cannam@89 143 else
cannam@89 144 osName = "Windows Server 2008";
cannam@89 145 break;
cannam@89 146 case 1:
cannam@89 147 if( osVersionInfoEx.wProductType == VER_NT_WORKSTATION )
cannam@89 148 osName = "Windows 7";
cannam@89 149 else
cannam@89 150 osName = "Windows Server 2008 R2";
cannam@89 151 break;
cannam@89 152 }break;
cannam@89 153 }
cannam@89 154 }
cannam@89 155
cannam@89 156 if(osVersionInfoEx.dwMajorVersion == 4)
cannam@89 157 {
cannam@89 158 if(osVersionInfoEx.wProductType == VER_NT_WORKSTATION)
cannam@89 159 osProductType = "Workstation";
cannam@89 160 else if(osVersionInfoEx.wProductType == VER_NT_SERVER)
cannam@89 161 osProductType = "Server";
cannam@89 162 }
cannam@89 163 else if(osVersionInfoEx.dwMajorVersion == 5)
cannam@89 164 {
cannam@89 165 if(osVersionInfoEx.wProductType == VER_NT_WORKSTATION)
cannam@89 166 {
cannam@89 167 if((osVersionInfoEx.wSuiteMask & VER_SUITE_PERSONAL) == VER_SUITE_PERSONAL)
cannam@89 168 osProductType = "Home Edition"; // Windows XP Home Edition
cannam@89 169 else
cannam@89 170 osProductType = "Professional"; // Windows XP / Windows 2000 Professional
cannam@89 171 }
cannam@89 172 else if(osVersionInfoEx.wProductType == VER_NT_SERVER)
cannam@89 173 {
cannam@89 174 if(osVersionInfoEx.dwMinorVersion == 0)
cannam@89 175 {
cannam@89 176 if((osVersionInfoEx.wSuiteMask & VER_SUITE_DATACENTER) == VER_SUITE_DATACENTER)
cannam@89 177 osProductType = "Datacenter Server"; // Windows 2000 Datacenter Server
cannam@89 178 else if((osVersionInfoEx.wSuiteMask & VER_SUITE_ENTERPRISE) == VER_SUITE_ENTERPRISE)
cannam@89 179 osProductType = "Advanced Server"; // Windows 2000 Advanced Server
cannam@89 180 else
cannam@89 181 osProductType = "Server"; // Windows 2000 Server
cannam@89 182 }
cannam@89 183 }
cannam@89 184 else
cannam@89 185 {
cannam@89 186 if((osVersionInfoEx.wSuiteMask & VER_SUITE_DATACENTER) == VER_SUITE_DATACENTER)
cannam@89 187 osProductType = "Datacenter Edition"; // Windows Server 2003 Datacenter Edition
cannam@89 188 else if((osVersionInfoEx.wSuiteMask & VER_SUITE_ENTERPRISE) == VER_SUITE_ENTERPRISE)
cannam@89 189 osProductType = "Enterprise Edition"; // Windows Server 2003 Enterprise Edition
cannam@89 190 else if((osVersionInfoEx.wSuiteMask & VER_SUITE_BLADE) == VER_SUITE_BLADE)
cannam@89 191 osProductType = "Web Edition"; // Windows Server 2003 Web Edition
cannam@89 192 else
cannam@89 193 osProductType = "Standard Edition"; // Windows Server 2003 Standard Edition
cannam@89 194 }
cannam@89 195 }
cannam@89 196
cannam@89 197 memset( &systemInfo, 0, sizeof(SYSTEM_INFO) );
cannam@89 198 GetNativeSystemInfo( &systemInfo );
cannam@89 199
cannam@89 200 if( systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL )
cannam@89 201 processorArchitecture = "x86";
cannam@89 202 else if( systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 )
cannam@89 203 processorArchitecture = "x64";
cannam@89 204 else if( systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
cannam@89 205 processorArchitecture = "Itanium";
cannam@89 206
cannam@89 207
cannam@89 208 fprintf( fp, "OS name and edition: %s %s\n", osName, osProductType );
cannam@89 209 fprintf( fp, "OS version: %d.%d.%d %S\n",
cannam@89 210 osVersionInfoEx.dwMajorVersion, osVersionInfoEx.dwMinorVersion,
cannam@89 211 osVersionInfoEx.dwBuildNumber, osVersionInfoEx.szCSDVersion );
cannam@89 212 fprintf( fp, "Processor architecture: %s\n", processorArchitecture );
cannam@89 213 fprintf( fp, "WoW64 process: %s\n", IsWow64() ? "Yes" : "No" );
cannam@89 214 }
cannam@89 215
cannam@89 216 static void printTimeAndDate( FILE *fp )
cannam@89 217 {
cannam@89 218 struct tm *local;
cannam@89 219 time_t t;
cannam@89 220
cannam@89 221 t = time(NULL);
cannam@89 222 local = localtime(&t);
cannam@89 223 fprintf(fp, "Local time and date: %s", asctime(local));
cannam@89 224 local = gmtime(&t);
cannam@89 225 fprintf(fp, "UTC time and date: %s", asctime(local));
cannam@89 226 }
cannam@89 227
cannam@89 228 /*******************************************************************/
cannam@89 229
cannam@89 230 typedef struct
cannam@89 231 {
cannam@89 232 float sine[TABLE_SIZE];
cannam@89 233 double phase;
cannam@89 234 double phaseIncrement;
cannam@89 235 volatile int fadeIn;
cannam@89 236 volatile int fadeOut;
cannam@89 237 double amp;
cannam@89 238 }
cannam@89 239 paTestData;
cannam@89 240
cannam@89 241 static paTestData data;
cannam@89 242
cannam@89 243 /* This routine will be called by the PortAudio engine when audio is needed.
cannam@89 244 ** It may called at interrupt level on some machines so don't do anything
cannam@89 245 ** that could mess up the system like calling malloc() or free().
cannam@89 246 */
cannam@89 247 static int patestCallback( const void *inputBuffer, void *outputBuffer,
cannam@89 248 unsigned long framesPerBuffer,
cannam@89 249 const PaStreamCallbackTimeInfo* timeInfo,
cannam@89 250 PaStreamCallbackFlags statusFlags,
cannam@89 251 void *userData )
cannam@89 252 {
cannam@89 253 paTestData *data = (paTestData*)userData;
cannam@89 254 float *out = (float*)outputBuffer;
cannam@89 255 unsigned long i,j;
cannam@89 256
cannam@89 257 (void) timeInfo; /* Prevent unused variable warnings. */
cannam@89 258 (void) statusFlags;
cannam@89 259 (void) inputBuffer;
cannam@89 260
cannam@89 261 for( i=0; i<framesPerBuffer; i++ )
cannam@89 262 {
cannam@89 263 float x = data->sine[(int)data->phase];
cannam@89 264 data->phase += data->phaseIncrement;
cannam@89 265 if( data->phase >= TABLE_SIZE ){
cannam@89 266 data->phase -= TABLE_SIZE;
cannam@89 267 }
cannam@89 268
cannam@89 269 x *= data->amp;
cannam@89 270 if( data->fadeIn ){
cannam@89 271 data->amp += .001;
cannam@89 272 if( data->amp >= 1. )
cannam@89 273 data->fadeIn = 0;
cannam@89 274 }else if( data->fadeOut ){
cannam@89 275 if( data->amp > 0 )
cannam@89 276 data->amp -= .001;
cannam@89 277 }
cannam@89 278
cannam@89 279 for( j = 0; j < CHANNEL_COUNT; ++j ){
cannam@89 280 *out++ = x;
cannam@89 281 }
cannam@89 282 }
cannam@89 283
cannam@89 284 if( data->amp > 0 )
cannam@89 285 return paContinue;
cannam@89 286 else
cannam@89 287 return paComplete;
cannam@89 288 }
cannam@89 289
cannam@89 290
cannam@89 291 #define YES 1
cannam@89 292 #define NO 0
cannam@89 293
cannam@89 294
cannam@89 295 static int playUntilKeyPress( int deviceIndex, float sampleRate,
cannam@89 296 int framesPerUserBuffer, int framesPerWmmeBuffer, int wmmeBufferCount )
cannam@89 297 {
cannam@89 298 PaStreamParameters outputParameters;
cannam@89 299 PaWinMmeStreamInfo wmmeStreamInfo;
cannam@89 300 PaStream *stream;
cannam@89 301 PaError err;
cannam@89 302 int c;
cannam@89 303
cannam@89 304 outputParameters.device = deviceIndex;
cannam@89 305 outputParameters.channelCount = CHANNEL_COUNT;
cannam@89 306 outputParameters.sampleFormat = paFloat32; /* 32 bit floating point processing */
cannam@89 307 outputParameters.suggestedLatency = 0; /*Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;*/
cannam@89 308 outputParameters.hostApiSpecificStreamInfo = NULL;
cannam@89 309
cannam@89 310 wmmeStreamInfo.size = sizeof(PaWinMmeStreamInfo);
cannam@89 311 wmmeStreamInfo.hostApiType = paMME;
cannam@89 312 wmmeStreamInfo.version = 1;
cannam@89 313 wmmeStreamInfo.flags = paWinMmeUseLowLevelLatencyParameters | paWinMmeDontThrottleOverloadedProcessingThread;
cannam@89 314 wmmeStreamInfo.framesPerBuffer = framesPerWmmeBuffer;
cannam@89 315 wmmeStreamInfo.bufferCount = wmmeBufferCount;
cannam@89 316 outputParameters.hostApiSpecificStreamInfo = &wmmeStreamInfo;
cannam@89 317
cannam@89 318 err = Pa_OpenStream(
cannam@89 319 &stream,
cannam@89 320 NULL, /* no input */
cannam@89 321 &outputParameters,
cannam@89 322 sampleRate,
cannam@89 323 framesPerUserBuffer,
cannam@89 324 paClipOff | paPrimeOutputBuffersUsingStreamCallback, /* we won't output out of range samples so don't bother clipping them */
cannam@89 325 patestCallback,
cannam@89 326 &data );
cannam@89 327 if( err != paNoError ) goto error;
cannam@89 328
cannam@89 329 data.amp = 0;
cannam@89 330 data.fadeIn = 1;
cannam@89 331 data.fadeOut = 0;
cannam@89 332 data.phase = 0;
cannam@89 333 data.phaseIncrement = 15 + ((rand()%100) / 10); // randomise pitch
cannam@89 334
cannam@89 335 err = Pa_StartStream( stream );
cannam@89 336 if( err != paNoError ) goto error;
cannam@89 337
cannam@89 338
cannam@89 339 do{
cannam@89 340 printf( "Trying buffer size %d.\nIf it sounds smooth (without clicks or glitches) press 'y', if it sounds bad press 'n' ('q' to quit)\n", framesPerWmmeBuffer );
cannam@89 341 c = tolower(_getch());
cannam@89 342 if( c == 'q' ){
cannam@89 343 Pa_Terminate();
cannam@89 344 exit(0);
cannam@89 345 }
cannam@89 346 }while( c != 'y' && c != 'n' );
cannam@89 347
cannam@89 348 data.fadeOut = 1;
cannam@89 349 while( Pa_IsStreamActive(stream) == 1 )
cannam@89 350 Pa_Sleep( 100 );
cannam@89 351
cannam@89 352 err = Pa_StopStream( stream );
cannam@89 353 if( err != paNoError ) goto error;
cannam@89 354
cannam@89 355 err = Pa_CloseStream( stream );
cannam@89 356 if( err != paNoError ) goto error;
cannam@89 357
cannam@89 358 return (c == 'y') ? YES : NO;
cannam@89 359
cannam@89 360 error:
cannam@89 361 return err;
cannam@89 362 }
cannam@89 363
cannam@89 364 /*******************************************************************/
cannam@89 365 static void usage( int wmmeHostApiIndex )
cannam@89 366 {
cannam@89 367 int i;
cannam@89 368
cannam@89 369 fprintf( stderr, "PortAudio WMME output latency user guided test\n" );
cannam@89 370 fprintf( stderr, "Usage: x.exe mme-device-index [sampleRate [min-buffer-count max-buffer-count]]\n" );
cannam@89 371 fprintf( stderr, "Invalid device index. Use one of these:\n" );
cannam@89 372 for( i=0; i < Pa_GetDeviceCount(); ++i ){
cannam@89 373
cannam@89 374 if( Pa_GetDeviceInfo(i)->hostApi == wmmeHostApiIndex && Pa_GetDeviceInfo(i)->maxOutputChannels > 0 )
cannam@89 375 fprintf( stderr, "%d (%s)\n", i, Pa_GetDeviceInfo(i)->name );
cannam@89 376 }
cannam@89 377 Pa_Terminate();
cannam@89 378 exit(-1);
cannam@89 379 }
cannam@89 380
cannam@89 381 /*
cannam@89 382 ideas:
cannam@89 383 o- could be testing with 80% CPU load
cannam@89 384 o- could test with different channel counts
cannam@89 385 */
cannam@89 386
cannam@89 387 int main(int argc, char* argv[])
cannam@89 388 {
cannam@89 389 PaError err;
cannam@89 390 int i;
cannam@89 391 int deviceIndex;
cannam@89 392 int wmmeBufferCount, wmmeBufferSize, smallestWorkingBufferSize;
cannam@89 393 int smallestWorkingBufferingLatencyFrames;
cannam@89 394 int min, max, mid;
cannam@89 395 int testResult;
cannam@89 396 FILE *resultsFp;
cannam@89 397 int wmmeHostApiIndex;
cannam@89 398 const PaHostApiInfo *wmmeHostApiInfo;
cannam@89 399 double sampleRate = DEFAULT_SAMPLE_RATE;
cannam@89 400 int wmmeMinBufferCount = MIN_WMME_BUFFER_COUNT;
cannam@89 401 int wmmeMaxBufferCount = MAX_WMME_BUFFER_COUNT;
cannam@89 402
cannam@89 403 err = Pa_Initialize();
cannam@89 404 if( err != paNoError ) goto error;
cannam@89 405
cannam@89 406 wmmeHostApiIndex = Pa_HostApiTypeIdToHostApiIndex( paMME );
cannam@89 407 wmmeHostApiInfo = Pa_GetHostApiInfo( wmmeHostApiIndex );
cannam@89 408
cannam@89 409 if( argc > 5 )
cannam@89 410 usage(wmmeHostApiIndex);
cannam@89 411
cannam@89 412 deviceIndex = wmmeHostApiInfo->defaultOutputDevice;
cannam@89 413 if( argc >= 2 ){
cannam@89 414 deviceIndex = -1;
cannam@89 415 if( sscanf( argv[1], "%d", &deviceIndex ) != 1 )
cannam@89 416 usage(wmmeHostApiIndex);
cannam@89 417 if( deviceIndex < 0 || deviceIndex >= Pa_GetDeviceCount() || Pa_GetDeviceInfo(deviceIndex)->hostApi != wmmeHostApiIndex ){
cannam@89 418 usage(wmmeHostApiIndex);
cannam@89 419 }
cannam@89 420 }
cannam@89 421
cannam@89 422 printf( "Using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name );
cannam@89 423
cannam@89 424 if( argc >= 3 ){
cannam@89 425 if( sscanf( argv[2], "%lf", &sampleRate ) != 1 )
cannam@89 426 usage(wmmeHostApiIndex);
cannam@89 427 }
cannam@89 428
cannam@89 429 printf( "Testing with sample rate %f.\n", (float)sampleRate );
cannam@89 430
cannam@89 431 if( argc == 4 ){
cannam@89 432 if( sscanf( argv[3], "%d", &wmmeMinBufferCount ) != 1 )
cannam@89 433 usage(wmmeHostApiIndex);
cannam@89 434 wmmeMaxBufferCount = wmmeMinBufferCount;
cannam@89 435 }
cannam@89 436
cannam@89 437 if( argc == 5 ){
cannam@89 438 if( sscanf( argv[3], "%d", &wmmeMinBufferCount ) != 1 )
cannam@89 439 usage(wmmeHostApiIndex);
cannam@89 440 if( sscanf( argv[4], "%d", &wmmeMaxBufferCount ) != 1 )
cannam@89 441 usage(wmmeHostApiIndex);
cannam@89 442 }
cannam@89 443
cannam@89 444 printf( "Testing buffer counts from %d to %d\n", wmmeMinBufferCount, wmmeMaxBufferCount );
cannam@89 445
cannam@89 446
cannam@89 447 /* initialise sinusoidal wavetable */
cannam@89 448 for( i=0; i<TABLE_SIZE; i++ )
cannam@89 449 {
cannam@89 450 data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
cannam@89 451 }
cannam@89 452
cannam@89 453 data.phase = 0;
cannam@89 454
cannam@89 455 resultsFp = fopen( "results.txt", "at" );
cannam@89 456 fprintf( resultsFp, "*** WMME smallest working output buffer sizes\n" );
cannam@89 457
cannam@89 458 printTimeAndDate( resultsFp );
cannam@89 459 printWindowsVersionInfo( resultsFp );
cannam@89 460
cannam@89 461 fprintf( resultsFp, "audio device: %s\n", Pa_GetDeviceInfo( deviceIndex )->name );
cannam@89 462 fflush( resultsFp );
cannam@89 463
cannam@89 464 fprintf( resultsFp, "Sample rate: %f\n", (float)sampleRate );
cannam@89 465 fprintf( resultsFp, "Buffer count, Smallest working buffer size (frames), Smallest working buffering latency (frames), Smallest working buffering latency (Seconds)\n" );
cannam@89 466
cannam@89 467 for( wmmeBufferCount = wmmeMinBufferCount; wmmeBufferCount <= wmmeMaxBufferCount; ++wmmeBufferCount ){
cannam@89 468
cannam@89 469 printf( "Test %d of %d\n", (wmmeBufferCount - wmmeMinBufferCount) + 1, (wmmeMaxBufferCount-wmmeMinBufferCount) + 1 );
cannam@89 470 printf( "Testing with %d buffers...\n", wmmeBufferCount );
cannam@89 471
cannam@89 472 /*
cannam@89 473 Binary search after Niklaus Wirth
cannam@89 474 from http://en.wikipedia.org/wiki/Binary_search_algorithm#The_algorithm
cannam@89 475 */
cannam@89 476 min = 1;
cannam@89 477 max = (int)((sampleRate * .3) / (wmmeBufferCount-1)); //8192; /* we assume that this size works 300ms */
cannam@89 478 smallestWorkingBufferSize = 0;
cannam@89 479
cannam@89 480 do{
cannam@89 481 mid = min + ((max - min) / 2);
cannam@89 482
cannam@89 483 wmmeBufferSize = mid;
cannam@89 484 testResult = playUntilKeyPress( deviceIndex, sampleRate, wmmeBufferSize, wmmeBufferSize, wmmeBufferCount );
cannam@89 485
cannam@89 486 if( testResult == YES ){
cannam@89 487 max = mid - 1;
cannam@89 488 smallestWorkingBufferSize = wmmeBufferSize;
cannam@89 489 }else{
cannam@89 490 min = mid + 1;
cannam@89 491 }
cannam@89 492
cannam@89 493 }while( (min <= max) && (testResult == YES || testResult == NO) );
cannam@89 494
cannam@89 495 smallestWorkingBufferingLatencyFrames = smallestWorkingBufferSize * (wmmeBufferCount - 1);
cannam@89 496
cannam@89 497 printf( "Smallest working buffer size for %d buffers is: %d\n", wmmeBufferCount, smallestWorkingBufferSize );
cannam@89 498 printf( "Corresponding to buffering latency of %d frames, or %f seconds.\n", smallestWorkingBufferingLatencyFrames, smallestWorkingBufferingLatencyFrames / sampleRate );
cannam@89 499
cannam@89 500 fprintf( resultsFp, "%d, %d, %d, %f\n", wmmeBufferCount, smallestWorkingBufferSize, smallestWorkingBufferingLatencyFrames, smallestWorkingBufferingLatencyFrames / sampleRate );
cannam@89 501 fflush( resultsFp );
cannam@89 502 }
cannam@89 503
cannam@89 504 fprintf( resultsFp, "###\n" );
cannam@89 505 fclose( resultsFp );
cannam@89 506
cannam@89 507 Pa_Terminate();
cannam@89 508 printf("Test finished.\n");
cannam@89 509
cannam@89 510 return err;
cannam@89 511 error:
cannam@89 512 Pa_Terminate();
cannam@89 513 fprintf( stderr, "An error occured while using the portaudio stream\n" );
cannam@89 514 fprintf( stderr, "Error number: %d\n", err );
cannam@89 515 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
cannam@89 516 return err;
cannam@89 517 }
cannam@89 518