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:
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user