| 636 | } |
| 637 | |
| 638 | void HRTFPanner::pan(ContextRenderLock & r, |
| 639 | double desiredAzimuth, double elevation, |
| 640 | const AudioBus & inputBus, AudioBus & outputBus, |
| 641 | int busOffset, |
| 642 | int framesToProcess) |
| 643 | { |
| 644 | int numInputChannels = inputBus.numberOfChannels(); |
| 645 | |
| 646 | bool isInputGood = numInputChannels >= Channels::Mono && numInputChannels <= Channels::Stereo; |
| 647 | ASSERT(isInputGood); |
| 648 | |
| 649 | bool isOutputGood = outputBus.numberOfChannels() == Channels::Stereo && framesToProcess <= outputBus.length(); |
| 650 | ASSERT(isOutputGood); |
| 651 | |
| 652 | if (!isInputGood || !isOutputGood) |
| 653 | { |
| 654 | outputBus.zero(); |
| 655 | return; |
| 656 | } |
| 657 | |
| 658 | // This code only runs as long as the context is alive and after database has been loaded. |
| 659 | HRTFDatabase * database = HRTFDatabaseLoader::defaultHRTFDatabase(); |
| 660 | ASSERT(database); |
| 661 | |
| 662 | if (!database) |
| 663 | { |
| 664 | outputBus.zero(); |
| 665 | return; |
| 666 | } |
| 667 | |
| 668 | // IRCAM HRTF azimuths values from the loaded database is reversed from the panner's notion of azimuth. |
| 669 | double azimuth = -desiredAzimuth; |
| 670 | |
| 671 | bool isAzimuthGood = azimuth >= -180.0 && azimuth <= 180.0; |
| 672 | ASSERT(isAzimuthGood); |
| 673 | if (!isAzimuthGood) |
| 674 | { |
| 675 | outputBus.zero(); |
| 676 | return; |
| 677 | } |
| 678 | |
| 679 | // Normally, we'll just be dealing with mono sources. |
| 680 | // If we have a stereo input, implement stereo panning with left source processed by left HRTF, and right source by right HRTF. |
| 681 | const AudioChannel * inputChannelL = inputBus.channelByType(Channel::Left); |
| 682 | const AudioChannel * inputChannelR = numInputChannels > Channels::Mono ? inputBus.channelByType(Channel::Right) : 0; |
| 683 | |
| 684 | // Get source and destination pointers. |
| 685 | const float * sourceL = inputChannelL->data(); |
| 686 | const float * sourceR = numInputChannels > Channels::Mono ? inputChannelR->data() : sourceL; |
| 687 | |
| 688 | float * destinationL = outputBus.channelByType(Channel::Left)->mutableData(); |
| 689 | float * destinationR = outputBus.channelByType(Channel::Right)->mutableData(); |
| 690 | |
| 691 | double azimuthBlend; |
| 692 | int desiredAzimuthIndex = calculateDesiredAzimuthIndexAndBlend(azimuth, azimuthBlend); |
| 693 | |
| 694 | // Initially snap azimuth and elevation values to first values encountered. |
| 695 | if (m_azimuthIndex1 == UninitializedAzimuth) |
no test coverage detected