From 0db5f917964185bb89b88b7ca3e728b7b5d3ec23 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Fri, 15 Feb 2013 15:13:48 -0800 Subject: [PATCH] Siren audio engine in progress - Implementing Impulse-Response based reverb --- KREngine/Kraken.xcodeproj/project.pbxproj | 2 +- KREngine/kraken/KRAudioManager.cpp | 37 +++++++------ KREngine/kraken/KRAudioManager.h | 4 +- KREngine/kraken/KRAudioSample.cpp | 65 ++++++++++++++++++++--- KREngine/kraken/KRAudioSample.h | 4 +- KREngine/kraken/KREngine-common.h | 1 + 6 files changed, 85 insertions(+), 28 deletions(-) diff --git a/KREngine/Kraken.xcodeproj/project.pbxproj b/KREngine/Kraken.xcodeproj/project.pbxproj index b53c799..66f4f35 100644 --- a/KREngine/Kraken.xcodeproj/project.pbxproj +++ b/KREngine/Kraken.xcodeproj/project.pbxproj @@ -363,7 +363,7 @@ /* Begin PBXFileReference section */ 104A335C1672D31B001C8BA6 /* KRCollider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = KRCollider.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 104A335D1672D31C001C8BA6 /* KRCollider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRCollider.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 10CC33A3168530A300BB9846 /* libPVRTexLib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libPVRTexLib.a; path = PVRTexTool/Library/OSX_x86/Static/libPVRTexLib.a; sourceTree = PVRTexLib; }; + 10CC33A3168530A300BB9846 /* libPVRTexLib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libPVRTexLib.a; path = Utilities/PVRTexLib/MacOS/libPVRTexLib.a; sourceTree = PVRSDK; }; E4030E4B160A3CF000592648 /* KRStockGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRStockGeometry.h; sourceTree = ""; }; E40BA45215EFF79500D7C3DD /* KRAABB.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRAABB.cpp; sourceTree = ""; }; E40BA45315EFF79500D7C3DD /* KRAABB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRAABB.h; sourceTree = ""; }; diff --git a/KREngine/kraken/KRAudioManager.cpp b/KREngine/kraken/KRAudioManager.cpp index 7ede8d6..b7ffb29 100644 --- a/KREngine/kraken/KRAudioManager.cpp +++ b/KREngine/kraken/KRAudioManager.cpp @@ -37,7 +37,6 @@ #include "KRContext.h" #include -#include OSStatus alcASASetListenerProc(const ALuint property, ALvoid *data, ALuint dataSize); ALvoid alcMacOSXRenderingQualityProc(const ALint value); @@ -64,6 +63,7 @@ KRAudioManager::KRAudioManager(KRContext &context) : KRContextObject(context) m_reverb_input_samples = NULL; m_reverb_input_next_sample = 0; + m_reverb_accumulation = NULL; for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) { m_reverb_impulse_responses[i] = NULL; m_reverb_impulse_responses_weight[i] = 0.0f; @@ -137,7 +137,6 @@ void KRAudioManager::renderBlock() // ----====---- Clear output accumulation buffer ----====---- memcpy(m_output_accumulation, m_reverb_accumulation, KRENGINE_FILTER_LENGTH * KRENGINE_MAX_OUTPUT_CHANNELS * sizeof(float)); memset(m_reverb_accumulation, 0, KRENGINE_FILTER_LENGTH * KRENGINE_MAX_OUTPUT_CHANNELS * sizeof(float)); -// memset(m_output_accumulation, 0, KRENGINE_FILTER_LENGTH * KRENGINE_MAX_OUTPUT_CHANNELS * sizeof(float)); // ----====---- Render direct / HRTF audio ----====---- @@ -154,26 +153,22 @@ void KRAudioManager::renderBlock() if(reverb_send_level > 0.0f) { KRAudioSample *sample = source->getAudioSample(); if(sample) { - sample->sample((int)((__int64_t)m_audio_frame - source->getStartAudioFrame()), 44100, KRENGINE_FILTER_LENGTH, 0, reverb_data); - for(int i=0; i < KRENGINE_FILTER_LENGTH; i++) { - reverb_accum[i] += reverb_data[i] * reverb_send_level; - } + sample->sample((int)((__int64_t)m_audio_frame - source->getStartAudioFrame()), KRENGINE_FILTER_LENGTH, 0, reverb_data, reverb_send_level); + vDSP_vadd(reverb_accum, 1, reverb_data, 1, reverb_accum, 1, KRENGINE_FILTER_LENGTH); } } } - m_reverb_input_next_sample += KRENGINE_FILTER_LENGTH; if(m_reverb_input_next_sample >= KRENGINE_REVERB_MAX_SAMPLES) { m_reverb_input_next_sample = 0; } // Apply impulse response reverb -// KRAudioSample *impulse_response = getContext().getAudioManager()->get("hrtf_kemar_H-10e000a"); +// KRAudioSample *impulse_response = getContext().getAudioManager()->get("hrtf_kemar_H10e040a"); KRAudioSample *impulse_response = getContext().getAudioManager()->get("test_reverb"); if(impulse_response) { - int impulse_response_blocks = impulse_response->getFrameCount(44100) / KRENGINE_FILTER_LENGTH + 1; - impulse_response_blocks = 50; + int impulse_response_blocks = impulse_response->getFrameCount() / KRENGINE_FILTER_LENGTH + 1; for(int impulse_response_block=0; impulse_response_block < impulse_response_blocks; impulse_response_block++) { float impulse_block_start_index = impulse_response_block * KRENGINE_FILTER_LENGTH; int reverb_block_start_index = (m_reverb_input_next_sample - KRENGINE_FILTER_LENGTH * (impulse_response_block + 1)); @@ -196,18 +191,22 @@ void KRAudioManager::renderBlock() vDSP_fft_zip(m_fft_setup, &reverb_sample_data_complex, 1, KRENGINE_FILTER_LOG2 + 1, kFFTDirection_Forward); - int impulse_response_channels = 2; + for(int channel=0; channel < impulse_response_channels; channel++) { float impulse_response_block_real[KRENGINE_FILTER_LENGTH * 2] __attribute__ ((aligned)); float impulse_response_block_imag[KRENGINE_FILTER_LENGTH * 2] __attribute__ ((aligned)); - impulse_response->sample(impulse_block_start_index, 44100, KRENGINE_FILTER_LENGTH, channel, impulse_response_block_real); + impulse_response->sample(impulse_block_start_index, KRENGINE_FILTER_LENGTH, channel, impulse_response_block_real, 1.0f); memset(impulse_response_block_real + KRENGINE_FILTER_LENGTH, 0, KRENGINE_FILTER_LENGTH * sizeof(float)); memset(impulse_response_block_imag, 0, KRENGINE_FILTER_LENGTH * 2 * sizeof(float)); + + + + DSPSplitComplex impulse_block_data_complex; - impulse_block_data_complex.realp = impulse_response_block_real; + impulse_block_data_complex.realp = impulse_response_block_real ; impulse_block_data_complex.imagp = impulse_response_block_imag; float conv_data_real[KRENGINE_FILTER_LENGTH * 2] __attribute__ ((aligned)); @@ -425,12 +424,11 @@ void KRAudioManager::initSiren() m_reverb_input_samples = (float *)malloc(buffer_size); memset(m_reverb_input_samples, 0, buffer_size); m_reverb_input_next_sample = 0; - memset(m_reverb_input_samples, 0, buffer_size); - - memset(m_reverb_accumulation, 0, KRENGINE_FILTER_LENGTH * 2 * sizeof(float)); + m_reverb_accumulation = (float *)malloc(buffer_size * 2); // 2 channels + memset(m_reverb_accumulation, 0, buffer_size * 2); - m_fft_setup = vDSP_create_fftsetup( KRENGINE_FILTER_LOG2 + 1, kFFTRadix2); // We add 1 to KRENGINE_FILTER_LOG2, as we will zero-out the second half of the buffer when doing the overlap-add FFT convolution method + m_fft_setup = vDSP_create_fftsetup( 16, kFFTRadix2); // ----====---- Initialize Core Audio Objects ----====---- OSDEBUG(NewAUGraph(&m_auGraph)); @@ -587,6 +585,11 @@ void KRAudioManager::cleanupSiren() free(m_reverb_input_samples); m_reverb_input_samples = NULL; } + + if(m_reverb_accumulation) { + free(m_reverb_accumulation); + m_reverb_accumulation = NULL; + } for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) { m_reverb_impulse_responses[i] = NULL; diff --git a/KREngine/kraken/KRAudioManager.h b/KREngine/kraken/KRAudioManager.h index 0edecfb..a7751ec 100644 --- a/KREngine/kraken/KRAudioManager.h +++ b/KREngine/kraken/KRAudioManager.h @@ -132,9 +132,9 @@ private: KRAudioSample *m_reverb_impulse_responses[KRENGINE_MAX_REVERB_IMPULSE_MIX]; float m_reverb_impulse_responses_weight[KRENGINE_MAX_REVERB_IMPULSE_MIX]; - float m_reverb_accumulation[KRENGINE_FILTER_LENGTH * 2]; + float *m_reverb_accumulation; - float m_output_accumulation[KRENGINE_FILTER_LENGTH * KRENGINE_MAX_OUTPUT_CHANNELS]; // Interleaved output accumulation buffer + float *m_output_accumulation[KRENGINE_FILTER_LENGTH * KRENGINE_MAX_OUTPUT_CHANNELS]; // Interleaved output accumulation buffer int m_output_sample; FFTSetup m_fft_setup; diff --git a/KREngine/kraken/KRAudioSample.cpp b/KREngine/kraken/KRAudioSample.cpp index 276ce75..5ec6caf 100644 --- a/KREngine/kraken/KRAudioSample.cpp +++ b/KREngine/kraken/KRAudioSample.cpp @@ -35,6 +35,8 @@ #include "KRAudioBuffer.h" #include "KRContext.h" +#include + KRAudioSample::KRAudioSample(KRContext &context, std::string name, std::string extension) : KRResource(context, name) { m_pData = new KRDataBlock(); @@ -78,9 +80,10 @@ int KRAudioSample::getChannelCount() return m_channelsPerFrame; } -int KRAudioSample::getFrameCount(int frame_rate) +int KRAudioSample::getFrameCount() { - return (int)((__int64_t)m_totalFrames * (__int64_t)frame_rate / (__int64_t)m_frameRate); + //return (int)((__int64_t)m_totalFrames * (__int64_t)frame_rate / (__int64_t)m_frameRate); + return m_totalFrames; } float KRAudioSample::sample(int frame_offset, int frame_rate, int channel) @@ -116,12 +119,62 @@ float KRAudioSample::sample(int frame_offset, int frame_rate, int channel) } } -void KRAudioSample::sample(int frame_offset, int frame_rate, int frame_count, int channel, float *buffer) +void KRAudioSample::sample(int frame_offset, int frame_count, int channel, float *buffer, float amplitude) { - // FINDME, TODO, HACK - Replace with optimized function utilizing SIMD - for(int i=0; i < frame_count; i++ ) { - buffer[i] = sample(frame_offset + i, frame_rate, channel); + if(frame_offset + frame_count < 0) { + // Range is entirely before the sample + memset(buffer, 0, frame_count * sizeof(float)); + } else if(frame_offset >= m_totalFrames) { + // Range is entirely after the sample + memset(buffer, 0, frame_count * sizeof(float)); + } else { + int start_frame = frame_offset < 0 ? 0 : frame_offset; + int prefix_frames = frame_offset < 0 ? -frame_offset : 0; + if(prefix_frames > 0) { + // Prefix with padding of 0's + memset(buffer, 0, prefix_frames * sizeof(float)); + } + + int frames_per_buffer = KRENGINE_AUDIO_MAX_BUFFER_SIZE / m_bytesPerFrame; + + int buffer_index = start_frame / frames_per_buffer; + int buffer_offset = start_frame % frames_per_buffer; + int processed_frames = prefix_frames; + while(processed_frames < frame_count) { + int frames_left = frame_count - processed_frames; + if(buffer_index >= m_bufferCount) { + // Suffix with padding of 0's + memset(buffer + processed_frames, 0, frames_left * sizeof(float)); + processed_frames += frames_left; + } else { + KRAudioBuffer *source_buffer = getContext().getAudioManager()->getBuffer(*this, buffer_index); + int frames_to_copy = source_buffer->getFrameCount() - buffer_offset; + if(frames_to_copy > frames_left) frames_to_copy = frames_left; + if(frames_to_copy > 0) { + /* + + void vDSP_vflt16 ( + short *A, + vDSP_Stride __vDSP_I, + float *__vDSP_C, + vDSP_Stride __vDSP_K, + vDSP_Length __vDSP_N + ); + + */ + signed short *source_data = source_buffer->getFrameData() + buffer_offset * m_channelsPerFrame + channel; + vDSP_vflt16(source_data, m_channelsPerFrame, buffer + processed_frames, 1, frames_to_copy); + //memcpy(buffer + processed_frames, source_buffer->getFrameData() + buffer_offset, frames_to_copy * m_channelsPerFrame * sizeof(float)); + processed_frames += frames_to_copy; + } + buffer_index++; + buffer_offset = 0; + } + } } + + float scale = amplitude / 32768.0f; + vDSP_vsmul(buffer, 1, &scale, buffer, 1, frame_count); } OSStatus KRAudioSample::ReadProc( // AudioFile_ReadProc diff --git a/KREngine/kraken/KRAudioSample.h b/KREngine/kraken/KRAudioSample.h index 2f46e65..9183af6 100644 --- a/KREngine/kraken/KRAudioSample.h +++ b/KREngine/kraken/KRAudioSample.h @@ -56,9 +56,9 @@ public: // Siren audio engine interface int getChannelCount(); - int getFrameCount(int frame_rate); + int getFrameCount(); float sample(int frame_offset, int frame_rate, int channel); - void sample(int frame_offset, int frame_rate, int frame_count, int channel, float *buffer); + void sample(int frame_offset, int frame_count, int channel, float *buffer, float amplitude); private: diff --git a/KREngine/kraken/KREngine-common.h b/KREngine/kraken/KREngine-common.h index 1757c09..688590e 100644 --- a/KREngine/kraken/KREngine-common.h +++ b/KREngine/kraken/KREngine-common.h @@ -82,6 +82,7 @@ using std::queue; #endif +#include #include #include #include