diff --git a/KREngine/kraken/KRAudioManager.cpp b/KREngine/kraken/KRAudioManager.cpp index fd7f485..9f8449a 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 ----====---- @@ -1488,7 +1491,19 @@ void KRAudioManager::setGlobalAmbientGain(float gain) void KRAudioManager::startFrame(float deltaTime) { - m_mutex.lock(); + static unsigned long trackCount = 0; + static unsigned long trackMissed = 0; + trackCount++; + if (trackCount > 200) { +// printf("Missed %ld out of 200 try_lock attempts on audio startFrame\n", trackMissed); + trackCount = 0; + trackMissed = 0; + } + + if (!m_mutex.try_lock()) { + trackMissed++; + return; // if we are rendering audio don't update audio state + } // NOTE: this misses anywhere from 0 to to 30 times out of 200 on the iPad2 // ----====---- Determine Ambient Zone Contributions ----====---- m_ambient_zone_weights.clear(); @@ -1931,4 +1946,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 = framesize; + + // (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 1a4ecb3..c19697c 100644 --- a/KREngine/kraken/KRAudioManager.h +++ b/KREngine/kraken/KRAudioManager.h @@ -40,13 +40,28 @@ #include "KRMat4.h" #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_POOL_SIZE = 60; //32; + // for Circa we play a maximum of 11 mono audio streams at once + cross fading with ambient + // so we could safely say a maximum of 12 or 13 streams, which would be 39 buffers + // do the WAV files for the reverb use the same buffer pool ??? + +const int KRENGINE_AUDIO_MAX_BUFFER_SIZE = 5120; // in bytes + // this is the buffer for our decoded audio (not the source file data) + // it should be greater then 1152 samples (the size of an mp3 frame in samples) + // so it should be greater then 2304 bytes and also a multiple of 128 samples (to make + // the data flow efficient) but it shouldn't be too large or it will cause + // the render loop to stall out decoding large chunks of mp3 data. + // 2560 bytes would be the smallest size for mono sources, and 5120 would be smallest for stereo. + const int KRENGINE_AUDIO_BUFFERS_PER_SOURCE = 3; -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 + // 7 is 128 .. NOTE: the hrtf code uses magic numbers everywhere and is hardcoded to 128 samples per frame -const int KRENGINE_AUDIO_BLOCK_LOG2N = 7; // 2 ^ KRENGINE_AUDIO_BLOCK_LOG2N = KRENGINE_AUDIO_BLOCK_LENGTH +const int KRENGINE_AUDIO_BLOCK_LENGTH = 1 << KRENGINE_AUDIO_BLOCK_LOG2N; + // Length of one block to process. Determines the latency of the audio system and sets size for FFT's used in HRTF convolution + // the AUGraph works in 1024 sample chunks. At 128 we are making 8 consecutive calls to the renderBlock method for each + // render initiated by the AUGraph. const int KRENGINE_REVERB_MAX_FFT_LOG2 = 15; const int KRENGINE_REVERB_WORKSPACE_SIZE = 1 << KRENGINE_REVERB_MAX_FFT_LOG2; @@ -128,6 +143,7 @@ public: KRAudioBuffer *getBuffer(KRAudioSample &audio_sample, int buffer_index); + static void mute(bool onNotOff); void startFrame(float deltaTime); @@ -216,6 +232,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; diff --git a/KREngine/kraken/KRTextureManager.cpp b/KREngine/kraken/KRTextureManager.cpp index 2f554c8..0e02202 100644 --- a/KREngine/kraken/KRTextureManager.cpp +++ b/KREngine/kraken/KRTextureManager.cpp @@ -329,6 +329,10 @@ void KRTextureManager::balanceTextureMemory() } } + if (maxDimActive > 512) maxDimActive = 512; // FINDME - hack to stop the texture resizer from blowing out its brains .. + // when the texture quality goes up to 1024, the app runs for about 2 mins and then + // runs out of memory. + // Resize active textures to balance the memory usage and mipmap levels for(std::set::iterator itr=m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end() && memory_available > 0; itr++) { KRTexture *activeTexture = *itr;