void HrtfPanner::pan(float* input, float *left_output, float *right_output) { //Do we need to crossfade? We do if we've moved more than the threshold and crossfading is being allowed. bool needsCrossfade = should_crossfade && fabs(azimuth-prev_azimuth)+fabs(elevation-prev_elevation) >= crossfade_threshold; if(azimuth != prev_azimuth || elevation != prev_elevation) { if(needsCrossfade) { std::swap(left_convolver, prev_left_convolver); std::swap(right_convolver, prev_right_convolver); left_convolver->reset(); right_convolver->reset(); } float* left_response_ptr = left_response_workspace.get(response_length); float* right_response_ptr = right_response_workspace.get(response_length); float leftDelay, rightDelay; std::tie(leftDelay, rightDelay) = hrtf->computeCoefficientsStereo(elevation, azimuth, left_response_ptr, right_response_ptr); left_convolver->setResponse(response_length, left_response_ptr); right_convolver->setResponse(response_length, right_response_ptr); left_delay->setDelay(leftDelay, needsCrossfade); right_delay->setDelay(rightDelay, needsCrossfade); } //These two convolutions always happen. left_convolver->convolve(input, left_output); right_convolver->convolve(input, right_output); if(needsCrossfade) { double delta = 1.0/block_size; float* crossfade_ptr = crossfade_workspace.get(block_size); prev_left_convolver->convolve(input, crossfade_ptr); for(int i = 0; i < block_size; i++) left_output[i] = (block_size-i)*delta*crossfade_ptr[i]+i*delta*left_output[i]; prev_right_convolver->convolve(input, crossfade_ptr); for(int i = 0; i < block_size; i++) right_output[i] = (block_size-i)*delta*crossfade_ptr[i]+i*delta*right_output[i]; } prev_azimuth = azimuth; prev_elevation = elevation; left_delay->process(block_size, left_output, left_output); right_delay->process(block_size, right_output, right_output); }
HrtfPanner::HrtfPanner(int _block_size, float _sr, std::shared_ptr<HrtfData> _hrtf): block_size(_block_size), sr(_sr), hrtf(_hrtf) { response_length = hrtf->getLength(); float* left_response_ptr= left_response_workspace.get(response_length); float* right_response_ptr = right_response_workspace.get(response_length); hrtf->computeCoefficientsStereo(azimuth, elevation, left_response_ptr, right_response_ptr); left_convolver = new BlockConvolver(block_size); right_convolver = new BlockConvolver(block_size); prev_left_convolver = new BlockConvolver(block_size); prev_right_convolver = new BlockConvolver(block_size); left_convolver->setResponse(response_length, left_response_ptr); right_convolver->setResponse(response_length, right_response_ptr); left_delay = new DoppleringDelayLine(hrtf->getMaxDelay(), _sr); right_delay = new DoppleringDelayLine(hrtf->getMaxDelay(), _sr); // Move delay over 1 MS. left_delay->setInterpolationTime(0.003); right_delay->setInterpolationTime(0.003); }