diff --git a/KREngine/kraken/KRAudioManager.cpp b/KREngine/kraken/KRAudioManager.cpp index fd7f485..8634bba 100644 --- a/KREngine/kraken/KRAudioManager.cpp +++ b/KREngine/kraken/KRAudioManager.cpp @@ -406,6 +406,9 @@ void KRAudioManager::renderBlock() // ----====---- Render Ambient Sound ----====---- renderAmbient(); + + // ----====---- Render Ambient Sound ----====---- + renderLimiter(); } // ----====---- Advance audio sources ----====---- @@ -1931,4 +1934,114 @@ void KRAudioManager::renderITD() */ -} \ No newline at end of file +} + +static bool audioIsMuted = false; +static bool audioShouldBecomeMuted = false; +static bool audioShouldBecomeUnmuted = false; + +void audioLimit_Mute(bool onNotOff) { + if (onNotOff) { + if (audioIsMuted) return; + audioShouldBecomeMuted = true; + audioShouldBecomeUnmuted = false; + } + else { + if (!audioIsMuted) return; + audioShouldBecomeMuted = false; + audioShouldBecomeUnmuted = true; + } +} + +float audioGetLimitParameters_Stereo(float *buffer, unsigned long framesize, + unsigned long *attack_sample_position, float *peak) +{ + float limitvol = 1.0; + long attack_position = -1; + *peak = 0.0; + float max = 0.0; + float amplitude = 0.0; + + float *src = buffer; + for (unsigned long i = 0; i < framesize * 2; i++) { + amplitude = fabs(*src); src++; + if (amplitude > max) max = amplitude; + if (amplitude > 0.995) if (attack_position < 0) attack_position = (i+1) / 2; + } + if (max > 0.995) limitvol = 0.995 / max; + *peak = max; + + if (attack_position < 0) attack_position = framesize; + *attack_sample_position = (unsigned long) attack_position; + return limitvol; +} // returns the new limit volume, *attack_sample_position tells how fast we need to reach the new limit + +void audioLimit_Stereo(float *stereo_buffer, unsigned long framesize) +{ + static float limit_value = 1.0; + + // (1) get the limiting parameters for the incoming audio data + float previouslimitvol = limit_value; + float peak; + unsigned long attack_sample_position; + + // (1a) check for a mute or unmute state then get the next limit volume + float nextlimitvol = 0.0; + if (audioIsMuted && audioShouldBecomeUnmuted) { audioIsMuted = false; audioShouldBecomeUnmuted = false; } + if (audioShouldBecomeMuted) { audioIsMuted = true; audioShouldBecomeMuted = false; } + if (!audioIsMuted) nextlimitvol = audioGetLimitParameters_Stereo(stereo_buffer, framesize, &attack_sample_position, &peak); + + // (1b) if no limiting is needed then return + if ((1.0 == nextlimitvol) && (1.0 == previouslimitvol)) { return; } // no limiting necessary + + // (2) calculate limiting factors + float deltavol = 0.0; + if (previouslimitvol != nextlimitvol) { + deltavol = (nextlimitvol - previouslimitvol) / (float) attack_sample_position; + } + + // (3) do the limiting + float *src = stereo_buffer; + + if (0.0 == deltavol) { // fixed volume + for (unsigned long i=0; i < framesize; i++) { + *src = *src * nextlimitvol; + src++; + *src = *src * nextlimitvol; + src++; + } + } + else { + for (unsigned long i=0; i < attack_sample_position; i++) { // attack phase + *src = *src * previouslimitvol; + src++; + *src = *src * previouslimitvol; + src++; + previouslimitvol += deltavol; + } + if (nextlimitvol < 1.0) { // plateau phase + for (unsigned long i = attack_sample_position; i < framesize; i++) { + *src = *src * nextlimitvol; + src++; + *src = *src * nextlimitvol; + src++; + } + } + } + + // (4) save our limit level for next time + limit_value = nextlimitvol; +} + +void KRAudioManager::mute(bool onNotOff) +{ + audioLimit_Mute(onNotOff); +} + +void KRAudioManager::renderLimiter() +{ + int output_offset = (m_output_accumulation_block_start) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); + float *output = m_output_accumulation + output_offset; + unsigned long numframes = KRENGINE_AUDIO_BLOCK_LENGTH; + audioLimit_Stereo(output, numframes); +} diff --git a/KREngine/kraken/KRAudioManager.h b/KREngine/kraken/KRAudioManager.h index c2bff56..a39357c 100644 --- a/KREngine/kraken/KRAudioManager.h +++ b/KREngine/kraken/KRAudioManager.h @@ -41,7 +41,7 @@ #include "KRAudioSource.h" const int KRENGINE_AUDIO_MAX_POOL_SIZE = 32; -const int KRENGINE_AUDIO_MAX_BUFFER_SIZE = 64*1024; +const int KRENGINE_AUDIO_MAX_BUFFER_SIZE = 64*1024; // this is the buffer for our decoded audio (not the source file data) const int KRENGINE_AUDIO_BUFFERS_PER_SOURCE = 3; const int KRENGINE_AUDIO_BLOCK_LOG2N = 7; // 2 ^ KRENGINE_AUDIO_BLOCK_LOG2N = KRENGINE_AUDIO_BLOCK_LENGTH @@ -133,6 +133,7 @@ public: KRAudioBuffer *getBuffer(KRAudioSample &audio_sample, int buffer_index); + void mute(bool onNotOff); void startFrame(float deltaTime); @@ -221,6 +222,7 @@ private: void renderHRTF(); void renderITD(); void renderReverbImpulseResponse(int impulse_response_offset, int frame_count_log2); + void renderLimiter(); std::vector m_hrtf_sample_locations; float *m_hrtf_data;