Fixed access violations

Implemented a divide-and-conquer approach to speeding up reverb engine, without increasing latency using multiple, different sized FFT's.  Algorithm optimized to ensure that the same amount of processing is done each frame.  Reverb now working in real-time.
This commit is contained in:
2013-02-16 01:35:05 -08:00
parent eee1dc28e0
commit 7e0459653d
6 changed files with 42 additions and 15 deletions

View File

@@ -152,7 +152,7 @@ void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response
DSPSplitComplex impulse_block_data_complex = m_reverb_workspace[1];
DSPSplitComplex conv_data_complex = m_reverb_workspace[2];
int reverb_offset = (m_reverb_input_next_sample - impulse_response_offset);
int reverb_offset = (m_reverb_input_next_sample + KRENGINE_AUDIO_BLOCK_LENGTH - frame_count);
if(reverb_offset < 0) {
reverb_offset += KRENGINE_REVERB_MAX_SAMPLES;
} else {
@@ -180,7 +180,7 @@ void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response
for(int channel=0; channel < impulse_response_channels; channel++) {
impulse_response->sample(impulse_response_offset, frame_count, channel, impulse_block_data_complex.realp, 1.0f);
memset(impulse_block_data_complex.realp + frame_count, 0, KRENGINE_AUDIO_BLOCK_LENGTH * sizeof(float));
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);
@@ -189,10 +189,10 @@ void KRAudioManager::renderReverbImpulseResponse(KRAudioSample *impulse_response
vDSP_vsmul(conv_data_complex.realp, 1, &scale, conv_data_complex.realp, 1, fft_size);
int output_offset = m_output_accumulation_block_start;
int output_offset = (m_output_accumulation_block_start + impulse_response_offset * KRENGINE_MAX_OUTPUT_CHANNELS) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS);
frames_left = fft_size;
while(frames_left) {
int frames_to_process = (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS - m_output_accumulation_block_start) / 2;
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, conv_data_complex.realp + fft_size - frames_left, 1, m_output_accumulation + output_offset + channel, KRENGINE_MAX_OUTPUT_CHANNELS, frames_to_process);
frames_left -= frames_to_process;
@@ -229,11 +229,36 @@ 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;
for(int impulse_response_block=0; impulse_response_block < impulse_response_blocks; impulse_response_block++) {
renderReverbImpulseResponse(impulse_response_sample, impulse_response_block * KRENGINE_AUDIO_BLOCK_LENGTH, KRENGINE_AUDIO_BLOCK_LOG2N);
int period_log_2 = 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;
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, "----");
}
impulse_response_block += period;
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++;
}
}
}
// fprintf(stderr, "\n");
}
m_reverb_sequence = (m_reverb_sequence + 1) % 0x1000000;
// Rotate reverb buffer
m_reverb_input_next_sample = (m_reverb_input_next_sample + KRENGINE_AUDIO_BLOCK_LENGTH) % KRENGINE_REVERB_MAX_SAMPLES;
}
@@ -302,7 +327,7 @@ 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);
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;
@@ -312,7 +337,7 @@ void KRAudioManager::initSiren()
m_reverb_sequence = 0;
m_fft_setup = vDSP_create_fftsetup( 16, kFFTRadix2);
m_fft_setup = vDSP_create_fftsetup( KRENGINE_REVERB_MAX_FFT_LOG_2, kFFTRadix2);
// ----====---- Initialize Core Audio Objects ----====----
OSDEBUG(NewAUGraph(&m_auGraph));

View File

@@ -44,10 +44,11 @@ const int KRENGINE_AUDIO_MAX_POOL_SIZE = 32;
const int KRENGINE_AUDIO_MAX_BUFFER_SIZE = 64*1024;
const int KRENGINE_AUDIO_BUFFERS_PER_SOURCE = 3;
const int KRENGINE_AUDIO_BLOCK_LENGTH = 512; // 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 = 9; // 2 ^ KRENGINE_AUDIO_BLOCK_LOG2N = KRENGINE_AUDIO_BLOCK_LENGTH
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_WORKSPACE_SIZE = KRENGINE_AUDIO_BLOCK_LENGTH * 4;
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_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

View File

@@ -121,7 +121,7 @@ float KRAudioSample::sample(int frame_offset, int frame_rate, int channel)
void KRAudioSample::sample(int frame_offset, int frame_count, int channel, float *buffer, float amplitude)
{
if(frame_offset + frame_count < 0) {
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) {

View File

@@ -46,7 +46,8 @@ KRMeshManager::KRMeshManager(KRContext &context) : KRContextObject(context) {
m_randomParticleVertexData = NULL;
m_volumetricLightingVertexData = NULL;
addModel(new KRMeshCube(context));
// addModel(new KRMeshCube(context)); // FINDME - HACK! This needs to be fixed, as it currently segfaults
addModel(new KRMeshSphere(context));
}

View File

@@ -147,7 +147,7 @@ void KRScene::render(KRCamera *pCamera, std::map<KRAABB, int> &visibleBounds, co
}
}
void KRScene::render(KROctreeNode *pOctreeNode, std::map<KRAABB, int> &visibleBounds, KRCamera *pCamera, std::vector<KRLight *> lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly)
void KRScene::render(KROctreeNode *pOctreeNode, std::map<KRAABB, int> &visibleBounds, KRCamera *pCamera, std::vector<KRLight *> &lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly)
{
if(pOctreeNode) {

View File

@@ -67,7 +67,7 @@ public:
void renderFrame(float deltaTime, int width, int height);
void render(KRCamera *pCamera, std::map<KRAABB, int> &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, bool new_frame);
void render(KROctreeNode *pOctreeNode, std::map<KRAABB, int> &visibleBounds, KRCamera *pCamera, std::vector<KRLight *> lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly);
void render(KROctreeNode *pOctreeNode, std::map<KRAABB, int> &visibleBounds, KRCamera *pCamera, std::vector<KRLight *> &lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly);
void notify_sceneGraphCreate(KRNode *pNode);