diff options
Diffstat (limited to 'quantum/audio/audio.c')
-rw-r--r-- | quantum/audio/audio.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c index 2570ad9cd1..28c8267517 100644 --- a/quantum/audio/audio.c +++ b/quantum/audio/audio.c @@ -311,6 +311,10 @@ void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat) { return; } + if (n_count == 0) { + return; + } + if (!audio_initialized) { audio_init(); } @@ -547,20 +551,42 @@ void audio_decrease_tempo(uint8_t tempo_change) { note_tempo -= tempo_change; } -// TODO in the int-math version are some bugs; songs sometimes abruptly end - maybe an issue with the timer/system-tick wrapping around? +/** + * Converts from units of 1/64ths of a beat to milliseconds. + * + * Round-off error is at most 1 millisecond. + * + * Conversion will never overflow for duration_bpm <= 699, provided that + * note_tempo is at least 10. This is quite a long duration, over ten beats. + * + * Beware that for duration_bpm > 699, the result may overflow uint16_t range + * when duration_bpm is large compared to note_tempo: + * + * duration_bpm * 60 * 1000 / (64 * note_tempo) > UINT16_MAX + * + * duration_bpm > (2 * 65535 / 1875) * note_tempo + * = 69.904 * note_tempo. + */ uint16_t audio_duration_to_ms(uint16_t duration_bpm) { -#if defined(__AVR__) - // doing int-math saves us some bytes in the overall firmware size, but the intermediate result is less accurate before being cast to/returned as uint - return ((uint32_t)duration_bpm * 60 * 1000) / (64 * note_tempo); - // NOTE: beware of uint16_t overflows when note_tempo is low and/or the duration is long -#else - return ((float)duration_bpm * 60) / (64 * note_tempo) * 1000; -#endif + return ((uint32_t)duration_bpm * 1875) / ((uint_fast16_t)note_tempo * 2); } + +/** + * Converts from units of milliseconds to 1/64ths of a beat. + * + * Round-off error is at most 1/64th of a beat. + * + * This conversion never overflows: since duration_ms <= UINT16_MAX = 65535 + * and note_tempo <= 255, the result is always in uint16_t range: + * + * duration_ms * 64 * note_tempo / 60 / 1000 + * <= 65535 * 2 * 255 / 1875 + * = 17825.52 + * <= UINT16_MAX. + */ uint16_t audio_ms_to_duration(uint16_t duration_ms) { -#if defined(__AVR__) - return ((uint32_t)duration_ms * 64 * note_tempo) / 60 / 1000; -#else - return ((float)duration_ms * 64 * note_tempo) / 60 / 1000; -#endif + return ((uint32_t)duration_ms * 2 * note_tempo) / 1875; } + +__attribute__((weak)) void audio_on_user(void) {} +__attribute__((weak)) void audio_off_user(void) {} |