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