1 // **************************************************************************** 2 // 3 // CEchoGals_transport.cpp 4 // 5 // Audio transport methods for the CEchoGals driver class. 6 // Set editor tabs to 3 for your viewing pleasure. 7 // 8 // ---------------------------------------------------------------------------- 9 // 10 // This file is part of Echo Digital Audio's generic driver library. 11 // Copyright Echo Digital Audio Corporation (c) 1998 - 2005 12 // All rights reserved 13 // www.echoaudio.com 14 // 15 // This library is free software; you can redistribute it and/or 16 // modify it under the terms of the GNU Lesser General Public 17 // License as published by the Free Software Foundation; either 18 // version 2.1 of the License, or (at your option) any later version. 19 // 20 // This library is distributed in the hope that it will be useful, 21 // but WITHOUT ANY WARRANTY; without even the implied warranty of 22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 // Lesser General Public License for more details. 24 // 25 // You should have received a copy of the GNU Lesser General Public 26 // License along with this library; if not, write to the Free Software 27 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 // 29 // **************************************************************************** 30 31 #include "CEchoGals.h" 32 33 #pragma optimize("",off) 34 35 36 /****************************************************************************** 37 38 Functions for opening and closing pipes 39 40 ******************************************************************************/ 41 42 //=========================================================================== 43 // 44 // OpenAudio is used to reserve audio pipes for your exclusive use. The call 45 // will fail if someone else has already opened the pipes. Calling OpenAudio 46 // is the first step if you want to play or record. 47 // 48 // If the fCheckHardware flag is true, then the open will fail 49 // if the DSP and ASIC firmware have not been loaded (usually means 50 // your external box is turned off). 51 // 52 //=========================================================================== 53 54 ECHOSTATUS CEchoGals::OpenAudio 55 ( 56 PECHOGALS_OPENAUDIOPARAMETERS pOpenParameters, // Info on pipe 57 PWORD pwPipeIndex, // Pipe index ptr 58 BOOL fCheckHardware, 59 CDaffyDuck *pDuck 60 ) 61 { 62 CChannelMask cmMask; 63 WORD wPipeMax, wPipe, wPipeIndex, i, wWidth; 64 ECHOSTATUS Status; 65 66 ECHO_DEBUGPRINTF( ("CEchoGals::OpenAudio: %s %u " 67 "PipeWidth %d " 68 "Cyclic %u \n", 69 ( pOpenParameters->Pipe.bIsInput ) ? "Input" : "Output", 70 pOpenParameters->Pipe.nPipe, 71 pOpenParameters->Pipe.wInterleave, 72 pOpenParameters->bIsCyclic) ); 73 74 *pwPipeIndex = (WORD) -1; // So it's never undefined 75 76 // 77 // Make sure the hardware is OK 78 // 79 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 80 { 81 ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") ); 82 return ECHOSTATUS_DSP_DEAD; 83 } 84 85 // 86 // Make sure the DSP & ASIC are up and running 87 // - only if fCheckHardware is true 88 // 89 if (fCheckHardware) 90 { 91 Status = GetDspCommObject()->LoadFirmware(); 92 93 if ( ECHOSTATUS_OK != Status ) 94 return Status; 95 } 96 97 // 98 // Validate the pipe number 99 // 100 wPipe = pOpenParameters->Pipe.nPipe; 101 wWidth = pOpenParameters->Pipe.wInterleave; 102 103 if ( pOpenParameters->Pipe.bIsInput ) 104 { 105 wPipeIndex = wPipe + GetNumPipesOut(); 106 wPipeMax = GetNumPipesIn(); 107 } 108 else 109 { 110 wPipeIndex = wPipe; 111 wPipeMax = GetNumPipesOut(); 112 } 113 114 if ( ( wPipe + wWidth ) > wPipeMax ) 115 { 116 ECHO_DEBUGPRINTF( ("\tECHOSTATUS_INVALID_CHANNEL\n") ); 117 return ECHOSTATUS_INVALID_CHANNEL; 118 } 119 120 // 121 // If the width is more than two, make sure that this card 122 // can handle super interleave 123 // 124 if ( (0 == (m_wFlags & ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK)) && 125 (wWidth > 2) 126 ) 127 { 128 ECHO_DEBUGPRINTF( ("\tECHOSTATUS_NO_SUPER_INTERLEAVE\n") ); 129 return ECHOSTATUS_NO_SUPER_INTERLEAVE; 130 } 131 132 // 133 // See if the specified pipes are already open 134 // 135 for ( i = 0; i < pOpenParameters->Pipe.wInterleave; i++ ) 136 { 137 cmMask.SetIndexInMask( wPipeIndex + i ); 138 } 139 140 if ( m_cmAudioOpen.Test( &cmMask ) ) 141 { 142 ECHO_DEBUGPRINTF( ("OpenAudio - ECHOSTATUS_CHANNEL_ALREADY_OPEN - m_cmAudioOpen 0x%x cmMask 0x%x\n", 143 m_cmAudioOpen.GetMask(),cmMask.GetMask()) ); 144 return ECHOSTATUS_CHANNEL_ALREADY_OPEN; 145 } 146 147 #ifdef AUTO_DUCK_ALLOCATE 148 // 149 // Make a daffy duck 150 // 151 if (NULL == pDuck) 152 { 153 pDuck = CDaffyDuck::MakeDaffyDuck(m_pOsSupport); 154 155 if (NULL == pDuck) 156 return ECHOSTATUS_NO_MEM; 157 } 158 159 SetDaffyDuck( wPipeIndex, pDuck ); 160 161 #else 162 163 // 164 // Use the specified duck if one was passed in 165 // 166 if (NULL != pDuck) 167 SetDaffyDuck( wPipeIndex, pDuck ); 168 169 #endif 170 171 172 // 173 // Reset the 64-bit DMA position 174 // 175 ResetDmaPos(wPipeIndex); 176 GetDspCommObject()->ResetPipePosition(wPipeIndex); 177 178 // 179 // Prep stuff 180 // 181 m_cmAudioOpen += cmMask; 182 if ( pOpenParameters->bIsCyclic ) 183 m_cmAudioCyclic += cmMask; 184 m_Pipes[ wPipeIndex ] = pOpenParameters->Pipe; 185 *pwPipeIndex = wPipeIndex; 186 m_ProcessId[ wPipeIndex ] = pOpenParameters->ProcessId; 187 Reset( wPipeIndex ); 188 189 ECHO_DEBUGPRINTF( ("OpenAudio - ECHOSTATUS_OK - m_cmAudioOpen 0x%x\n",m_cmAudioOpen.GetMask()) ); 190 return ECHOSTATUS_OK; 191 192 } // ECHOSTATUS CEchoGals::OpenAudio 193 194 195 //=========================================================================== 196 // 197 // CloseAudio is, naturally, the inverse of OpenAudio. 198 // 199 //=========================================================================== 200 201 ECHOSTATUS CEchoGals::CloseAudio 202 ( 203 PECHOGALS_CLOSEAUDIOPARAMETERS pCloseParameters, 204 BOOL fFreeDuck 205 ) 206 { 207 CChannelMask cmMask; 208 ECHOSTATUS Status; 209 WORD i; 210 WORD wPipeIndex; 211 212 wPipeIndex = pCloseParameters->wPipeIndex; 213 214 ECHO_DEBUGPRINTF( ("CEchoGals::CloseAudio: Pipe %u ", 215 wPipeIndex) ); 216 217 Status = VerifyAudioOpen( wPipeIndex ); 218 if ( ECHOSTATUS_OK != Status ) 219 return Status; 220 221 for ( i = 0; 222 i < m_Pipes[ wPipeIndex ].wInterleave; 223 i++ ) 224 { 225 cmMask.SetIndexInMask( wPipeIndex + i ); 226 } 227 228 Reset( wPipeIndex ); 229 230 // 231 // Free the scatter-gather list 232 // 233 if (NULL != m_DaffyDucks[wPipeIndex]) 234 { 235 if (fFreeDuck) 236 delete m_DaffyDucks[wPipeIndex]; 237 238 m_DaffyDucks[wPipeIndex] = NULL; 239 } 240 241 m_cmAudioOpen -= cmMask; 242 m_cmAudioCyclic -= cmMask; 243 244 wPipeIndex = wPipeIndex; 245 m_ProcessId[ wPipeIndex ] = NULL; 246 m_Pipes[ wPipeIndex ].wInterleave = 0; 247 248 ECHO_DEBUGPRINTF( ("CloseAudio - ECHOSTATUS_OK - m_cmAudioOpen 0x%x\n",m_cmAudioOpen.GetMask()) ); 249 return ECHOSTATUS_OK; 250 251 } // ECHOSTATUS CEchoGals::CloseAudio 252 253 254 //=========================================================================== 255 // 256 // VerifyAudioOpen is a utility function; it tells you if 257 // a pipe is open or not. 258 // 259 //=========================================================================== 260 261 ECHOSTATUS CEchoGals::VerifyAudioOpen 262 ( 263 WORD wPipeIndex 264 ) 265 { 266 CChannelMask cmMask; 267 268 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 269 { 270 ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") ); 271 return ECHOSTATUS_DSP_DEAD; 272 } 273 274 cmMask.SetIndexInMask( wPipeIndex ); 275 if ( !( m_cmAudioOpen.Test( &cmMask ) ) ) 276 { 277 ECHO_DEBUGPRINTF( ("VerifyAudioOpen - ECHOSTATUS_CHANNEL_NOT_OPEN - wPipeIndex %d - m_cmAudioOpen 0x%x - cmMask 0x%x\n", 278 wPipeIndex,m_cmAudioOpen.GetMask(),cmMask.GetMask()) ); 279 return ECHOSTATUS_CHANNEL_NOT_OPEN; 280 } 281 282 return ECHOSTATUS_OK; 283 284 } // ECHOSTATUS CEchoGals::VerifyAudioOpen 285 286 287 //=========================================================================== 288 // 289 // GetActivePipes tells you which pipes are currently active; that is, which 290 // pipes are currently playing or recording. 291 // 292 //=========================================================================== 293 294 ECHOSTATUS CEchoGals::GetActivePipes 295 ( 296 PCChannelMask pChannelMask 297 ) 298 { 299 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 300 return ECHOSTATUS_DSP_DEAD; 301 302 GetDspCommObject()->GetActivePipes( pChannelMask ); 303 return ECHOSTATUS_OK; 304 } // void CEchoGals::GetActivePipes() 305 306 307 //=========================================================================== 308 // 309 // Just like GetActivePipes, but this one tells you which pipes are currently 310 // open. 311 // 312 //=========================================================================== 313 314 ECHOSTATUS CEchoGals::GetOpenPipes 315 ( 316 PCChannelMask pChannelMask 317 ) 318 { 319 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 320 return ECHOSTATUS_DSP_DEAD; 321 322 *pChannelMask = m_cmAudioOpen; 323 return ECHOSTATUS_OK; 324 325 } // void CEchoGals::GetOpenPipes() 326 327 328 329 330 /****************************************************************************** 331 332 Functions for setting audio formats and the sample rate 333 334 ******************************************************************************/ 335 336 //=========================================================================== 337 // 338 // Validate an audio format. 339 // 340 // For comments on audio formats, refer to the definition of 341 // ECHOGALS_AUDIOFORMAT. 342 // 343 //=========================================================================== 344 345 ECHOSTATUS CEchoGals::QueryAudioFormat 346 ( 347 WORD wPipeIndex, 348 PECHOGALS_AUDIOFORMAT pAudioFormat 349 ) 350 { 351 ECHOSTATUS Status = ECHOSTATUS_OK; 352 353 ECHO_DEBUGPRINTF( ("CEchoGals::QueryAudioFormat:\n") ); 354 355 // 356 // If this pipe is open, make sure that this audio format 357 // does not exceed the stored pipe width 358 // 359 WORD wInterleave = pAudioFormat->wDataInterleave; 360 WORD wStoredPipeWidth = m_Pipes[ wPipeIndex ].wInterleave; 361 362 if (0 != wStoredPipeWidth) 363 { 364 if (wInterleave > wStoredPipeWidth) 365 { 366 ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - pipe was opened " 367 "with a width of %d; interleave of %d invalid.\n", 368 wStoredPipeWidth, 369 pAudioFormat->wDataInterleave)); 370 return ECHOSTATUS_BAD_FORMAT; 371 } 372 } 373 374 // 375 // Check for super interleave (i.e. interleave > 2) 376 // 377 if (wInterleave > 2) 378 { 379 // 380 // Make sure the card is capable of super interleave 381 // 382 if (0 == (m_wFlags & ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK)) 383 return ECHOSTATUS_NO_SUPER_INTERLEAVE; 384 385 // 386 // Interleave must be even & data must be little endian 387 // 388 if ( (0 != pAudioFormat->byDataAreBigEndian) || 389 (0 != (wInterleave & 1) ) 390 ) 391 return ECHOSTATUS_BAD_FORMAT; 392 393 // 394 // 16, 24, or 32 bit samples are required 395 // 396 if ( (32 != pAudioFormat->wBitsPerSample) && 397 (24 != pAudioFormat->wBitsPerSample) && 398 (16 != pAudioFormat->wBitsPerSample) ) 399 return ECHOSTATUS_BAD_FORMAT; 400 401 402 // 403 // Make sure that this interleave factor on this pipe 404 // does not exceed the number of pipes for the card 405 // 406 WORD wMaxPipe; 407 408 if (wPipeIndex >= GetNumPipesOut()) 409 { 410 wMaxPipe = GetNumPipesIn(); 411 wPipeIndex = wPipeIndex - GetNumPipesOut(); 412 } 413 else 414 { 415 wMaxPipe = GetNumPipesOut(); 416 } 417 418 if ( (wPipeIndex + wInterleave) > wMaxPipe) 419 return ECHOSTATUS_BAD_FORMAT; 420 421 return ECHOSTATUS_OK; 422 } 423 424 // 425 // Check the interleave 426 // 427 if ( (1 != pAudioFormat->wDataInterleave) && 428 (2 != pAudioFormat->wDataInterleave) ) 429 430 { 431 ECHO_DEBUGPRINTF( ("CEchoGals::QueryAudioFormat - interleave %d not allowed\n", 432 pAudioFormat->wDataInterleave)); 433 return ECHOSTATUS_BAD_FORMAT; 434 } 435 436 // 437 // If the big endian flag is set, the data must be mono or stereo interleave, 438 // 32 bits wide, left justified data. Only the upper 24 bits are used. 439 // 440 if (pAudioFormat->byDataAreBigEndian) 441 { 442 // 443 // Must have 32 bits per sample 444 // 445 if (pAudioFormat->wBitsPerSample != 32) 446 { 447 ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - Only 32 bits per" 448 " sample supported for big-endian data\n")); 449 return ECHOSTATUS_BAD_FORMAT; 450 } 451 452 // 453 // Mono or stereo only 454 // 455 switch (pAudioFormat->wDataInterleave) 456 { 457 458 #ifdef STEREO_BIG_ENDIAN32_SUPPORT 459 460 case 1 : 461 case 2 : 462 break; 463 #else 464 465 case 1 : 466 break; 467 468 #endif 469 470 default : 471 ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - Interleave of %d" 472 " not allowed for big-endian data\n", 473 pAudioFormat->wDataInterleave)); 474 return ECHOSTATUS_BAD_FORMAT; 475 } 476 477 return ECHOSTATUS_OK; 478 } 479 480 // 481 // Check bits per sample 482 // 483 switch ( pAudioFormat->wBitsPerSample ) 484 { 485 case 8 : 486 case 16 : 487 case 24 : 488 case 32 : 489 break; 490 491 default : 492 ECHO_DEBUGPRINTF( 493 ("CEchoGals::QueryAudioFormat: No valid format " 494 "specified, bits per sample %d\n", 495 pAudioFormat->wBitsPerSample) ); 496 Status = ECHOSTATUS_BAD_FORMAT; 497 break; 498 } 499 500 return Status; 501 502 } // ECHOSTATUS CEchoGals::QueryAudioFormat 503 504 505 //=========================================================================== 506 // 507 // SetAudioFormat sets the format of the audio data in host memory 508 // for this pipe. 509 // 510 //=========================================================================== 511 512 ECHOSTATUS CEchoGals::SetAudioFormat 513 ( 514 WORD wPipeIndex, 515 PECHOGALS_AUDIOFORMAT pAudioFormat 516 ) 517 { 518 ECHOSTATUS Status; 519 520 ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: " 521 "for pipe %d\n", 522 wPipeIndex) ); 523 524 // 525 // Make sure this pipe is open 526 // 527 Status = VerifyAudioOpen( wPipeIndex ); 528 if ( ECHOSTATUS_OK != Status ) 529 return Status; 530 531 // 532 // Check the format 533 // 534 Status = QueryAudioFormat( wPipeIndex, pAudioFormat ); 535 if ( ECHOSTATUS_OK != Status ) 536 return Status; 537 538 // 539 // Set the format 540 // 541 Status = GetDspCommObject()->SetAudioFormat( wPipeIndex, pAudioFormat ); 542 543 return Status; 544 545 } // ECHOSTATUS CEchoGals::SetAudioFormat - single pipe 546 547 548 //=========================================================================== 549 // 550 // This call lets you set the audio format for several pipes at once. 551 // 552 //=========================================================================== 553 554 ECHOSTATUS CEchoGals::SetAudioFormat 555 ( 556 PCChannelMask pChannelMask, 557 PECHOGALS_AUDIOFORMAT pAudioFormat 558 ) 559 { 560 WORD wPipeIndex = 0xffff; 561 ECHOSTATUS Status; 562 563 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 564 { 565 ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") ); 566 return ECHOSTATUS_DSP_DEAD; 567 } 568 569 for ( ; ; ) 570 { 571 wPipeIndex = pChannelMask->GetIndexFromMask( ++wPipeIndex ); 572 if ( (WORD) ECHO_INVALID_CHANNEL == wPipeIndex ) 573 break; // We be done! 574 575 // 576 // See if this pipe is open 577 // 578 if ( !( m_cmAudioOpen.TestIndexInMask( wPipeIndex ) ) ) 579 { 580 ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: " 581 "for pipe %d failed, pipe not open\n", 582 wPipeIndex) ); 583 return ECHOSTATUS_CHANNEL_NOT_OPEN; 584 } 585 586 // 587 // See if the format is OK 588 // 589 ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: " 590 "for pipe %d\n", 591 wPipeIndex) ); 592 Status = QueryAudioFormat( wPipeIndex, pAudioFormat ); 593 if ( ECHOSTATUS_OK != Status ) 594 return Status; 595 596 // 597 // Set the format for this pipe 598 // 599 Status = GetDspCommObject()->SetAudioFormat( wPipeIndex, pAudioFormat ); 600 if ( ECHOSTATUS_OK != Status ) 601 return Status; 602 } 603 604 return ECHOSTATUS_OK; 605 606 } // ECHOSTATUS CEchoGals::SetAudioFormat - multiple pipes 607 608 609 610 //=========================================================================== 611 // 612 // GetAudioFormat returns the current audio format for a pipe. 613 // 614 //=========================================================================== 615 616 ECHOSTATUS CEchoGals::GetAudioFormat 617 ( 618 WORD wPipeIndex, 619 PECHOGALS_AUDIOFORMAT pAudioFormat 620 ) 621 { 622 ECHO_DEBUGPRINTF( ("CEchoGals::GetAudioFormat: " 623 "for pipe %d\n", 624 wPipeIndex) ); 625 626 GetDspCommObject()->GetAudioFormat( wPipeIndex, pAudioFormat ); 627 628 return ECHOSTATUS_OK; 629 630 } // ECHOSTATUS CEchoGals::GetAudioFormat 631 632 633 //=========================================================================== 634 // 635 // This function does exactly what you think it does. 636 // 637 // Note that if the card is not set to internal clock (that is, the hardware 638 // is synced to word clock or some such), this call has no effect. 639 // 640 // Note that all of the inputs and outputs on a single card share the same 641 // clock. 642 // 643 //=========================================================================== 644 645 ECHOSTATUS CEchoGals::SetAudioSampleRate 646 ( 647 DWORD dwSampleRate 648 ) 649 { 650 ECHOSTATUS Status; 651 652 ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioSampleRate: " 653 "to %ld Hz\n", 654 dwSampleRate) ); 655 656 // 657 // Check to see if the sample rate is locked 658 // 659 if ( 0 != (m_wFlags & ECHOGALS_FLAG_SAMPLE_RATE_LOCKED)) 660 { 661 return ECHOSTATUS_OK; 662 } 663 else 664 { 665 Status = QueryAudioSampleRate( dwSampleRate ); 666 if ( ECHOSTATUS_OK != Status ) 667 return Status; 668 669 if ( dwSampleRate == GetDspCommObject()->SetSampleRate( dwSampleRate ) ) 670 { 671 m_dwSampleRate = dwSampleRate; 672 return ECHOSTATUS_OK; 673 } 674 } 675 return ECHOSTATUS_BAD_FORMAT; 676 677 } // ECHOSTATUS CEchoGals::SetAudioSampleRate 678 679 680 //=========================================================================== 681 // 682 // GetAudioSampleRate - retrieves the current sample rate for the hardware 683 // 684 //=========================================================================== 685 686 ECHOSTATUS CEchoGals::GetAudioSampleRate 687 ( 688 PDWORD pdwSampleRate 689 ) 690 { 691 ECHO_DEBUGPRINTF( ("CEchoGals::GetAudioSampleRate\n")); 692 693 *pdwSampleRate = m_dwSampleRate; 694 695 return ECHOSTATUS_OK; 696 697 } // ECHOSTATUS CEchoGals::GetAudioSampleRate 698 699 700 701 702 /****************************************************************************** 703 704 Functions related to the scatter-gather list 705 706 ******************************************************************************/ 707 708 709 //=========================================================================== 710 // 711 // Use the given CDaffyDuck object as the scatter-gather list for this pipe 712 // 713 //=========================================================================== 714 715 ECHOSTATUS CEchoGals::SetDaffyDuck(WORD wPipeIndex, CDaffyDuck *pDuck) 716 { 717 m_DaffyDucks[wPipeIndex] = pDuck; 718 719 return ECHOSTATUS_OK; 720 721 } // SetDaffyDuck 722 723 724 725 726 //=========================================================================== 727 // 728 // This method returns a pointer to the daffy duck for a pipe; the caller 729 // can then have direct access to the daffy duck object. 730 // 731 //=========================================================================== 732 733 CDaffyDuck *CEchoGals::GetDaffyDuck(WORD wPipeIndex) 734 { 735 ECHO_DEBUGPRINTF(("CEchoGals::GetDaffyDuck for pipe index %d\n",wPipeIndex)); 736 737 if (wPipeIndex >= GetNumPipes()) 738 return NULL; 739 740 return m_DaffyDucks[wPipeIndex]; 741 } 742 743 744 745 /****************************************************************************** 746 747 Functions for starting and stopping transport 748 749 ******************************************************************************/ 750 751 //=========================================================================== 752 // 753 // Start transport for a single pipe 754 // 755 //=========================================================================== 756 757 ECHOSTATUS CEchoGals::Start 758 ( 759 WORD wPipeIndex 760 ) 761 { 762 CChannelMask cmMask; 763 764 cmMask.SetIndexInMask( wPipeIndex ); 765 return Start( &cmMask ); 766 767 } // ECHOSTATUS CEchoGals::Start 768 769 770 //=========================================================================== 771 // 772 // Start transport for a group of pipes 773 // 774 // This function includes logic to sync-start several pipes at once, 775 // according to the process ID specified when the pipe was opened. This is 776 // included to work around a limitation of the Windows wave API so that 777 // programs could use multiple inputs and outputs and have them start at the 778 // same time. 779 // 780 // If you don't want to use this feature, call CEchoGals::ClearFlags 781 // with ECHOGALS_FLAG_SYNCH_WAVE and the pipes will start immediately. 782 // 783 //=========================================================================== 784 785 ECHOSTATUS CEchoGals::Start 786 ( 787 PCChannelMask pChannelMask 788 ) 789 { 790 WORD wPipe; 791 DWORD dwPhysStartAddr; 792 CChannelMask cmStart; 793 PVOID ProcessId = NULL; 794 CDspCommObject *pDCO; 795 796 pDCO = GetDspCommObject(); 797 if ( NULL == pDCO || pDCO->IsBoardBad() ) 798 return ECHOSTATUS_DSP_DEAD; 799 800 // 801 // See if we are dealing with synchronized wave pipes. If the sync 802 // flag is set, get the process ID for this pipe to compare with 803 // other pipes. 804 // 805 if ( GetFlags() & ECHOGALS_FLAG_SYNCH_WAVE ) 806 { 807 wPipe = pChannelMask->GetIndexFromMask( 0 ); 808 ProcessId = m_ProcessId[ wPipe ]; 809 } 810 811 //-------------------------------------------------------- 812 // Process each pipe in the mask 813 //-------------------------------------------------------- 814 815 for (wPipe = 0; wPipe < GetNumPipes(); wPipe++) 816 { 817 PDWORD pdwDspCommPositions; 818 819 // 820 // Skip this pipe if it's not in the mask 821 // 822 if (!pChannelMask->TestIndexInMask(wPipe)) 823 continue; 824 825 // 826 // This pipe must have a CDaffyDuck object 827 // 828 if (NULL == m_DaffyDucks[ wPipe ]) 829 { 830 ECHO_DEBUGPRINTF(("CDaffyDuck::Start - trying to start pipe index %d " 831 "but there is no CDaffyDuck!\n",wPipe)); 832 return ECHOSTATUS_CHANNEL_NOT_OPEN; 833 } 834 835 // 836 // If this pipe was opened in cyclic mode, make sure that the corresponding 837 // CDaffyDuck has been wrapped 838 // 839 if ( (0 != m_cmAudioCyclic.TestIndexInMask( wPipe ) ) && 840 (FALSE == m_DaffyDucks[wPipe]->Wrapped()) 841 ) 842 { 843 ECHO_DEBUGPRINTF(("CEchoGals::Start called for pipe index %d - " 844 "pipe was opened in cyclic mode, but the duck " 845 "has not been wrapped\n",wPipe)); 846 return ECHOSTATUS_DUCK_NOT_WRAPPED; 847 } 848 849 // 850 // Set the physical start address for the duck for this pipe 851 // 852 dwPhysStartAddr = m_DaffyDucks[wPipe]->GetPhysStartAddr(); 853 pDCO->SetAudioDuckListPhys( wPipe, dwPhysStartAddr ); 854 855 856 // 857 // Do different things to this pipe depending on the 858 // state 859 // 860 switch (m_byPipeState[wPipe]) 861 { 862 case PIPE_STATE_RESET : 863 // 864 // Clean up the DMA position stuff 865 // 866 pdwDspCommPositions = pDCO->GetAudioPositionPtr(); 867 pdwDspCommPositions[ wPipe ] = 0; 868 869 // 870 // If this pipe isn't synced or is in a reset state, 871 // start it up 872 // 873 if (NULL == ProcessId) 874 { 875 m_byPipeState[ wPipe ] = PIPE_STATE_STARTED; 876 cmStart.SetIndexInMask( wPipe ); 877 } 878 else 879 { 880 // 881 // This pipe is synced; upgrade to PENDING 882 // 883 m_byPipeState[ wPipe ] = PIPE_STATE_PENDING; 884 } 885 break; 886 887 888 case PIPE_STATE_STOPPED : 889 890 if (NULL == ProcessId) 891 { 892 // 893 // Non-synced pipe; start 'er up! 894 // 895 m_byPipeState[ wPipe ] = PIPE_STATE_STARTED; 896 cmStart.SetIndexInMask( wPipe ); 897 } 898 else 899 { 900 // 901 // Synced pipe; if this pipe is in STOP mode, 902 // upgrade it to PENDING status 903 // 904 m_byPipeState[ wPipe ] = PIPE_STATE_PENDING; 905 } 906 break; 907 908 909 case PIPE_STATE_PENDING : 910 case PIPE_STATE_STARTED : 911 break; 912 } 913 } 914 915 //----------------------------------------------------------------- 916 // Start the pipes 917 //----------------------------------------------------------------- 918 919 // 920 // Don't go if all the synced pipes are not yet pending 921 // 922 BOOL fAllReady = TRUE; 923 for ( wPipe = 0; wPipe < GetNumPipes(); wPipe++ ) 924 { 925 if ( ( ProcessId == m_ProcessId[ wPipe ] ) && 926 ( PIPE_STATE_STOPPED == m_byPipeState[wPipe])) 927 { 928 ECHO_DEBUGPRINTF(("CEchoGals::Start - can't start; pipe %d " 929 "still set to state %d\n", 930 wPipe, 931 m_byPipeState[wPipe])); 932 fAllReady = FALSE; 933 } 934 } 935 936 // 937 // All synced pipes are pending; time to go! 938 // 939 if (fAllReady) 940 { 941 for (wPipe = 0; wPipe < GetNumPipes(); wPipe++) 942 { 943 if ( (ProcessId == m_ProcessId[ wPipe ]) && 944 (PIPE_STATE_PENDING == m_byPipeState[ wPipe ])) 945 { 946 m_byPipeState[wPipe] = PIPE_STATE_STARTED; 947 cmStart.SetIndexInMask( wPipe ); 948 ECHO_DEBUGPRINTF(("CEchoGals::Start - setting pipe %d to start\n", 949 wPipe)); 950 } 951 } 952 } 953 954 if ( cmStart.IsEmpty() ) 955 return ECHOSTATUS_OK; 956 957 958 //----------------------------------------------------------------- 959 // Time to go 960 //----------------------------------------------------------------- 961 962 return pDCO->StartTransport( &cmStart ); 963 964 } // ECHOSTATUS CEchoGals::Start 965 966 967 968 //=========================================================================== 969 // 970 // Stop a single pipe 971 // 972 //=========================================================================== 973 974 ECHOSTATUS CEchoGals::Stop 975 ( 976 WORD wPipeIndex 977 ) 978 { 979 CChannelMask cmMask; 980 981 cmMask.SetIndexInMask( wPipeIndex ); 982 return( Stop( &cmMask ) ); 983 984 } // ECHOSTATUS CEchoGals::Stop 985 986 987 //=========================================================================== 988 // 989 // Stop several pipes simultaneously 990 // 991 //=========================================================================== 992 993 ECHOSTATUS CEchoGals::Stop 994 ( 995 PCChannelMask pChannelMask 996 ) 997 { 998 INT32 i; 999 ECHOSTATUS Status; 1000 1001 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 1002 return ECHOSTATUS_DSP_DEAD; 1003 1004 Status = GetDspCommObject()->StopTransport( pChannelMask ); 1005 if ( ECHOSTATUS_OK != Status ) 1006 return Status; 1007 1008 for ( i = 0; i < GetNumPipes(); i++ ) 1009 { 1010 // 1011 // Skip channel if not in mask 1012 // 1013 if ( !pChannelMask->TestIndexInMask( (WORD) i ) ) 1014 continue; 1015 1016 1017 // 1018 // Don't bother if it's stopped already 1019 // 1020 if ( PIPE_STATE_STOPPED == m_byPipeState[ i ] ) 1021 continue; 1022 1023 // 1024 // Muck with the DMA position 1025 // 1026 UpdateDmaPos( (WORD) i ); 1027 1028 m_byPipeState[ i ] = PIPE_STATE_STOPPED; 1029 } 1030 1031 return Status; 1032 1033 } // ECHOSTATUS CEchoGals::Stop 1034 1035 1036 //=========================================================================== 1037 // 1038 // Reset transport for a single pipe 1039 // 1040 //=========================================================================== 1041 1042 ECHOSTATUS CEchoGals::Reset 1043 ( 1044 WORD wPipeIndex 1045 ) 1046 { 1047 CChannelMask cmMask; 1048 1049 cmMask.SetIndexInMask( wPipeIndex ); 1050 return Reset( &cmMask ); 1051 1052 } // ECHOSTATUS CEchoGals::Reset 1053 1054 1055 //=========================================================================== 1056 // 1057 // Reset transport for a group of pipes simultaneously 1058 // 1059 //=========================================================================== 1060 1061 ECHOSTATUS CEchoGals::Reset 1062 ( 1063 PCChannelMask pChannelMask 1064 ) 1065 { 1066 WORD i; 1067 ECHOSTATUS Status; 1068 1069 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 1070 return ECHOSTATUS_DSP_DEAD; 1071 1072 Status = GetDspCommObject()->ResetTransport( pChannelMask ); 1073 if ( ECHOSTATUS_OK != Status ) 1074 return Status; 1075 1076 for ( i = 0; i < GetNumPipes(); i++ ) 1077 { 1078 // 1079 // Skip channel if not in mask 1080 // 1081 if ( !pChannelMask->TestIndexInMask( (WORD) i ) ) 1082 continue; 1083 1084 if ( PIPE_STATE_RESET == m_byPipeState[ i ] ) 1085 continue; 1086 1087 // 1088 // Muck with the DMA position 1089 // 1090 UpdateDmaPos( i ); 1091 m_dwLastDspPos[ i ] = 0; 1092 GetDspCommObject()->ResetPipePosition(i); 1093 1094 m_byPipeState[ i ] = PIPE_STATE_RESET; 1095 } 1096 1097 return Status; 1098 1099 } // ECHOSTATUS CEchoGals::Reset 1100 1101 1102 1103 1104 /****************************************************************************** 1105 1106 Functions for handling the current DMA position for pipes; the DMA position 1107 is the number of bytes transported by a pipe. 1108 1109 ******************************************************************************/ 1110 1111 //=========================================================================== 1112 // 1113 // The DSP sends back a 32 bit DMA counter for each pipe of the number of bytes 1114 // transported; this count is written by the DSP to the comm page without 1115 // the driver doing anything. 1116 // 1117 // The driver then maintains a 64 bit counter based off of the DSP's counter. 1118 // 1119 // Call UpdateDmaPos to cause the driver to update the internal 64 bit DMA 1120 // counter. 1121 // 1122 // The 64 bit DMA counter is in units of bytes, not samples. 1123 // 1124 //=========================================================================== 1125 1126 void CEchoGals::UpdateDmaPos( WORD wPipeIndex ) 1127 { 1128 DWORD dwDspPos; 1129 DWORD dwDelta; 1130 1131 // 1132 // Get the current DSP position and find out how much it 1133 // has moved since last time. This is necessary to avoid 1134 // the 32 bit counter wrapping around. 1135 // 1136 dwDspPos = GetDspCommObject()->GetAudioPosition( wPipeIndex ); 1137 dwDelta = dwDspPos - m_dwLastDspPos[ wPipeIndex ]; 1138 1139 // 1140 // Adjust the 64 bit position 1141 // 1142 m_ullDmaPos[ wPipeIndex ] += dwDelta; 1143 m_dwLastDspPos[ wPipeIndex ] = dwDspPos; 1144 1145 } // UpdateDmaPos 1146 1147 1148 //=========================================================================== 1149 // 1150 // ResetDmaPos resets the 64 bit DMA counter. 1151 // 1152 //=========================================================================== 1153 1154 void CEchoGals::ResetDmaPos(WORD wPipe) 1155 { 1156 m_ullDmaPos[ wPipe ] = 0; 1157 m_dwLastDspPos[ wPipe ] = 0; 1158 1159 // 1160 // There may still be mappings in the daffy duck; if so, 1161 // tell them to reset their DMA positions starting at zero 1162 // 1163 if (NULL != m_DaffyDucks[wPipe]) 1164 m_DaffyDucks[wPipe]->ResetStartPos(); 1165 } 1166 1167 1168 //=========================================================================== 1169 // 1170 // This is a very powerful feature; calling this function gives you a pointer 1171 // to the memory location where the DSP writes the 32 bit DMA position for 1172 // a pipe. The DSP is constantly updating this value as it moves data. 1173 // 1174 // Since the DSP is constantly updating it, you can dereference this pointer 1175 // from anywhere and read the DMA position without calling the generic driver. 1176 // This means that with some adroit mapping, you could read the DMA position 1177 // from user mode without calling the kernel. 1178 // 1179 // Remember, Peter - with great power comes great responsibility; you should 1180 // only read this pointer and never write to it or to anywhere around it. You 1181 // could easily lock up your computer. 1182 // 1183 // Note that the DSP writes the position in little endian format; if you are 1184 // on a big endian machine, you will need to byte swap the postion 1185 // before you use it. 1186 // 1187 //=========================================================================== 1188 1189 ECHOSTATUS CEchoGals::GetAudioPositionPtr 1190 ( 1191 WORD wPipeIndex, 1192 PDWORD & pdwPosition 1193 ) 1194 { 1195 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 1196 return ECHOSTATUS_DSP_DEAD; 1197 1198 if (wPipeIndex >= GetNumPipes()) 1199 { 1200 pdwPosition = NULL; 1201 return ECHOSTATUS_INVALID_CHANNEL; 1202 } 1203 1204 PDWORD pdwDspCommPos = GetDspCommObject()->GetAudioPositionPtr(); 1205 1206 pdwPosition = pdwDspCommPos + wPipeIndex; 1207 1208 return ECHOSTATUS_OK; 1209 1210 } // ECHOSTATUS CEchoGals::GetAudioPositionPtr 1211 1212 1213