summaryrefslogtreecommitdiff
path: root/quantum/audio
diff options
context:
space:
mode:
authorPascal Getreuer <50221757+getreuer@users.noreply.github.com>2023-07-07 08:47:16 -0600
committerGitHub <noreply@github.com>2023-07-08 00:47:16 +1000
commita8a87a0922a33d38ed80165ee62f9dc35bd08a3d (patch)
treeb590d46212c06e92f1683e08d9ebf12784eabd32 /quantum/audio
parente648b84da3db022ba308163f21c3cf8165c45e09 (diff)
[Core] Simplify audio_duration_to_ms() and audio_ms_to_duration(), reduce firmware size by a few bytes. (#21427)
Diffstat (limited to 'quantum/audio')
-rw-r--r--quantum/audio/audio.c45
1 files changed, 32 insertions, 13 deletions
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
index 2570ad9cd1..0300483a93 100644
--- a/quantum/audio/audio.c
+++ b/quantum/audio/audio.c
@@ -547,20 +547,39 @@ 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;
}