pa_process.c (68282B)
1 /* 2 * $Id$ 3 * Portable Audio I/O Library 4 * streamCallback <-> host buffer processing adapter 5 * 6 * Based on the Open Source API proposed by Ross Bencina 7 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining 10 * a copy of this software and associated documentation files 11 * (the "Software"), to deal in the Software without restriction, 12 * including without limitation the rights to use, copy, modify, merge, 13 * publish, distribute, sublicense, and/or sell copies of the Software, 14 * and to permit persons to whom the Software is furnished to do so, 15 * subject to the following conditions: 16 * 17 * The above copyright notice and this permission notice shall be 18 * included in all copies or substantial portions of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 24 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 25 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 */ 28 29 /* 30 * The text above constitutes the entire PortAudio license; however, 31 * the PortAudio community also makes the following non-binding requests: 32 * 33 * Any person wishing to distribute modifications to the Software is 34 * requested to send the modifications to the original developer so that 35 * they can be incorporated into the canonical version. It is also 36 * requested that these non-binding requests be included along with the 37 * license above. 38 */ 39 40 /** @file 41 @ingroup common_src 42 43 @brief Buffer Processor implementation. 44 */ 45 46 47 #include <assert.h> 48 #include <string.h> /* memset() */ 49 50 #include "pa_process.h" 51 #include "pa_util.h" 52 53 54 #define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024 55 56 #define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) ) 57 58 59 /* greatest common divisor - PGCD in French */ 60 static unsigned long GCD( unsigned long a, unsigned long b ) 61 { 62 return (b==0) ? a : GCD( b, a%b); 63 } 64 65 /* least common multiple - PPCM in French */ 66 static unsigned long LCM( unsigned long a, unsigned long b ) 67 { 68 return (a*b) / GCD(a,b); 69 } 70 71 #define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b)) 72 73 static unsigned long CalculateFrameShift( unsigned long M, unsigned long N ) 74 { 75 unsigned long result = 0; 76 unsigned long i; 77 unsigned long lcm; 78 79 assert( M > 0 ); 80 assert( N > 0 ); 81 82 lcm = LCM( M, N ); 83 for( i = M; i < lcm; i += M ) 84 result = PA_MAX_( result, i % N ); 85 86 return result; 87 } 88 89 90 PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp, 91 int inputChannelCount, PaSampleFormat userInputSampleFormat, 92 PaSampleFormat hostInputSampleFormat, 93 int outputChannelCount, PaSampleFormat userOutputSampleFormat, 94 PaSampleFormat hostOutputSampleFormat, 95 double sampleRate, 96 PaStreamFlags streamFlags, 97 unsigned long framesPerUserBuffer, 98 unsigned long framesPerHostBuffer, 99 PaUtilHostBufferSizeMode hostBufferSizeMode, 100 PaStreamCallback *streamCallback, void *userData ) 101 { 102 PaError result = paNoError; 103 PaError bytesPerSample; 104 unsigned long tempInputBufferSize, tempOutputBufferSize; 105 PaStreamFlags tempInputStreamFlags; 106 107 if( streamFlags & paNeverDropInput ) 108 { 109 /* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */ 110 if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) || 111 framesPerUserBuffer != paFramesPerBufferUnspecified ) 112 return paInvalidFlag; 113 } 114 115 /* initialize buffer ptrs to zero so they can be freed if necessary in error */ 116 bp->tempInputBuffer = 0; 117 bp->tempInputBufferPtrs = 0; 118 bp->tempOutputBuffer = 0; 119 bp->tempOutputBufferPtrs = 0; 120 121 bp->framesPerUserBuffer = framesPerUserBuffer; 122 bp->framesPerHostBuffer = framesPerHostBuffer; 123 124 bp->inputChannelCount = inputChannelCount; 125 bp->outputChannelCount = outputChannelCount; 126 127 bp->hostBufferSizeMode = hostBufferSizeMode; 128 129 bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0; 130 bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0; 131 132 if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */ 133 { 134 bp->useNonAdaptingProcess = 1; 135 bp->initialFramesInTempInputBuffer = 0; 136 bp->initialFramesInTempOutputBuffer = 0; 137 138 if( hostBufferSizeMode == paUtilFixedHostBufferSize 139 || hostBufferSizeMode == paUtilBoundedHostBufferSize ) 140 { 141 bp->framesPerTempBuffer = framesPerHostBuffer; 142 } 143 else /* unknown host buffer size */ 144 { 145 bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_; 146 } 147 } 148 else 149 { 150 bp->framesPerTempBuffer = framesPerUserBuffer; 151 152 if( hostBufferSizeMode == paUtilFixedHostBufferSize 153 && framesPerHostBuffer % framesPerUserBuffer == 0 ) 154 { 155 bp->useNonAdaptingProcess = 1; 156 bp->initialFramesInTempInputBuffer = 0; 157 bp->initialFramesInTempOutputBuffer = 0; 158 } 159 else 160 { 161 bp->useNonAdaptingProcess = 0; 162 163 if( inputChannelCount > 0 && outputChannelCount > 0 ) 164 { 165 /* full duplex */ 166 if( hostBufferSizeMode == paUtilFixedHostBufferSize ) 167 { 168 unsigned long frameShift = 169 CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer ); 170 171 if( framesPerUserBuffer > framesPerHostBuffer ) 172 { 173 bp->initialFramesInTempInputBuffer = frameShift; 174 bp->initialFramesInTempOutputBuffer = 0; 175 } 176 else 177 { 178 bp->initialFramesInTempInputBuffer = 0; 179 bp->initialFramesInTempOutputBuffer = frameShift; 180 } 181 } 182 else /* variable host buffer size, add framesPerUserBuffer latency */ 183 { 184 bp->initialFramesInTempInputBuffer = 0; 185 bp->initialFramesInTempOutputBuffer = framesPerUserBuffer; 186 } 187 } 188 else 189 { 190 /* half duplex */ 191 bp->initialFramesInTempInputBuffer = 0; 192 bp->initialFramesInTempOutputBuffer = 0; 193 } 194 } 195 } 196 197 198 bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer; 199 bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer; 200 201 202 if( inputChannelCount > 0 ) 203 { 204 bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat ); 205 if( bytesPerSample > 0 ) 206 { 207 bp->bytesPerHostInputSample = bytesPerSample; 208 } 209 else 210 { 211 result = bytesPerSample; 212 goto error; 213 } 214 215 bytesPerSample = Pa_GetSampleSize( userInputSampleFormat ); 216 if( bytesPerSample > 0 ) 217 { 218 bp->bytesPerUserInputSample = bytesPerSample; 219 } 220 else 221 { 222 result = bytesPerSample; 223 goto error; 224 } 225 226 /* Under the assumption that no ADC in existence delivers better than 24bits resolution, 227 we disable dithering when host input format is paInt32 and user format is paInt24, 228 since the host samples will just be padded with zeros anyway. */ 229 230 tempInputStreamFlags = streamFlags; 231 if( !(tempInputStreamFlags & paDitherOff) /* dither is on */ 232 && (hostInputSampleFormat & paInt32) /* host input format is int32 */ 233 && (userInputSampleFormat & paInt24) /* user requested format is int24 */ ){ 234 235 tempInputStreamFlags = tempInputStreamFlags | paDitherOff; 236 } 237 238 bp->inputConverter = 239 PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags ); 240 241 bp->inputZeroer = PaUtil_SelectZeroer( userInputSampleFormat ); 242 243 bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1; 244 245 bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1; 246 247 bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved)); 248 249 tempInputBufferSize = 250 bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount; 251 252 bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize ); 253 if( bp->tempInputBuffer == 0 ) 254 { 255 result = paInsufficientMemory; 256 goto error; 257 } 258 259 if( bp->framesInTempInputBuffer > 0 ) 260 memset( bp->tempInputBuffer, 0, tempInputBufferSize ); 261 262 if( userInputSampleFormat & paNonInterleaved ) 263 { 264 bp->tempInputBufferPtrs = 265 (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount ); 266 if( bp->tempInputBufferPtrs == 0 ) 267 { 268 result = paInsufficientMemory; 269 goto error; 270 } 271 } 272 273 bp->hostInputChannels[0] = (PaUtilChannelDescriptor*) 274 PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2); 275 if( bp->hostInputChannels[0] == 0 ) 276 { 277 result = paInsufficientMemory; 278 goto error; 279 } 280 281 bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount]; 282 } 283 284 if( outputChannelCount > 0 ) 285 { 286 bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat ); 287 if( bytesPerSample > 0 ) 288 { 289 bp->bytesPerHostOutputSample = bytesPerSample; 290 } 291 else 292 { 293 result = bytesPerSample; 294 goto error; 295 } 296 297 bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat ); 298 if( bytesPerSample > 0 ) 299 { 300 bp->bytesPerUserOutputSample = bytesPerSample; 301 } 302 else 303 { 304 result = bytesPerSample; 305 goto error; 306 } 307 308 bp->outputConverter = 309 PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags ); 310 311 bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat ); 312 313 bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1; 314 315 bp->hostOutputIsInterleaved = (hostOutputSampleFormat & paNonInterleaved)?0:1; 316 317 bp->userOutputSampleFormatIsEqualToHost = ((userOutputSampleFormat & ~paNonInterleaved) == (hostOutputSampleFormat & ~paNonInterleaved)); 318 319 tempOutputBufferSize = 320 bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount; 321 322 bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize ); 323 if( bp->tempOutputBuffer == 0 ) 324 { 325 result = paInsufficientMemory; 326 goto error; 327 } 328 329 if( bp->framesInTempOutputBuffer > 0 ) 330 memset( bp->tempOutputBuffer, 0, tempOutputBufferSize ); 331 332 if( userOutputSampleFormat & paNonInterleaved ) 333 { 334 bp->tempOutputBufferPtrs = 335 (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount ); 336 if( bp->tempOutputBufferPtrs == 0 ) 337 { 338 result = paInsufficientMemory; 339 goto error; 340 } 341 } 342 343 bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*) 344 PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 ); 345 if( bp->hostOutputChannels[0] == 0 ) 346 { 347 result = paInsufficientMemory; 348 goto error; 349 } 350 351 bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount]; 352 } 353 354 PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator ); 355 356 bp->samplePeriod = 1. / sampleRate; 357 358 bp->streamCallback = streamCallback; 359 bp->userData = userData; 360 361 return result; 362 363 error: 364 if( bp->tempInputBuffer ) 365 PaUtil_FreeMemory( bp->tempInputBuffer ); 366 367 if( bp->tempInputBufferPtrs ) 368 PaUtil_FreeMemory( bp->tempInputBufferPtrs ); 369 370 if( bp->hostInputChannels[0] ) 371 PaUtil_FreeMemory( bp->hostInputChannels[0] ); 372 373 if( bp->tempOutputBuffer ) 374 PaUtil_FreeMemory( bp->tempOutputBuffer ); 375 376 if( bp->tempOutputBufferPtrs ) 377 PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); 378 379 if( bp->hostOutputChannels[0] ) 380 PaUtil_FreeMemory( bp->hostOutputChannels[0] ); 381 382 return result; 383 } 384 385 386 void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp ) 387 { 388 if( bp->tempInputBuffer ) 389 PaUtil_FreeMemory( bp->tempInputBuffer ); 390 391 if( bp->tempInputBufferPtrs ) 392 PaUtil_FreeMemory( bp->tempInputBufferPtrs ); 393 394 if( bp->hostInputChannels[0] ) 395 PaUtil_FreeMemory( bp->hostInputChannels[0] ); 396 397 if( bp->tempOutputBuffer ) 398 PaUtil_FreeMemory( bp->tempOutputBuffer ); 399 400 if( bp->tempOutputBufferPtrs ) 401 PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); 402 403 if( bp->hostOutputChannels[0] ) 404 PaUtil_FreeMemory( bp->hostOutputChannels[0] ); 405 } 406 407 408 void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp ) 409 { 410 unsigned long tempInputBufferSize, tempOutputBufferSize; 411 412 bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer; 413 bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer; 414 415 if( bp->framesInTempInputBuffer > 0 ) 416 { 417 tempInputBufferSize = 418 bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount; 419 memset( bp->tempInputBuffer, 0, tempInputBufferSize ); 420 } 421 422 if( bp->framesInTempOutputBuffer > 0 ) 423 { 424 tempOutputBufferSize = 425 bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount; 426 memset( bp->tempOutputBuffer, 0, tempOutputBufferSize ); 427 } 428 } 429 430 431 unsigned long PaUtil_GetBufferProcessorInputLatencyFrames( PaUtilBufferProcessor* bp ) 432 { 433 return bp->initialFramesInTempInputBuffer; 434 } 435 436 437 unsigned long PaUtil_GetBufferProcessorOutputLatencyFrames( PaUtilBufferProcessor* bp ) 438 { 439 return bp->initialFramesInTempOutputBuffer; 440 } 441 442 443 void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp, 444 unsigned long frameCount ) 445 { 446 if( frameCount == 0 ) 447 bp->hostInputFrameCount[0] = bp->framesPerHostBuffer; 448 else 449 bp->hostInputFrameCount[0] = frameCount; 450 } 451 452 453 void PaUtil_SetNoInput( PaUtilBufferProcessor* bp ) 454 { 455 assert( bp->inputChannelCount > 0 ); 456 457 bp->hostInputChannels[0][0].data = 0; 458 } 459 460 461 void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp, 462 unsigned int channel, void *data, unsigned int stride ) 463 { 464 assert( channel < bp->inputChannelCount ); 465 466 bp->hostInputChannels[0][channel].data = data; 467 bp->hostInputChannels[0][channel].stride = stride; 468 } 469 470 471 void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp, 472 unsigned int firstChannel, void *data, unsigned int channelCount ) 473 { 474 unsigned int i; 475 unsigned int channel = firstChannel; 476 unsigned char *p = (unsigned char*)data; 477 478 if( channelCount == 0 ) 479 channelCount = bp->inputChannelCount; 480 481 assert( firstChannel < bp->inputChannelCount ); 482 assert( firstChannel + channelCount <= bp->inputChannelCount ); 483 assert( bp->hostInputIsInterleaved ); 484 485 for( i=0; i< channelCount; ++i ) 486 { 487 bp->hostInputChannels[0][channel+i].data = p; 488 p += bp->bytesPerHostInputSample; 489 bp->hostInputChannels[0][channel+i].stride = channelCount; 490 } 491 } 492 493 494 void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp, 495 unsigned int channel, void *data ) 496 { 497 assert( channel < bp->inputChannelCount ); 498 assert( !bp->hostInputIsInterleaved ); 499 500 bp->hostInputChannels[0][channel].data = data; 501 bp->hostInputChannels[0][channel].stride = 1; 502 } 503 504 505 void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp, 506 unsigned long frameCount ) 507 { 508 bp->hostInputFrameCount[1] = frameCount; 509 } 510 511 512 void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp, 513 unsigned int channel, void *data, unsigned int stride ) 514 { 515 assert( channel < bp->inputChannelCount ); 516 517 bp->hostInputChannels[1][channel].data = data; 518 bp->hostInputChannels[1][channel].stride = stride; 519 } 520 521 522 void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp, 523 unsigned int firstChannel, void *data, unsigned int channelCount ) 524 { 525 unsigned int i; 526 unsigned int channel = firstChannel; 527 unsigned char *p = (unsigned char*)data; 528 529 if( channelCount == 0 ) 530 channelCount = bp->inputChannelCount; 531 532 assert( firstChannel < bp->inputChannelCount ); 533 assert( firstChannel + channelCount <= bp->inputChannelCount ); 534 assert( bp->hostInputIsInterleaved ); 535 536 for( i=0; i< channelCount; ++i ) 537 { 538 bp->hostInputChannels[1][channel+i].data = p; 539 p += bp->bytesPerHostInputSample; 540 bp->hostInputChannels[1][channel+i].stride = channelCount; 541 } 542 } 543 544 545 void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp, 546 unsigned int channel, void *data ) 547 { 548 assert( channel < bp->inputChannelCount ); 549 assert( !bp->hostInputIsInterleaved ); 550 551 bp->hostInputChannels[1][channel].data = data; 552 bp->hostInputChannels[1][channel].stride = 1; 553 } 554 555 556 void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp, 557 unsigned long frameCount ) 558 { 559 if( frameCount == 0 ) 560 bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer; 561 else 562 bp->hostOutputFrameCount[0] = frameCount; 563 } 564 565 566 void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp ) 567 { 568 assert( bp->outputChannelCount > 0 ); 569 570 bp->hostOutputChannels[0][0].data = 0; 571 572 /* note that only NonAdaptingProcess is able to deal with no output at this stage. not implemented for AdaptingProcess */ 573 } 574 575 576 void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp, 577 unsigned int channel, void *data, unsigned int stride ) 578 { 579 assert( channel < bp->outputChannelCount ); 580 assert( data != NULL ); 581 582 bp->hostOutputChannels[0][channel].data = data; 583 bp->hostOutputChannels[0][channel].stride = stride; 584 } 585 586 587 void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp, 588 unsigned int firstChannel, void *data, unsigned int channelCount ) 589 { 590 unsigned int i; 591 unsigned int channel = firstChannel; 592 unsigned char *p = (unsigned char*)data; 593 594 if( channelCount == 0 ) 595 channelCount = bp->outputChannelCount; 596 597 assert( firstChannel < bp->outputChannelCount ); 598 assert( firstChannel + channelCount <= bp->outputChannelCount ); 599 assert( bp->hostOutputIsInterleaved ); 600 601 for( i=0; i< channelCount; ++i ) 602 { 603 PaUtil_SetOutputChannel( bp, channel + i, p, channelCount ); 604 p += bp->bytesPerHostOutputSample; 605 } 606 } 607 608 609 void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, 610 unsigned int channel, void *data ) 611 { 612 assert( channel < bp->outputChannelCount ); 613 assert( !bp->hostOutputIsInterleaved ); 614 615 PaUtil_SetOutputChannel( bp, channel, data, 1 ); 616 } 617 618 619 void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp, 620 unsigned long frameCount ) 621 { 622 bp->hostOutputFrameCount[1] = frameCount; 623 } 624 625 626 void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp, 627 unsigned int channel, void *data, unsigned int stride ) 628 { 629 assert( channel < bp->outputChannelCount ); 630 assert( data != NULL ); 631 632 bp->hostOutputChannels[1][channel].data = data; 633 bp->hostOutputChannels[1][channel].stride = stride; 634 } 635 636 637 void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp, 638 unsigned int firstChannel, void *data, unsigned int channelCount ) 639 { 640 unsigned int i; 641 unsigned int channel = firstChannel; 642 unsigned char *p = (unsigned char*)data; 643 644 if( channelCount == 0 ) 645 channelCount = bp->outputChannelCount; 646 647 assert( firstChannel < bp->outputChannelCount ); 648 assert( firstChannel + channelCount <= bp->outputChannelCount ); 649 assert( bp->hostOutputIsInterleaved ); 650 651 for( i=0; i< channelCount; ++i ) 652 { 653 PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount ); 654 p += bp->bytesPerHostOutputSample; 655 } 656 } 657 658 659 void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, 660 unsigned int channel, void *data ) 661 { 662 assert( channel < bp->outputChannelCount ); 663 assert( !bp->hostOutputIsInterleaved ); 664 665 PaUtil_Set2ndOutputChannel( bp, channel, data, 1 ); 666 } 667 668 669 void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp, 670 PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags ) 671 { 672 bp->timeInfo = timeInfo; 673 674 /* the first streamCallback will be called to process samples which are 675 currently in the input buffer before the ones starting at the timeInfo time */ 676 677 bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod; 678 679 /* We just pass through timeInfo->currentTime provided by the caller. This is 680 not strictly conformant to the word of the spec, since the buffer processor 681 might call the callback multiple times, and we never refresh currentTime. */ 682 683 /* the first streamCallback will be called to generate samples which will be 684 outputted after the frames currently in the output buffer have been 685 outputted. */ 686 bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod; 687 688 bp->callbackStatusFlags = callbackStatusFlags; 689 690 bp->hostInputFrameCount[1] = 0; 691 bp->hostOutputFrameCount[1] = 0; 692 } 693 694 695 /* 696 NonAdaptingProcess() is a simple buffer copying adaptor that can handle 697 both full and half duplex copies. It processes framesToProcess frames, 698 broken into blocks bp->framesPerTempBuffer long. 699 This routine can be used when the streamCallback doesn't care what length 700 the buffers are, or when framesToProcess is an integer multiple of 701 bp->framesPerTempBuffer, in which case streamCallback will always be called 702 with bp->framesPerTempBuffer samples. 703 */ 704 static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, 705 int *streamCallbackResult, 706 PaUtilChannelDescriptor *hostInputChannels, 707 PaUtilChannelDescriptor *hostOutputChannels, 708 unsigned long framesToProcess ) 709 { 710 void *userInput, *userOutput; 711 unsigned char *srcBytePtr, *destBytePtr; 712 unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ 713 unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ 714 unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ 715 unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ 716 unsigned int i; 717 unsigned long frameCount; 718 unsigned long framesToGo = framesToProcess; 719 unsigned long framesProcessed = 0; 720 int skipOutputConvert = 0; 721 int skipInputConvert = 0; 722 723 724 if( *streamCallbackResult == paContinue ) 725 { 726 do 727 { 728 frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo ); 729 730 /* configure user input buffer and convert input data (host -> user) */ 731 if( bp->inputChannelCount == 0 ) 732 { 733 /* no input */ 734 userInput = 0; 735 } 736 else /* there are input channels */ 737 { 738 739 destBytePtr = (unsigned char *)bp->tempInputBuffer; 740 741 if( bp->userInputIsInterleaved ) 742 { 743 destSampleStrideSamples = bp->inputChannelCount; 744 destChannelStrideBytes = bp->bytesPerUserInputSample; 745 746 /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved, 747 * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */ 748 if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved 749 && bp->hostInputChannels[0][0].data && bp->inputChannelCount == hostInputChannels[0].stride ) 750 { 751 userInput = hostInputChannels[0].data; 752 destBytePtr = (unsigned char *)hostInputChannels[0].data; 753 skipInputConvert = 1; 754 } 755 else 756 { 757 userInput = bp->tempInputBuffer; 758 } 759 } 760 else /* user input is not interleaved */ 761 { 762 destSampleStrideSamples = 1; 763 destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample; 764 765 /* setup non-interleaved ptrs */ 766 if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved && bp->hostInputChannels[0][0].data ) 767 { 768 for( i=0; i<bp->inputChannelCount; ++i ) 769 { 770 bp->tempInputBufferPtrs[i] = hostInputChannels[i].data; 771 } 772 skipInputConvert = 1; 773 } 774 else 775 { 776 for( i=0; i<bp->inputChannelCount; ++i ) 777 { 778 bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + 779 i * bp->bytesPerUserInputSample * frameCount; 780 } 781 } 782 783 userInput = bp->tempInputBufferPtrs; 784 } 785 786 if( !bp->hostInputChannels[0][0].data ) 787 { 788 /* no input was supplied (see PaUtil_SetNoInput), so 789 zero the input buffer */ 790 791 for( i=0; i<bp->inputChannelCount; ++i ) 792 { 793 bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount ); 794 destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ 795 } 796 } 797 else 798 { 799 if( skipInputConvert ) 800 { 801 for( i=0; i<bp->inputChannelCount; ++i ) 802 { 803 /* advance src ptr for next iteration */ 804 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + 805 frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; 806 } 807 } 808 else 809 { 810 for( i=0; i<bp->inputChannelCount; ++i ) 811 { 812 bp->inputConverter( destBytePtr, destSampleStrideSamples, 813 hostInputChannels[i].data, 814 hostInputChannels[i].stride, 815 frameCount, &bp->ditherGenerator ); 816 817 destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ 818 819 /* advance src ptr for next iteration */ 820 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + 821 frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; 822 } 823 } 824 } 825 } 826 827 /* configure user output buffer */ 828 if( bp->outputChannelCount == 0 ) 829 { 830 /* no output */ 831 userOutput = 0; 832 } 833 else /* there are output channels */ 834 { 835 if( bp->userOutputIsInterleaved ) 836 { 837 /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved, 838 * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */ 839 if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved 840 && bp->outputChannelCount == hostOutputChannels[0].stride ) 841 { 842 userOutput = hostOutputChannels[0].data; 843 skipOutputConvert = 1; 844 } 845 else 846 { 847 userOutput = bp->tempOutputBuffer; 848 } 849 } 850 else /* user output is not interleaved */ 851 { 852 if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved ) 853 { 854 for( i=0; i<bp->outputChannelCount; ++i ) 855 { 856 bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data; 857 } 858 skipOutputConvert = 1; 859 } 860 else 861 { 862 for( i=0; i<bp->outputChannelCount; ++i ) 863 { 864 bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + 865 i * bp->bytesPerUserOutputSample * frameCount; 866 } 867 } 868 869 userOutput = bp->tempOutputBufferPtrs; 870 } 871 } 872 873 *streamCallbackResult = bp->streamCallback( userInput, userOutput, 874 frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData ); 875 876 if( *streamCallbackResult == paAbort ) 877 { 878 /* callback returned paAbort, don't advance framesProcessed 879 and framesToGo, they will be handled below */ 880 } 881 else 882 { 883 bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod; 884 bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod; 885 886 /* convert output data (user -> host) */ 887 888 if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data ) 889 { 890 if( skipOutputConvert ) 891 { 892 for( i=0; i<bp->outputChannelCount; ++i ) 893 { 894 /* advance dest ptr for next iteration */ 895 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + 896 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; 897 } 898 } 899 else 900 { 901 902 srcBytePtr = (unsigned char *)bp->tempOutputBuffer; 903 904 if( bp->userOutputIsInterleaved ) 905 { 906 srcSampleStrideSamples = bp->outputChannelCount; 907 srcChannelStrideBytes = bp->bytesPerUserOutputSample; 908 } 909 else /* user output is not interleaved */ 910 { 911 srcSampleStrideSamples = 1; 912 srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample; 913 } 914 915 for( i=0; i<bp->outputChannelCount; ++i ) 916 { 917 bp->outputConverter( hostOutputChannels[i].data, 918 hostOutputChannels[i].stride, 919 srcBytePtr, srcSampleStrideSamples, 920 frameCount, &bp->ditherGenerator ); 921 922 srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ 923 924 /* advance dest ptr for next iteration */ 925 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + 926 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; 927 } 928 } 929 } 930 931 framesProcessed += frameCount; 932 933 framesToGo -= frameCount; 934 } 935 } 936 while( framesToGo > 0 && *streamCallbackResult == paContinue ); 937 } 938 939 if( framesToGo > 0 ) 940 { 941 /* zero any remaining frames output. There will only be remaining frames 942 if the callback has returned paComplete or paAbort */ 943 944 frameCount = framesToGo; 945 946 if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data ) 947 { 948 for( i=0; i<bp->outputChannelCount; ++i ) 949 { 950 bp->outputZeroer( hostOutputChannels[i].data, 951 hostOutputChannels[i].stride, 952 frameCount ); 953 954 /* advance dest ptr for next iteration */ 955 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + 956 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; 957 } 958 } 959 960 framesProcessed += frameCount; 961 } 962 963 return framesProcessed; 964 } 965 966 967 /* 968 AdaptingInputOnlyProcess() is a half duplex input buffer processor. It 969 converts data from the input buffers into the temporary input buffer, 970 when the temporary input buffer is full, it calls the streamCallback. 971 */ 972 static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp, 973 int *streamCallbackResult, 974 PaUtilChannelDescriptor *hostInputChannels, 975 unsigned long framesToProcess ) 976 { 977 void *userInput, *userOutput; 978 unsigned char *destBytePtr; 979 unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ 980 unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ 981 unsigned int i; 982 unsigned long frameCount; 983 unsigned long framesToGo = framesToProcess; 984 unsigned long framesProcessed = 0; 985 986 userOutput = 0; 987 988 do 989 { 990 frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer ) 991 ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer ) 992 : framesToGo; 993 994 /* convert frameCount samples into temp buffer */ 995 996 if( bp->userInputIsInterleaved ) 997 { 998 destBytePtr = ((unsigned char*)bp->tempInputBuffer) + 999 bp->bytesPerUserInputSample * bp->inputChannelCount * 1000 bp->framesInTempInputBuffer; 1001 1002 destSampleStrideSamples = bp->inputChannelCount; 1003 destChannelStrideBytes = bp->bytesPerUserInputSample; 1004 1005 userInput = bp->tempInputBuffer; 1006 } 1007 else /* user input is not interleaved */ 1008 { 1009 destBytePtr = ((unsigned char*)bp->tempInputBuffer) + 1010 bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; 1011 1012 destSampleStrideSamples = 1; 1013 destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; 1014 1015 /* setup non-interleaved ptrs */ 1016 for( i=0; i<bp->inputChannelCount; ++i ) 1017 { 1018 bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + 1019 i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer; 1020 } 1021 1022 userInput = bp->tempInputBufferPtrs; 1023 } 1024 1025 for( i=0; i<bp->inputChannelCount; ++i ) 1026 { 1027 bp->inputConverter( destBytePtr, destSampleStrideSamples, 1028 hostInputChannels[i].data, 1029 hostInputChannels[i].stride, 1030 frameCount, &bp->ditherGenerator ); 1031 1032 destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ 1033 1034 /* advance src ptr for next iteration */ 1035 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + 1036 frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; 1037 } 1038 1039 bp->framesInTempInputBuffer += frameCount; 1040 1041 if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer ) 1042 { 1043 /** 1044 @todo (non-critical optimisation) 1045 The conditional below implements the continue/complete/abort mechanism 1046 simply by continuing on iterating through the input buffer, but not 1047 passing the data to the callback. With care, the outer loop could be 1048 terminated earlier, thus some unneeded conversion cycles would be 1049 saved. 1050 */ 1051 if( *streamCallbackResult == paContinue ) 1052 { 1053 bp->timeInfo->outputBufferDacTime = 0; 1054 1055 *streamCallbackResult = bp->streamCallback( userInput, userOutput, 1056 bp->framesPerUserBuffer, bp->timeInfo, 1057 bp->callbackStatusFlags, bp->userData ); 1058 1059 bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod; 1060 } 1061 1062 bp->framesInTempInputBuffer = 0; 1063 } 1064 1065 framesProcessed += frameCount; 1066 1067 framesToGo -= frameCount; 1068 }while( framesToGo > 0 ); 1069 1070 return framesProcessed; 1071 } 1072 1073 1074 /* 1075 AdaptingOutputOnlyProcess() is a half duplex output buffer processor. 1076 It converts data from the temporary output buffer, to the output buffers, 1077 when the temporary output buffer is empty, it calls the streamCallback. 1078 */ 1079 static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp, 1080 int *streamCallbackResult, 1081 PaUtilChannelDescriptor *hostOutputChannels, 1082 unsigned long framesToProcess ) 1083 { 1084 void *userInput, *userOutput; 1085 unsigned char *srcBytePtr; 1086 unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ 1087 unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ 1088 unsigned int i; 1089 unsigned long frameCount; 1090 unsigned long framesToGo = framesToProcess; 1091 unsigned long framesProcessed = 0; 1092 1093 do 1094 { 1095 if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue ) 1096 { 1097 userInput = 0; 1098 1099 /* setup userOutput */ 1100 if( bp->userOutputIsInterleaved ) 1101 { 1102 userOutput = bp->tempOutputBuffer; 1103 } 1104 else /* user output is not interleaved */ 1105 { 1106 for( i = 0; i < bp->outputChannelCount; ++i ) 1107 { 1108 bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + 1109 i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; 1110 } 1111 1112 userOutput = bp->tempOutputBufferPtrs; 1113 } 1114 1115 bp->timeInfo->inputBufferAdcTime = 0; 1116 1117 *streamCallbackResult = bp->streamCallback( userInput, userOutput, 1118 bp->framesPerUserBuffer, bp->timeInfo, 1119 bp->callbackStatusFlags, bp->userData ); 1120 1121 if( *streamCallbackResult == paAbort ) 1122 { 1123 /* if the callback returned paAbort, we disregard its output */ 1124 } 1125 else 1126 { 1127 bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; 1128 1129 bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; 1130 } 1131 } 1132 1133 if( bp->framesInTempOutputBuffer > 0 ) 1134 { 1135 /* convert frameCount frames from user buffer to host buffer */ 1136 1137 frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo ); 1138 1139 if( bp->userOutputIsInterleaved ) 1140 { 1141 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + 1142 bp->bytesPerUserOutputSample * bp->outputChannelCount * 1143 (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); 1144 1145 srcSampleStrideSamples = bp->outputChannelCount; 1146 srcChannelStrideBytes = bp->bytesPerUserOutputSample; 1147 } 1148 else /* user output is not interleaved */ 1149 { 1150 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + 1151 bp->bytesPerUserOutputSample * 1152 (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); 1153 1154 srcSampleStrideSamples = 1; 1155 srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; 1156 } 1157 1158 for( i=0; i<bp->outputChannelCount; ++i ) 1159 { 1160 bp->outputConverter( hostOutputChannels[i].data, 1161 hostOutputChannels[i].stride, 1162 srcBytePtr, srcSampleStrideSamples, 1163 frameCount, &bp->ditherGenerator ); 1164 1165 srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ 1166 1167 /* advance dest ptr for next iteration */ 1168 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + 1169 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; 1170 } 1171 1172 bp->framesInTempOutputBuffer -= frameCount; 1173 } 1174 else 1175 { 1176 /* no more user data is available because the callback has returned 1177 paComplete or paAbort. Fill the remainder of the host buffer 1178 with zeros. 1179 */ 1180 1181 frameCount = framesToGo; 1182 1183 for( i=0; i<bp->outputChannelCount; ++i ) 1184 { 1185 bp->outputZeroer( hostOutputChannels[i].data, 1186 hostOutputChannels[i].stride, 1187 frameCount ); 1188 1189 /* advance dest ptr for next iteration */ 1190 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + 1191 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; 1192 } 1193 } 1194 1195 framesProcessed += frameCount; 1196 1197 framesToGo -= frameCount; 1198 1199 }while( framesToGo > 0 ); 1200 1201 return framesProcessed; 1202 } 1203 1204 /* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from 1205 tempOutputBuffer to hostOutputChannels. This includes data conversion 1206 and interleaving. 1207 */ 1208 static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp) 1209 { 1210 unsigned long maxFramesToCopy; 1211 PaUtilChannelDescriptor *hostOutputChannels; 1212 unsigned int frameCount; 1213 unsigned char *srcBytePtr; 1214 unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ 1215 unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ 1216 unsigned int i; 1217 1218 /* copy frames from user to host output buffers */ 1219 while( bp->framesInTempOutputBuffer > 0 && 1220 ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) ) 1221 { 1222 maxFramesToCopy = bp->framesInTempOutputBuffer; 1223 1224 /* select the output buffer set (1st or 2nd) */ 1225 if( bp->hostOutputFrameCount[0] > 0 ) 1226 { 1227 hostOutputChannels = bp->hostOutputChannels[0]; 1228 frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy ); 1229 } 1230 else 1231 { 1232 hostOutputChannels = bp->hostOutputChannels[1]; 1233 frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy ); 1234 } 1235 1236 if( bp->userOutputIsInterleaved ) 1237 { 1238 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + 1239 bp->bytesPerUserOutputSample * bp->outputChannelCount * 1240 (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); 1241 1242 srcSampleStrideSamples = bp->outputChannelCount; 1243 srcChannelStrideBytes = bp->bytesPerUserOutputSample; 1244 } 1245 else /* user output is not interleaved */ 1246 { 1247 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + 1248 bp->bytesPerUserOutputSample * 1249 (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); 1250 1251 srcSampleStrideSamples = 1; 1252 srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; 1253 } 1254 1255 for( i=0; i<bp->outputChannelCount; ++i ) 1256 { 1257 assert( hostOutputChannels[i].data != NULL ); 1258 bp->outputConverter( hostOutputChannels[i].data, 1259 hostOutputChannels[i].stride, 1260 srcBytePtr, srcSampleStrideSamples, 1261 frameCount, &bp->ditherGenerator ); 1262 1263 srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ 1264 1265 /* advance dest ptr for next iteration */ 1266 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + 1267 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; 1268 } 1269 1270 if( bp->hostOutputFrameCount[0] > 0 ) 1271 bp->hostOutputFrameCount[0] -= frameCount; 1272 else 1273 bp->hostOutputFrameCount[1] -= frameCount; 1274 1275 bp->framesInTempOutputBuffer -= frameCount; 1276 } 1277 } 1278 1279 /* 1280 AdaptingProcess is a full duplex adapting buffer processor. It converts 1281 data from the temporary output buffer into the host output buffers, then 1282 from the host input buffers into the temporary input buffers. Calling the 1283 streamCallback when necessary. 1284 When processPartialUserBuffers is 0, all available input data will be 1285 consumed and all available output space will be filled. When 1286 processPartialUserBuffers is non-zero, as many full user buffers 1287 as possible will be processed, but partial buffers will not be consumed. 1288 */ 1289 static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp, 1290 int *streamCallbackResult, int processPartialUserBuffers ) 1291 { 1292 void *userInput, *userOutput; 1293 unsigned long framesProcessed = 0; 1294 unsigned long framesAvailable; 1295 unsigned long endProcessingMinFrameCount; 1296 unsigned long maxFramesToCopy; 1297 PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels; 1298 unsigned int frameCount; 1299 unsigned char *destBytePtr; 1300 unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ 1301 unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ 1302 unsigned int i, j; 1303 1304 1305 framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */ 1306 1307 if( processPartialUserBuffers ) 1308 endProcessingMinFrameCount = 0; 1309 else 1310 endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1); 1311 1312 /* Fill host output with remaining frames in user output (tempOutputBuffer) */ 1313 CopyTempOutputBuffersToHostOutputBuffers( bp ); 1314 1315 while( framesAvailable > endProcessingMinFrameCount ) 1316 { 1317 1318 if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue ) 1319 { 1320 /* the callback will not be called any more, so zero what remains 1321 of the host output buffers */ 1322 1323 for( i=0; i<2; ++i ) 1324 { 1325 frameCount = bp->hostOutputFrameCount[i]; 1326 if( frameCount > 0 ) 1327 { 1328 hostOutputChannels = bp->hostOutputChannels[i]; 1329 1330 for( j=0; j<bp->outputChannelCount; ++j ) 1331 { 1332 bp->outputZeroer( hostOutputChannels[j].data, 1333 hostOutputChannels[j].stride, 1334 frameCount ); 1335 1336 /* advance dest ptr for next iteration */ 1337 hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) + 1338 frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample; 1339 } 1340 bp->hostOutputFrameCount[i] = 0; 1341 } 1342 } 1343 } 1344 1345 1346 /* copy frames from host to user input buffers */ 1347 while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer && 1348 ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) ) 1349 { 1350 maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer; 1351 1352 /* select the input buffer set (1st or 2nd) */ 1353 if( bp->hostInputFrameCount[0] > 0 ) 1354 { 1355 hostInputChannels = bp->hostInputChannels[0]; 1356 frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy ); 1357 } 1358 else 1359 { 1360 hostInputChannels = bp->hostInputChannels[1]; 1361 frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy ); 1362 } 1363 1364 /* configure conversion destination pointers */ 1365 if( bp->userInputIsInterleaved ) 1366 { 1367 destBytePtr = ((unsigned char*)bp->tempInputBuffer) + 1368 bp->bytesPerUserInputSample * bp->inputChannelCount * 1369 bp->framesInTempInputBuffer; 1370 1371 destSampleStrideSamples = bp->inputChannelCount; 1372 destChannelStrideBytes = bp->bytesPerUserInputSample; 1373 } 1374 else /* user input is not interleaved */ 1375 { 1376 destBytePtr = ((unsigned char*)bp->tempInputBuffer) + 1377 bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; 1378 1379 destSampleStrideSamples = 1; 1380 destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; 1381 } 1382 1383 for( i=0; i<bp->inputChannelCount; ++i ) 1384 { 1385 bp->inputConverter( destBytePtr, destSampleStrideSamples, 1386 hostInputChannels[i].data, 1387 hostInputChannels[i].stride, 1388 frameCount, &bp->ditherGenerator ); 1389 1390 destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ 1391 1392 /* advance src ptr for next iteration */ 1393 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + 1394 frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; 1395 } 1396 1397 if( bp->hostInputFrameCount[0] > 0 ) 1398 bp->hostInputFrameCount[0] -= frameCount; 1399 else 1400 bp->hostInputFrameCount[1] -= frameCount; 1401 1402 bp->framesInTempInputBuffer += frameCount; 1403 1404 /* update framesAvailable and framesProcessed based on input consumed 1405 unless something is very wrong this will also correspond to the 1406 amount of output generated */ 1407 framesAvailable -= frameCount; 1408 framesProcessed += frameCount; 1409 } 1410 1411 /* call streamCallback */ 1412 if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer && 1413 bp->framesInTempOutputBuffer == 0 ) 1414 { 1415 if( *streamCallbackResult == paContinue ) 1416 { 1417 /* setup userInput */ 1418 if( bp->userInputIsInterleaved ) 1419 { 1420 userInput = bp->tempInputBuffer; 1421 } 1422 else /* user input is not interleaved */ 1423 { 1424 for( i = 0; i < bp->inputChannelCount; ++i ) 1425 { 1426 bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + 1427 i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample; 1428 } 1429 1430 userInput = bp->tempInputBufferPtrs; 1431 } 1432 1433 /* setup userOutput */ 1434 if( bp->userOutputIsInterleaved ) 1435 { 1436 userOutput = bp->tempOutputBuffer; 1437 } 1438 else /* user output is not interleaved */ 1439 { 1440 for( i = 0; i < bp->outputChannelCount; ++i ) 1441 { 1442 bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + 1443 i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; 1444 } 1445 1446 userOutput = bp->tempOutputBufferPtrs; 1447 } 1448 1449 /* call streamCallback */ 1450 1451 *streamCallbackResult = bp->streamCallback( userInput, userOutput, 1452 bp->framesPerUserBuffer, bp->timeInfo, 1453 bp->callbackStatusFlags, bp->userData ); 1454 1455 bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod; 1456 bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; 1457 1458 bp->framesInTempInputBuffer = 0; 1459 1460 if( *streamCallbackResult == paAbort ) 1461 bp->framesInTempOutputBuffer = 0; 1462 else 1463 bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; 1464 } 1465 else 1466 { 1467 /* paComplete or paAbort has already been called. */ 1468 1469 bp->framesInTempInputBuffer = 0; 1470 } 1471 } 1472 1473 /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels) 1474 Means to process the user output provided by the callback. Has to be called after 1475 each callback. */ 1476 CopyTempOutputBuffersToHostOutputBuffers( bp ); 1477 1478 } 1479 1480 return framesProcessed; 1481 } 1482 1483 1484 unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult ) 1485 { 1486 unsigned long framesToProcess, framesToGo; 1487 unsigned long framesProcessed = 0; 1488 1489 if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 1490 && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */ 1491 && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ ) 1492 { 1493 assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) == 1494 (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) ); 1495 } 1496 1497 assert( *streamCallbackResult == paContinue 1498 || *streamCallbackResult == paComplete 1499 || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */ 1500 1501 if( bp->useNonAdaptingProcess ) 1502 { 1503 if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) 1504 { 1505 /* full duplex non-adapting process, splice buffers if they are 1506 different lengths */ 1507 1508 framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */ 1509 1510 do{ 1511 unsigned long noInputInputFrameCount; 1512 unsigned long *hostInputFrameCount; 1513 PaUtilChannelDescriptor *hostInputChannels; 1514 unsigned long noOutputOutputFrameCount; 1515 unsigned long *hostOutputFrameCount; 1516 PaUtilChannelDescriptor *hostOutputChannels; 1517 unsigned long framesProcessedThisIteration; 1518 1519 if( !bp->hostInputChannels[0][0].data ) 1520 { 1521 /* no input was supplied (see PaUtil_SetNoInput) 1522 NonAdaptingProcess knows how to deal with this 1523 */ 1524 noInputInputFrameCount = framesToGo; 1525 hostInputFrameCount = &noInputInputFrameCount; 1526 hostInputChannels = 0; 1527 } 1528 else if( bp->hostInputFrameCount[0] != 0 ) 1529 { 1530 hostInputFrameCount = &bp->hostInputFrameCount[0]; 1531 hostInputChannels = bp->hostInputChannels[0]; 1532 } 1533 else 1534 { 1535 hostInputFrameCount = &bp->hostInputFrameCount[1]; 1536 hostInputChannels = bp->hostInputChannels[1]; 1537 } 1538 1539 if( !bp->hostOutputChannels[0][0].data ) 1540 { 1541 /* no output was supplied (see PaUtil_SetNoOutput) 1542 NonAdaptingProcess knows how to deal with this 1543 */ 1544 noOutputOutputFrameCount = framesToGo; 1545 hostOutputFrameCount = &noOutputOutputFrameCount; 1546 hostOutputChannels = 0; 1547 } 1548 if( bp->hostOutputFrameCount[0] != 0 ) 1549 { 1550 hostOutputFrameCount = &bp->hostOutputFrameCount[0]; 1551 hostOutputChannels = bp->hostOutputChannels[0]; 1552 } 1553 else 1554 { 1555 hostOutputFrameCount = &bp->hostOutputFrameCount[1]; 1556 hostOutputChannels = bp->hostOutputChannels[1]; 1557 } 1558 1559 framesToProcess = PA_MIN_( *hostInputFrameCount, 1560 *hostOutputFrameCount ); 1561 1562 assert( framesToProcess != 0 ); 1563 1564 framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult, 1565 hostInputChannels, hostOutputChannels, 1566 framesToProcess ); 1567 1568 *hostInputFrameCount -= framesProcessedThisIteration; 1569 *hostOutputFrameCount -= framesProcessedThisIteration; 1570 1571 framesProcessed += framesProcessedThisIteration; 1572 framesToGo -= framesProcessedThisIteration; 1573 1574 }while( framesToGo > 0 ); 1575 } 1576 else 1577 { 1578 /* half duplex non-adapting process, just process 1st and 2nd buffer */ 1579 /* process first buffer */ 1580 1581 framesToProcess = (bp->inputChannelCount != 0) 1582 ? bp->hostInputFrameCount[0] 1583 : bp->hostOutputFrameCount[0]; 1584 1585 framesProcessed = NonAdaptingProcess( bp, streamCallbackResult, 1586 bp->hostInputChannels[0], bp->hostOutputChannels[0], 1587 framesToProcess ); 1588 1589 /* process second buffer if provided */ 1590 1591 framesToProcess = (bp->inputChannelCount != 0) 1592 ? bp->hostInputFrameCount[1] 1593 : bp->hostOutputFrameCount[1]; 1594 if( framesToProcess > 0 ) 1595 { 1596 framesProcessed += NonAdaptingProcess( bp, streamCallbackResult, 1597 bp->hostInputChannels[1], bp->hostOutputChannels[1], 1598 framesToProcess ); 1599 } 1600 } 1601 } 1602 else /* block adaption necessary*/ 1603 { 1604 1605 if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) 1606 { 1607 /* full duplex */ 1608 1609 if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed ) 1610 { 1611 framesProcessed = AdaptingProcess( bp, streamCallbackResult, 1612 0 /* dont process partial user buffers */ ); 1613 } 1614 else 1615 { 1616 framesProcessed = AdaptingProcess( bp, streamCallbackResult, 1617 1 /* process partial user buffers */ ); 1618 } 1619 } 1620 else if( bp->inputChannelCount != 0 ) 1621 { 1622 /* input only */ 1623 framesToProcess = bp->hostInputFrameCount[0]; 1624 1625 framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult, 1626 bp->hostInputChannels[0], framesToProcess ); 1627 1628 framesToProcess = bp->hostInputFrameCount[1]; 1629 if( framesToProcess > 0 ) 1630 { 1631 framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult, 1632 bp->hostInputChannels[1], framesToProcess ); 1633 } 1634 } 1635 else 1636 { 1637 /* output only */ 1638 framesToProcess = bp->hostOutputFrameCount[0]; 1639 1640 framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult, 1641 bp->hostOutputChannels[0], framesToProcess ); 1642 1643 framesToProcess = bp->hostOutputFrameCount[1]; 1644 if( framesToProcess > 0 ) 1645 { 1646 framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult, 1647 bp->hostOutputChannels[1], framesToProcess ); 1648 } 1649 } 1650 } 1651 1652 return framesProcessed; 1653 } 1654 1655 1656 int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp ) 1657 { 1658 return (bp->framesInTempOutputBuffer) ? 0 : 1; 1659 } 1660 1661 1662 unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp, 1663 void **buffer, unsigned long frameCount ) 1664 { 1665 PaUtilChannelDescriptor *hostInputChannels; 1666 unsigned int framesToCopy; 1667 unsigned char *destBytePtr; 1668 void **nonInterleavedDestPtrs; 1669 unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ 1670 unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ 1671 unsigned int i; 1672 1673 hostInputChannels = bp->hostInputChannels[0]; 1674 framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount ); 1675 1676 if( bp->userInputIsInterleaved ) 1677 { 1678 destBytePtr = (unsigned char*)*buffer; 1679 1680 destSampleStrideSamples = bp->inputChannelCount; 1681 destChannelStrideBytes = bp->bytesPerUserInputSample; 1682 1683 for( i=0; i<bp->inputChannelCount; ++i ) 1684 { 1685 bp->inputConverter( destBytePtr, destSampleStrideSamples, 1686 hostInputChannels[i].data, 1687 hostInputChannels[i].stride, 1688 framesToCopy, &bp->ditherGenerator ); 1689 1690 destBytePtr += destChannelStrideBytes; /* skip to next dest channel */ 1691 1692 /* advance source ptr for next iteration */ 1693 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + 1694 framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; 1695 } 1696 1697 /* advance callers dest pointer (buffer) */ 1698 *buffer = ((unsigned char *)*buffer) + 1699 framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample; 1700 } 1701 else 1702 { 1703 /* user input is not interleaved */ 1704 1705 nonInterleavedDestPtrs = (void**)*buffer; 1706 1707 destSampleStrideSamples = 1; 1708 1709 for( i=0; i<bp->inputChannelCount; ++i ) 1710 { 1711 destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i]; 1712 1713 bp->inputConverter( destBytePtr, destSampleStrideSamples, 1714 hostInputChannels[i].data, 1715 hostInputChannels[i].stride, 1716 framesToCopy, &bp->ditherGenerator ); 1717 1718 /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */ 1719 destBytePtr += bp->bytesPerUserInputSample * framesToCopy; 1720 nonInterleavedDestPtrs[i] = destBytePtr; 1721 1722 /* advance source ptr for next iteration */ 1723 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + 1724 framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; 1725 } 1726 } 1727 1728 bp->hostInputFrameCount[0] -= framesToCopy; 1729 1730 return framesToCopy; 1731 } 1732 1733 unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp, 1734 const void ** buffer, unsigned long frameCount ) 1735 { 1736 PaUtilChannelDescriptor *hostOutputChannels; 1737 unsigned int framesToCopy; 1738 unsigned char *srcBytePtr; 1739 void **nonInterleavedSrcPtrs; 1740 unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ 1741 unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ 1742 unsigned int i; 1743 1744 hostOutputChannels = bp->hostOutputChannels[0]; 1745 framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount ); 1746 1747 if( bp->userOutputIsInterleaved ) 1748 { 1749 srcBytePtr = (unsigned char*)*buffer; 1750 1751 srcSampleStrideSamples = bp->outputChannelCount; 1752 srcChannelStrideBytes = bp->bytesPerUserOutputSample; 1753 1754 for( i=0; i<bp->outputChannelCount; ++i ) 1755 { 1756 bp->outputConverter( hostOutputChannels[i].data, 1757 hostOutputChannels[i].stride, 1758 srcBytePtr, srcSampleStrideSamples, 1759 framesToCopy, &bp->ditherGenerator ); 1760 1761 srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ 1762 1763 /* advance dest ptr for next iteration */ 1764 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + 1765 framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; 1766 } 1767 1768 /* advance callers source pointer (buffer) */ 1769 *buffer = ((unsigned char *)*buffer) + 1770 framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample; 1771 1772 } 1773 else 1774 { 1775 /* user output is not interleaved */ 1776 1777 nonInterleavedSrcPtrs = (void**)*buffer; 1778 1779 srcSampleStrideSamples = 1; 1780 1781 for( i=0; i<bp->outputChannelCount; ++i ) 1782 { 1783 srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i]; 1784 1785 bp->outputConverter( hostOutputChannels[i].data, 1786 hostOutputChannels[i].stride, 1787 srcBytePtr, srcSampleStrideSamples, 1788 framesToCopy, &bp->ditherGenerator ); 1789 1790 1791 /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */ 1792 srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy; 1793 nonInterleavedSrcPtrs[i] = srcBytePtr; 1794 1795 /* advance dest ptr for next iteration */ 1796 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + 1797 framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; 1798 } 1799 } 1800 1801 bp->hostOutputFrameCount[0] += framesToCopy; 1802 1803 return framesToCopy; 1804 } 1805 1806 1807 unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount ) 1808 { 1809 PaUtilChannelDescriptor *hostOutputChannels; 1810 unsigned int framesToZero; 1811 unsigned int i; 1812 1813 hostOutputChannels = bp->hostOutputChannels[0]; 1814 framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount ); 1815 1816 for( i=0; i<bp->outputChannelCount; ++i ) 1817 { 1818 bp->outputZeroer( hostOutputChannels[i].data, 1819 hostOutputChannels[i].stride, 1820 framesToZero ); 1821 1822 1823 /* advance dest ptr for next iteration */ 1824 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + 1825 framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; 1826 } 1827 1828 bp->hostOutputFrameCount[0] += framesToZero; 1829 1830 return framesToZero; 1831 }