/** audio: this file implements the audio system. */ #ifndef _LCR_AUDIO #define _LCR_AUDIO #define LCR_SOUND_NONE 0 #define LCR_SOUND_CLICK 1 #define LCR_SOUND_CRASH_SMALL 2 #define LCR_SOUND_CRASH_BIG 3 #define LCR_SOUND_ACCELERATOR 4 #define LCR_AUDIO_CRASH_LEN 2048 struct { uint32_t frame; uint8_t on; uint8_t soundPlayed; uint16_t soundPlayedFrame; uint32_t noise; uint8_t crashSample; int engineIntensity; int engineOsc; int engineInc; } LCR_audio; void LCR_audioInit(void) { LCR_LOG0("initializing audio"); LCR_audio.frame = 0; LCR_audio.on = 1; LCR_audio.soundPlayed = LCR_SOUND_NONE; LCR_audio.soundPlayedFrame = 0; LCR_audio.noise = 0; LCR_audio.crashSample = 0; LCR_audio.engineOsc = 0; LCR_audio.engineInc = 1; LCR_audio.engineIntensity = 0; } void LCR_audioSetEngineIntensity(uint8_t value) { LCR_audio.engineIntensity = value; } void LCR_audioPlaySound(uint8_t sound) { LCR_LOG2("playing sound"); LCR_audio.soundPlayed = sound; LCR_audio.soundPlayedFrame = 0; } uint8_t _LCR_audioNoise(void) { LCR_audio.noise = LCR_audio.noise * 32310901 + 37; return LCR_audio.noise >> 16; } uint8_t LCR_audioGetNextSample(void) { unsigned char result = 128; if (!LCR_audio.on) return result; switch (LCR_audio.soundPlayed) { case LCR_SOUND_CRASH_SMALL: case LCR_SOUND_CRASH_BIG: { int limit = (LCR_audio.soundPlayed == LCR_SOUND_CRASH_BIG ? 256 : 128) - (LCR_audio.soundPlayedFrame * 256) / LCR_AUDIO_CRASH_LEN; if (LCR_audio.frame % 2 || // lower frequency LCR_audio.soundPlayedFrame < LCR_AUDIO_CRASH_LEN / 4) LCR_audio.crashSample = _LCR_audioNoise(); if (LCR_audio.crashSample > limit) LCR_audio.crashSample = (_LCR_audioNoise() % 2) ? 0 : limit; result += LCR_audio.crashSample - limit / 2; if (limit == 0) LCR_audio.soundPlayed = LCR_SOUND_NONE; break; } default: break; } if (LCR_audio.soundPlayed != LCR_SOUND_NONE) LCR_audio.soundPlayedFrame++; else if (LCR_audio.engineIntensity) { LCR_audio.engineOsc += LCR_audio.engineInc ? (((_LCR_audioNoise() % 256) < (10 + LCR_audio.engineIntensity))) : -31; if (LCR_audio.engineInc && LCR_audio.engineOsc > (90 + (LCR_audio.engineIntensity / 8))) LCR_audio.engineInc = 0; else if ((!LCR_audio.engineInc) && LCR_audio.engineOsc < 10) LCR_audio.engineInc = 1; result += LCR_audio.engineIntensity < 20 ? LCR_audio.engineOsc / 2 : LCR_audio.engineOsc; } LCR_audio.frame++; return result; } #endif // guard