Siren audio engine in progress - Implementing Impulse-Response based reverb
This commit is contained in:
@@ -64,6 +64,8 @@ KRAudioManager::KRAudioManager(KRContext &context) : KRContextObject(context)
|
|||||||
m_reverb_input_samples = NULL;
|
m_reverb_input_samples = NULL;
|
||||||
m_reverb_input_next_sample = 0;
|
m_reverb_input_next_sample = 0;
|
||||||
|
|
||||||
|
m_reverb_workspace_data = NULL;
|
||||||
|
|
||||||
for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) {
|
for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) {
|
||||||
m_reverb_impulse_responses[i] = NULL;
|
m_reverb_impulse_responses[i] = NULL;
|
||||||
m_reverb_impulse_responses_weight[i] = 0.0f;
|
m_reverb_impulse_responses_weight[i] = 0.0f;
|
||||||
@@ -141,6 +143,10 @@ float *KRAudioManager::getBlockAddress(int block_offset)
|
|||||||
|
|
||||||
void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_block)
|
void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response, int impulse_response_block)
|
||||||
{
|
{
|
||||||
|
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];
|
||||||
|
|
||||||
float *block_data = getBlockAddress(0);
|
float *block_data = getBlockAddress(0);
|
||||||
float *next_block = getBlockAddress(1);
|
float *next_block = getBlockAddress(1);
|
||||||
|
|
||||||
@@ -152,52 +158,31 @@ void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response
|
|||||||
reverb_block_start_index = reverb_block_start_index % KRENGINE_REVERB_MAX_SAMPLES;
|
reverb_block_start_index = reverb_block_start_index % KRENGINE_REVERB_MAX_SAMPLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
float reverb_sample_data_real[KRENGINE_FILTER_LENGTH * 2] __attribute__ ((aligned));
|
|
||||||
memcpy(reverb_sample_data_real, m_reverb_input_samples + reverb_block_start_index, KRENGINE_FILTER_LENGTH * sizeof(float));
|
|
||||||
memset(reverb_sample_data_real + KRENGINE_FILTER_LENGTH, 0, KRENGINE_FILTER_LENGTH * sizeof(float));
|
|
||||||
|
|
||||||
float reverb_sample_data_imag[KRENGINE_FILTER_LENGTH * 2] __attribute__ ((aligned));
|
|
||||||
memset(reverb_sample_data_imag, 0, KRENGINE_FILTER_LENGTH * 2 * sizeof(float));
|
|
||||||
|
|
||||||
DSPSplitComplex reverb_sample_data_complex;
|
memcpy(reverb_sample_data_complex.realp, m_reverb_input_samples + reverb_block_start_index, KRENGINE_FILTER_LENGTH * sizeof(float));
|
||||||
reverb_sample_data_complex.realp = reverb_sample_data_real;
|
memset(reverb_sample_data_complex.realp + KRENGINE_FILTER_LENGTH, 0, KRENGINE_FILTER_LENGTH * sizeof(float));
|
||||||
reverb_sample_data_complex.imagp = reverb_sample_data_imag;
|
memset(reverb_sample_data_complex.imagp, 0, KRENGINE_FILTER_LENGTH * 2 * sizeof(float));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vDSP_fft_zip(m_fft_setup, &reverb_sample_data_complex, 1, KRENGINE_FILTER_LOG2 + 1, kFFTDirection_Forward);
|
vDSP_fft_zip(m_fft_setup, &reverb_sample_data_complex, 1, KRENGINE_FILTER_LOG2 + 1, kFFTDirection_Forward);
|
||||||
|
|
||||||
int impulse_response_channels = 2;
|
float scale = 1.0f / (2 * (KRENGINE_FILTER_LENGTH * 2));
|
||||||
|
|
||||||
|
int impulse_response_channels = 2;
|
||||||
for(int channel=0; channel < impulse_response_channels; channel++) {
|
for(int channel=0; channel < impulse_response_channels; channel++) {
|
||||||
|
|
||||||
float impulse_response_block_real[KRENGINE_FILTER_LENGTH * 2] __attribute__ ((aligned));
|
impulse_response->sample(impulse_block_start_index, KRENGINE_FILTER_LENGTH, channel, impulse_block_data_complex.realp, 1.0f);
|
||||||
float impulse_response_block_imag[KRENGINE_FILTER_LENGTH * 2] __attribute__ ((aligned));
|
memset(impulse_block_data_complex.realp + KRENGINE_FILTER_LENGTH, 0, KRENGINE_FILTER_LENGTH * sizeof(float));
|
||||||
impulse_response->sample(impulse_block_start_index, KRENGINE_FILTER_LENGTH, channel, impulse_response_block_real, 1.0f);
|
memset(impulse_block_data_complex.imagp, 0, KRENGINE_FILTER_LENGTH * 2 * sizeof(float));
|
||||||
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.imagp = impulse_response_block_imag;
|
|
||||||
|
|
||||||
float conv_data_real[KRENGINE_FILTER_LENGTH * 2] __attribute__ ((aligned));
|
|
||||||
float conv_data_imag[KRENGINE_FILTER_LENGTH * 2] __attribute__ ((aligned));
|
|
||||||
DSPSplitComplex conv_data_complex;
|
|
||||||
conv_data_complex.realp = conv_data_real;
|
|
||||||
conv_data_complex.imagp = conv_data_imag;
|
|
||||||
|
|
||||||
vDSP_fft_zip(m_fft_setup, &impulse_block_data_complex, 1, KRENGINE_FILTER_LOG2 + 1, kFFTDirection_Forward);
|
vDSP_fft_zip(m_fft_setup, &impulse_block_data_complex, 1, KRENGINE_FILTER_LOG2 + 1, kFFTDirection_Forward);
|
||||||
|
|
||||||
vDSP_zvmul(&reverb_sample_data_complex, 1, &impulse_block_data_complex, 1, &conv_data_complex, 1, KRENGINE_FILTER_LENGTH * 2, 1);
|
vDSP_zvmul(&reverb_sample_data_complex, 1, &impulse_block_data_complex, 1, &conv_data_complex, 1, KRENGINE_FILTER_LENGTH * 2, 1);
|
||||||
|
|
||||||
vDSP_fft_zip(m_fft_setup, &conv_data_complex, 1, KRENGINE_FILTER_LOG2 + 1, kFFTDirection_Inverse);
|
vDSP_fft_zip(m_fft_setup, &conv_data_complex, 1, KRENGINE_FILTER_LOG2 + 1, kFFTDirection_Inverse);
|
||||||
|
|
||||||
float scale = 1.0f / (2 * (KRENGINE_FILTER_LENGTH * 2));
|
|
||||||
|
|
||||||
vDSP_vsmul(conv_data_complex.realp, 1, &scale, conv_data_complex.realp, 1, KRENGINE_FILTER_LENGTH * 2);
|
vDSP_vsmul(conv_data_complex.realp, 1, &scale, conv_data_complex.realp, 1, KRENGINE_FILTER_LENGTH * 2);
|
||||||
|
vDSP_vadd(block_data + channel, impulse_response_channels, conv_data_complex.realp, 1, block_data + channel, impulse_response_channels, KRENGINE_FILTER_LENGTH);
|
||||||
vDSP_vadd(block_data + channel, impulse_response_channels, conv_data_real, 1, block_data + channel, impulse_response_channels, KRENGINE_FILTER_LENGTH);
|
vDSP_vadd(next_block + channel, impulse_response_channels, conv_data_complex.realp + KRENGINE_FILTER_LENGTH, 1, next_block + channel, impulse_response_channels, KRENGINE_FILTER_LENGTH);
|
||||||
|
|
||||||
vDSP_vadd(next_block + channel, impulse_response_channels, conv_data_real + KRENGINE_FILTER_LENGTH, 1, next_block + channel, impulse_response_channels, KRENGINE_FILTER_LENGTH);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,6 +289,13 @@ void KRAudioManager::initSiren()
|
|||||||
memset(m_output_accumulation, 0, buffer_size * 2);
|
memset(m_output_accumulation, 0, buffer_size * 2);
|
||||||
m_output_accumulation_block_start = 0;
|
m_output_accumulation_block_start = 0;
|
||||||
|
|
||||||
|
m_reverb_workspace_data = (float *)malloc(KRENGINE_REVERB_WORKSPACE_SIZE * 6);
|
||||||
|
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_fft_setup = vDSP_create_fftsetup( 16, kFFTRadix2);
|
m_fft_setup = vDSP_create_fftsetup( 16, kFFTRadix2);
|
||||||
|
|
||||||
@@ -468,6 +460,11 @@ void KRAudioManager::cleanupSiren()
|
|||||||
m_output_accumulation = NULL;
|
m_output_accumulation = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(m_reverb_workspace_data) {
|
||||||
|
free(m_reverb_workspace_data);
|
||||||
|
m_reverb_workspace_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) {
|
for(int i=0; i < KRENGINE_MAX_REVERB_IMPULSE_MIX; i++) {
|
||||||
m_reverb_impulse_responses[i] = NULL;
|
m_reverb_impulse_responses[i] = NULL;
|
||||||
m_reverb_impulse_responses_weight[i] = 0.0f;
|
m_reverb_impulse_responses_weight[i] = 0.0f;
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ const int KRENGINE_AUDIO_BUFFERS_PER_SOURCE = 3;
|
|||||||
const int KRENGINE_FILTER_LENGTH = 128; // Size for FFT's used in HRTF convolution
|
const int KRENGINE_FILTER_LENGTH = 128; // Size for FFT's used in HRTF convolution
|
||||||
const int KRENGINE_FILTER_LOG2 = 7; // 2 ^ 7 = 128
|
const int KRENGINE_FILTER_LOG2 = 7; // 2 ^ 7 = 128
|
||||||
|
|
||||||
|
const int KRENGINE_REVERB_WORKSPACE_SIZE = KRENGINE_FILTER_LENGTH * 2;
|
||||||
|
|
||||||
const int KRENGINE_REVERB_MAX_SAMPLES = 435200; // At least 10s reverb impulse response length, divisible by KRENGINE_REVERB_FILTER_LENGTH
|
const int KRENGINE_REVERB_MAX_SAMPLES = 435200; // At least 10s reverb impulse response length, divisible by KRENGINE_REVERB_FILTER_LENGTH
|
||||||
const int KRENGINE_MAX_REVERB_IMPULSE_MIX = 16; // Maximum number of impulse response filters that can be mixed simultaneously
|
const int KRENGINE_MAX_REVERB_IMPULSE_MIX = 16; // Maximum number of impulse response filters that can be mixed simultaneously
|
||||||
const int KRENGINE_MAX_OUTPUT_CHANNELS = 2;
|
const int KRENGINE_MAX_OUTPUT_CHANNELS = 2;
|
||||||
@@ -138,6 +140,8 @@ private:
|
|||||||
int m_output_sample;
|
int m_output_sample;
|
||||||
|
|
||||||
FFTSetup m_fft_setup;
|
FFTSetup m_fft_setup;
|
||||||
|
float *m_reverb_workspace_data;
|
||||||
|
DSPSplitComplex m_reverb_workspace[3];
|
||||||
|
|
||||||
float *getBlockAddress(int block_offset);
|
float *getBlockAddress(int block_offset);
|
||||||
void renderBlock();
|
void renderBlock();
|
||||||
|
|||||||
Reference in New Issue
Block a user