From b4d0348be94a60b9ca24a095d8328fc7c84335f7 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Wed, 20 Feb 2013 18:24:07 -0800 Subject: [PATCH] Implmented HRTF sound source spatialization --- KREngine/kraken/KRAudioManager.cpp | 660 +++++++++++++++++++++++++++-- KREngine/kraken/KRAudioManager.h | 16 +- KREngine/kraken/KRMat4.cpp | 8 + KREngine/kraken/KRMat4.h | 2 + 4 files changed, 642 insertions(+), 44 deletions(-) diff --git a/KREngine/kraken/KRAudioManager.cpp b/KREngine/kraken/KRAudioManager.cpp index d9744f4..535cd69 100644 --- a/KREngine/kraken/KRAudioManager.cpp +++ b/KREngine/kraken/KRAudioManager.cpp @@ -35,7 +35,7 @@ #include "KRDataBlock.h" #include "KRAudioBuffer.h" #include "KRContext.h" - +#include "KRVector2.h" #include OSStatus alcASASetListenerProc(const ALuint property, ALvoid *data, ALuint dataSize); @@ -64,7 +64,7 @@ KRAudioManager::KRAudioManager(KRContext &context) : KRContextObject(context) m_reverb_input_samples = NULL; m_reverb_input_next_sample = 0; - m_reverb_workspace_data = NULL; + m_workspace_data = NULL; m_reverb_sequence = 0; for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) { @@ -142,15 +142,15 @@ float *KRAudioManager::getBlockAddress(int block_offset) return m_output_accumulation + (m_output_accumulation_block_start + block_offset * KRENGINE_AUDIO_BLOCK_LENGTH * KRENGINE_MAX_OUTPUT_CHANNELS) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); } -void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_offset, int frame_count_log_2) +void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_offset, int frame_count_log2) { - int frame_count = 1 << frame_count_log_2; + int frame_count = 1 << frame_count_log2; int fft_size = frame_count * 2; - int fft_size_log_2 = frame_count_log_2 + 1; + int fft_size_log2 = frame_count_log2 + 1; - DSPSplitComplex reverb_sample_data_complex = m_reverb_workspace[0]; - DSPSplitComplex impulse_block_data_complex = m_reverb_workspace[1]; - DSPSplitComplex conv_data_complex = m_reverb_workspace[2]; + DSPSplitComplex reverb_sample_data_complex = m_workspace[0]; + DSPSplitComplex impulse_block_data_complex = m_workspace[1]; + DSPSplitComplex conv_data_complex = m_workspace[2]; int reverb_offset = (m_reverb_input_next_sample + KRENGINE_AUDIO_BLOCK_LENGTH - frame_count); if(reverb_offset < 0) { @@ -172,7 +172,7 @@ void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response memset(reverb_sample_data_complex.realp + frame_count, 0, frame_count * sizeof(float)); memset(reverb_sample_data_complex.imagp, 0, fft_size * sizeof(float)); - vDSP_fft_zip(m_fft_setup, &reverb_sample_data_complex, 1, fft_size_log_2, kFFTDirection_Forward); + vDSP_fft_zip(m_fft_setup, &reverb_sample_data_complex, 1, fft_size_log2, kFFTDirection_Forward); float scale = 1.0f / fft_size; @@ -183,9 +183,9 @@ void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response memset(impulse_block_data_complex.realp + frame_count, 0, frame_count * sizeof(float)); memset(impulse_block_data_complex.imagp, 0, fft_size * sizeof(float)); - vDSP_fft_zip(m_fft_setup, &impulse_block_data_complex, 1, fft_size_log_2, kFFTDirection_Forward); + vDSP_fft_zip(m_fft_setup, &impulse_block_data_complex, 1, fft_size_log2, kFFTDirection_Forward); vDSP_zvmul(&reverb_sample_data_complex, 1, &impulse_block_data_complex, 1, &conv_data_complex, 1, fft_size, 1); - vDSP_fft_zip(m_fft_setup, &conv_data_complex, 1, fft_size_log_2, kFFTDirection_Inverse); + vDSP_fft_zip(m_fft_setup, &conv_data_complex, 1, fft_size_log2, kFFTDirection_Inverse); vDSP_vsmul(conv_data_complex.realp, 1, &scale, conv_data_complex.realp, 1, fft_size); @@ -201,11 +201,6 @@ void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response } } -void KRAudioManager::renderHRTF() -{ - -} - void KRAudioManager::renderReverb() { float reverb_data[KRENGINE_AUDIO_BLOCK_LENGTH]; @@ -229,19 +224,15 @@ void KRAudioManager::renderReverb() KRAudioSample *impulse_response_sample = getContext().getAudioManager()->get("test_reverb"); if(impulse_response_sample) { int impulse_response_blocks = impulse_response_sample->getFrameCount() / KRENGINE_AUDIO_BLOCK_LENGTH + 1; - int period_log_2 = 0; + int period_log2 = 0; int impulse_response_block=0; int period_count = 0; -// fprintf(stderr, "m_reverb_sequence - %i - ", m_reverb_sequence); while(impulse_response_block < impulse_response_blocks) { - int period = 1 << period_log_2; + int period = 1 << period_log2; if((m_reverb_sequence + period - period_count) % period == 0) { -// fprintf(stderr, "-%02i-", period); - renderReverbImpulseResponse(impulse_response_sample, impulse_response_block * KRENGINE_AUDIO_BLOCK_LENGTH, KRENGINE_AUDIO_BLOCK_LOG2N + period_log_2); - } else { -// fprintf(stderr, "----"); + renderReverbImpulseResponse(impulse_response_sample, impulse_response_block * KRENGINE_AUDIO_BLOCK_LENGTH, KRENGINE_AUDIO_BLOCK_LOG2N + period_log2); } impulse_response_block += period; @@ -249,12 +240,11 @@ void KRAudioManager::renderReverb() period_count++; if(period_count >= period) { period_count = 0; - if(KRENGINE_AUDIO_BLOCK_LOG2N + period_log_2 + 1 < KRENGINE_REVERB_MAX_FFT_LOG_2) { // FFT Size is double the number of frames in the period - period_log_2++; + if(KRENGINE_AUDIO_BLOCK_LOG2N + period_log2 + 1 < KRENGINE_REVERB_MAX_FFT_LOG2) { // FFT Size is double the number of frames in the period + period_log2++; } } } -// fprintf(stderr, "\n"); } m_reverb_sequence = (m_reverb_sequence + 1) % 0x1000000; @@ -265,6 +255,8 @@ void KRAudioManager::renderReverb() void KRAudioManager::renderBlock() { + bool headphone_mode = true; + // ----====---- Advance to next block in accumulation buffer ----====---- // Zero out block that was last used, so it will be ready for the next pass through the circular buffer @@ -275,8 +267,11 @@ void KRAudioManager::renderBlock() m_output_accumulation_block_start = (m_output_accumulation_block_start + KRENGINE_AUDIO_BLOCK_LENGTH * KRENGINE_MAX_OUTPUT_CHANNELS) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); // ----====---- Render Direct / HRTF audio ----====---- - renderHRTF(); -// renderITD(); + if(headphone_mode) { + renderHRTF(); + } else { + renderITD(); + } // ----====---- Render Indirect / Reverb channel ----====---- renderReverb(); @@ -312,9 +307,510 @@ void KRSetAUCanonical(AudioStreamBasicDescription &desc, UInt32 nChannels, bool } } +void KRAudioManager::initHRTF() +{ + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,005.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,010.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,015.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,020.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,025.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,035.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,040.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,045.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,050.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,055.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,065.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,070.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,075.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,080.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,085.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,095.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,100.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,105.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,110.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,115.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,125.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,130.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,135.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,140.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,145.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,155.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,160.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,165.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,170.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,175.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-10.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,005.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,010.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,015.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,020.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,025.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,035.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,040.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,045.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,050.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,055.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,065.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,070.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,075.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,080.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,085.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,095.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,100.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,105.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,110.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,115.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,125.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,130.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,135.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,140.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,145.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,155.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,160.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,165.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,170.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,175.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-20.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,006.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,012.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,018.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,024.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,036.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,042.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,048.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,054.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,066.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,072.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,078.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,084.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,096.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,102.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,108.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,114.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,126.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,132.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,138.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,144.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,156.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,162.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,168.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,174.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-30.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,006.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,013.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,019.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,026.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,032.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,039.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,045.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,051.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,058.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,064.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,071.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,077.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,084.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,096.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,103.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,109.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,116.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,122.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,129.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,135.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,141.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,148.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,154.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,161.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,167.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,174.0f)); + m_hrtf_sample_locations.push_back(KRVector2(-40.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,005.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,010.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,015.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,020.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,025.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,035.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,040.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,045.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,050.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,055.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,065.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,070.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,075.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,080.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,085.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,095.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,100.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,105.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,110.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,115.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,125.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,130.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,135.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,140.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,145.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,155.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,160.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,165.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,170.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,175.0f)); + m_hrtf_sample_locations.push_back(KRVector2(0.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,005.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,010.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,015.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,020.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,025.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,035.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,040.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,045.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,050.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,055.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,065.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,070.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,075.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,080.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,085.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,095.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,100.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,105.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,110.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,115.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,125.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,130.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,135.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,140.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,145.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,155.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,160.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,165.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,170.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,175.0f)); + m_hrtf_sample_locations.push_back(KRVector2(10.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,005.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,010.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,015.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,020.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,025.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,035.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,040.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,045.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,050.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,055.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,065.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,070.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,075.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,080.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,085.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,095.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,100.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,105.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,110.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,115.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,125.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,130.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,135.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,140.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,145.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,155.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,160.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,165.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,170.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,175.0f)); + m_hrtf_sample_locations.push_back(KRVector2(20.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,006.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,012.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,018.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,024.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,036.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,042.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,048.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,054.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,066.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,072.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,078.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,084.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,096.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,102.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,108.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,114.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,126.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,132.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,138.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,144.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,156.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,162.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,168.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,174.0f)); + m_hrtf_sample_locations.push_back(KRVector2(30.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,006.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,013.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,019.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,026.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,032.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,039.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,045.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,051.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,058.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,064.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,071.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,077.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,084.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,096.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,103.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,109.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,116.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,122.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,129.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,135.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,141.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,148.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,154.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,161.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,167.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,174.0f)); + m_hrtf_sample_locations.push_back(KRVector2(40.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,008.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,016.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,024.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,032.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,040.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,048.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,056.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,064.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,072.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,080.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,088.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,096.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,104.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,112.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,128.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,136.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,144.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,152.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,160.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,168.0f)); + m_hrtf_sample_locations.push_back(KRVector2(50.0f,176.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,010.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,020.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,040.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,050.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,070.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,080.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,100.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,110.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,130.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,140.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,160.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,170.0f)); + m_hrtf_sample_locations.push_back(KRVector2(60.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,015.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,045.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,075.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,105.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,135.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,165.0f)); + m_hrtf_sample_locations.push_back(KRVector2(70.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(80.0f,000.0f)); + m_hrtf_sample_locations.push_back(KRVector2(80.0f,030.0f)); + m_hrtf_sample_locations.push_back(KRVector2(80.0f,060.0f)); + m_hrtf_sample_locations.push_back(KRVector2(80.0f,090.0f)); + m_hrtf_sample_locations.push_back(KRVector2(80.0f,120.0f)); + m_hrtf_sample_locations.push_back(KRVector2(80.0f,150.0f)); + m_hrtf_sample_locations.push_back(KRVector2(80.0f,180.0f)); + m_hrtf_sample_locations.push_back(KRVector2(90.0f,000.0f)); +} + +void KRAudioManager::getHRTFMix(const KRVector2 &dir, KRVector2 &dir1, KRVector2 &dir2, KRVector2 &dir3, KRVector2 &dir4, float &mix1, float &mix2, float &mix3, float &mix4) +{ + float elev_gran = 10.0f; + + float elevation = dir.x * 180.0f / M_PI; + float azimuth = dir.y * 180.0f / M_PI; + + float elev1 = floor(elevation / elev_gran) * elev_gran; + float elev2 = ceil(elevation / elev_gran) * elev_gran; + float elev_blend = (elevation - elev1) / elev_gran; + if(elev1 < -40.0f) { + elev1 = -40.0f; + elev2 = -40.0f; + elev_blend = 0.0f; + } + + dir1.x = elev1; + dir2.x = elev1; + dir3.x = elev2; + dir4.x = elev2; + + bool first1 = true; + bool first2 = true; + bool first3 = true; + bool first4 = true; + for(std::vector::iterator itr = m_hrtf_sample_locations.begin(); itr != m_hrtf_sample_locations.end(); itr++) { + KRVector2 sample_pos = *itr; + + if(sample_pos.x == elev1) { + if(sample_pos.y <= azimuth) { + if(first1) { + first1 = false; + dir1.y = sample_pos.y; + } else if(sample_pos.y > dir1.y) { + dir1.y = sample_pos.y; + } + } + if(-sample_pos.y <= azimuth) { + if(first1) { + first1 = false; + dir1.y = -sample_pos.y; + } else if(-sample_pos.y > dir1.y) { + dir1.y = -sample_pos.y; + } + } + + if(sample_pos.y > azimuth) { + if(first2) { + first2 = false; + dir2.y = sample_pos.y; + } else if(sample_pos.y < dir2.y) { + dir2.y = sample_pos.y; + } + } + if(-sample_pos.y > azimuth) { + if(first2) { + first2 = false; + dir2.y = -sample_pos.y; + } else if(-sample_pos.y < dir2.y) { + dir2.y = -sample_pos.y; + } + } + } + if(sample_pos.x == elev2) { + if(sample_pos.y <= azimuth) { + if(first3) { + first3 = false; + dir3.y = sample_pos.y; + } else if(sample_pos.y > dir3.y) { + dir3.y = sample_pos.y; + } + } + if(-sample_pos.y <= azimuth) { + if(first3) { + first3 = false; + dir3.y = -sample_pos.y; + } else if(-sample_pos.y > dir3.y) { + dir3.y = -sample_pos.y; + } + } + + if(sample_pos.y > azimuth) { + if(first4) { + first4 = false; + dir4.y = sample_pos.y; + } else if(sample_pos.y < dir4.y) { + dir4.y = sample_pos.y; + } + } + if(-sample_pos.y > azimuth) { + if(first4) { + first4 = false; + dir4.y = -sample_pos.y; + } else if(-sample_pos.y < dir4.y) { + dir4.y = -sample_pos.y; + } + } + } + } + + + float azim_blend1 = 0.0f; + if(dir2.y > dir1.y) { + azim_blend1 = (azimuth - dir1.y) / (dir2.y - dir1.y); + } + + float azim_blend2 = 0.0f; + if(dir4.y > dir3.y) { + azim_blend2 = (azimuth - dir3.y) / (dir4.y - dir3.y); + } + + mix1 = (1.0f - azim_blend1) * (1.0f - elev_blend); + mix2 = azim_blend1 * (1.0f - elev_blend); + mix3 = (1.0f - azim_blend2) * elev_blend; + mix4 = azim_blend2 * elev_blend; +} + +KRAudioSample *KRAudioManager::getHRTFSample(const KRVector2 &hrtf_dir, bool &swap) +{ + //hrtf_kemar_H-10e000a.wav + swap = hrtf_dir.y < 0; + + char szName[64]; + sprintf(szName, "hrtf_kemar_H%de%03da", int(hrtf_dir.x), abs(int(hrtf_dir.y))); + + return get(szName); +} + void KRAudioManager::initSiren() { if(m_auGraph == NULL) { + initHRTF(); m_output_sample = KRENGINE_AUDIO_BLOCK_LENGTH; // initialize double-buffer for reverb input @@ -327,17 +823,17 @@ void KRAudioManager::initSiren() memset(m_output_accumulation, 0, buffer_size * 2); m_output_accumulation_block_start = 0; - m_reverb_workspace_data = (float *)malloc(KRENGINE_REVERB_WORKSPACE_SIZE * 6 * sizeof(float)); - m_reverb_workspace[0].realp = m_reverb_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 0; - m_reverb_workspace[0].imagp = m_reverb_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 1; - m_reverb_workspace[1].realp = m_reverb_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 2; - m_reverb_workspace[1].imagp = m_reverb_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 3; - m_reverb_workspace[2].realp = m_reverb_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 4; - m_reverb_workspace[2].imagp = m_reverb_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 5; + m_workspace_data = (float *)malloc(KRENGINE_REVERB_WORKSPACE_SIZE * 6 * sizeof(float)); + m_workspace[0].realp = m_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 0; + m_workspace[0].imagp = m_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 1; + m_workspace[1].realp = m_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 2; + m_workspace[1].imagp = m_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 3; + m_workspace[2].realp = m_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 4; + m_workspace[2].imagp = m_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 5; m_reverb_sequence = 0; - m_fft_setup = vDSP_create_fftsetup( KRENGINE_REVERB_MAX_FFT_LOG_2, kFFTRadix2); + m_fft_setup = vDSP_create_fftsetup( KRENGINE_REVERB_MAX_FFT_LOG2, kFFTRadix2); // ----====---- Initialize Core Audio Objects ----====---- OSDEBUG(NewAUGraph(&m_auGraph)); @@ -500,9 +996,9 @@ void KRAudioManager::cleanupSiren() m_output_accumulation = NULL; } - if(m_reverb_workspace_data) { - free(m_reverb_workspace_data); - m_reverb_workspace_data = NULL; + if(m_workspace_data) { + free(m_workspace_data); + m_workspace_data = NULL; } for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) { @@ -760,6 +1256,92 @@ void KRAudioManager::setGlobalReverbSendLevel(float send_level) } +void KRAudioManager::renderHRTF() +{ + DSPSplitComplex *hrtf_accum = m_workspace + 0; + DSPSplitComplex *hrtf_impulse = m_workspace + 1; + DSPSplitComplex *hrtf_convolved = m_workspace + 1; // We only need hrtf_impulse or hrtf_convolved at once; we can recycle the buffer + DSPSplitComplex *hrtf_sample = m_workspace + 2; + + int impulse_response_channels = 2; + int hrtf_frames = 128; + int fft_size = 256; + int fft_size_log2 = 8; + + + + KRVector3 listener_right = KRVector3::Cross(m_listener_forward, m_listener_up); + + KRMat4 inv_listener_mat = KRMat4::Invert(KRMat4(listener_right, m_listener_up, m_listener_forward, m_listener_position)); + + for(std::set::iterator itr=m_activeAudioSources.begin(); itr != m_activeAudioSources.end(); itr++) { + KRAudioSource *source = *itr; + KRAudioSample *source_sample = source->getAudioSample(); + if(source_sample) { + + KRVector3 source_listener_space = KRMat4::Dot(inv_listener_mat, source->getWorldTranslation()); + KRVector3 source_dir = KRVector3::Normalize(source_listener_space); + float distance = source_listener_space.magnitude(); + float gain = source->getGain() / pow(distance / source->getRolloffFactor(), 2.0f); +// gain = 1.0f; // FINDME, HACK - Test code + + float azimuth = atan2(source_dir.x, source_dir.z); + float elevation = atan( source_dir.y / sqrt(source_dir.x * source_dir.x + source_dir.z * source_dir.z)); + + float mix[4]; + KRVector2 dir[4]; + bool swap[4]; + KRAudioSample *sample[4]; + + getHRTFMix(KRVector2(elevation, azimuth), dir[0], dir[1], dir[2], dir[3], mix[0], mix[1], mix[2], mix[3]); + + for(int i=0; i < 4; i++) { + sample[i] = getHRTFSample(dir[i], swap[i]); + } + + for(int channel=0; channelrealp, 0, sizeof(float) * fft_size); + memset(hrtf_accum->imagp, 0, sizeof(float) * fft_size); + + for(int i=0; i < 4; i++) { + if(sample[i] != NULL && mix[i] > 0.0f) { + + sample[i]->sample(0, hrtf_frames, (channel + (swap[i] ? 1 : 0)) % 2, hrtf_impulse->realp, 1.0f); + memset(hrtf_impulse->realp + hrtf_frames, 0, sizeof(float) * hrtf_frames); + memset(hrtf_impulse->imagp, 0, sizeof(float) * fft_size); + vDSP_fft_zip(m_fft_setup, hrtf_impulse, 1, fft_size_log2, kFFTDirection_Forward); + vDSP_vsmul(hrtf_impulse->realp, 1, mix+i, hrtf_impulse->realp, 1, fft_size); + vDSP_vsmul(hrtf_impulse->imagp, 1, mix+i, hrtf_impulse->imagp, 1, fft_size); + vDSP_zvadd(hrtf_impulse, 1, hrtf_accum, 1, hrtf_accum, 1, fft_size); + } + } + + source_sample->sample((int)((__int64_t)m_audio_frame - source->getStartAudioFrame()), KRENGINE_AUDIO_BLOCK_LENGTH, 0, hrtf_sample->realp, gain); + memset(hrtf_sample->realp + hrtf_frames, 0, sizeof(float) * hrtf_frames); + memset(hrtf_sample->imagp, 0, sizeof(float) * fft_size); + + + float scale = 1.0f / fft_size; + vDSP_fft_zip(m_fft_setup, hrtf_sample, 1, fft_size_log2, kFFTDirection_Forward); + vDSP_zvmul(hrtf_sample, 1, hrtf_accum, 1, hrtf_convolved, 1, fft_size, 1); + vDSP_fft_zip(m_fft_setup, hrtf_convolved, 1, fft_size_log2, kFFTDirection_Inverse); + vDSP_vsmul(hrtf_convolved->realp, 1, &scale, hrtf_convolved->realp, 1, fft_size); + + int output_offset = (m_output_accumulation_block_start) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); + int frames_left = fft_size; + while(frames_left) { + int frames_to_process = (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS - output_offset) / KRENGINE_MAX_OUTPUT_CHANNELS; + if(frames_to_process > frames_left) frames_to_process = frames_left; + vDSP_vadd(m_output_accumulation + output_offset + channel, KRENGINE_MAX_OUTPUT_CHANNELS, hrtf_convolved->realp + fft_size - frames_left, 1, m_output_accumulation + output_offset + channel, KRENGINE_MAX_OUTPUT_CHANNELS, frames_to_process); + frames_left -= frames_to_process; + output_offset = (output_offset + frames_to_process * KRENGINE_MAX_OUTPUT_CHANNELS) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); + } + } + } + } +} + void KRAudioManager::renderITD() { /* diff --git a/KREngine/kraken/KRAudioManager.h b/KREngine/kraken/KRAudioManager.h index 95c0a7e..7cf8a8d 100644 --- a/KREngine/kraken/KRAudioManager.h +++ b/KREngine/kraken/KRAudioManager.h @@ -47,8 +47,8 @@ const int KRENGINE_AUDIO_BUFFERS_PER_SOURCE = 3; const int KRENGINE_AUDIO_BLOCK_LENGTH = 128; // Length of one block to process. Determines the latency of the audio system and sets size for FFT's used in HRTF convolution const int KRENGINE_AUDIO_BLOCK_LOG2N = 7; // 2 ^ KRENGINE_AUDIO_BLOCK_LOG2N = KRENGINE_AUDIO_BLOCK_LENGTH -const int KRENGINE_REVERB_MAX_FFT_LOG_2 = 15; -const int KRENGINE_REVERB_WORKSPACE_SIZE = 1 << KRENGINE_REVERB_MAX_FFT_LOG_2; +const int KRENGINE_REVERB_MAX_FFT_LOG2 = 15; +const int KRENGINE_REVERB_WORKSPACE_SIZE = 1 << KRENGINE_REVERB_MAX_FFT_LOG2; const int KRENGINE_REVERB_MAX_SAMPLES = 435200; // At least 10s reverb impulse response length, divisible by KRENGINE_AUDIO_BLOCK_LENGTH const int KRENGINE_MAX_REVERB_IMPULSE_MIX = 16; // Maximum number of impulse response filters that can be mixed simultaneously @@ -109,6 +109,7 @@ private: void initAudio(); void initOpenAL(); void initSiren(); + void initHRTF(); void cleanupAudio(); void cleanupOpenAL(); @@ -142,15 +143,20 @@ private: int m_output_sample; FFTSetup m_fft_setup; - float *m_reverb_workspace_data; - DSPSplitComplex m_reverb_workspace[3]; + float *m_workspace_data; + DSPSplitComplex m_workspace[3]; float *getBlockAddress(int block_offset); void renderBlock(); void renderReverb(); void renderHRTF(); void renderITD(); - void renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_offset, int frame_count_log_2); + void renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_offset, int frame_count_log2); + + std::vector m_hrtf_sample_locations; + + void getHRTFMix(const KRVector2 &dir, KRVector2 &hrtf1, KRVector2 &hrtf2, KRVector2 &hrtf3, KRVector2 &hrtf4, float &mix1, float &mix2, float &mix3, float &mix4); + KRAudioSample *getHRTFSample(const KRVector2 &hrtf_dir, bool &swap); }; #endif /* defined(KRAUDIO_MANAGER_H) */ diff --git a/KREngine/kraken/KRMat4.cpp b/KREngine/kraken/KRMat4.cpp index eb90f6f..99da4e7 100644 --- a/KREngine/kraken/KRMat4.cpp +++ b/KREngine/kraken/KRMat4.cpp @@ -50,6 +50,14 @@ KRMat4::KRMat4(GLfloat *pMat) { memcpy(m_mat, pMat, sizeof(GLfloat) * 16); } +KRMat4::KRMat4(const KRVector3 &axis_x, const KRVector3 &axis_y, const KRVector3 &axis_z, const KRVector3 &trans) +{ + m_mat[0] = axis_x.x; m_mat[1] = axis_x.y; m_mat[2] = axis_x.z; m_mat[3] = 0.0f; + m_mat[4] = axis_y.x; m_mat[5] = axis_y.y; m_mat[6] = axis_y.z; m_mat[7] = 0.0f; + m_mat[8] = axis_z.x; m_mat[9] = axis_z.y; m_mat[10] = axis_z.z; m_mat[11] = 0.0f; + m_mat[12] = trans.x; m_mat[13] = trans.y; m_mat[14] = trans.z; m_mat[15] = 1.0f; +} + KRMat4::~KRMat4() { } diff --git a/KREngine/kraken/KRMat4.h b/KREngine/kraken/KRMat4.h index 1e39bb6..e4036b4 100644 --- a/KREngine/kraken/KRMat4.h +++ b/KREngine/kraken/KRMat4.h @@ -67,6 +67,8 @@ public: KRMat4(GLfloat *pMat); + KRMat4(const KRVector3 &axis_x, const KRVector3 &axis_y, const KRVector3 &axis_z, const KRVector3 &trans); + // Destructor ~KRMat4();