From 1f30ffc5e4dddbd6ffb843bd8c56a8b4de859675 Mon Sep 17 00:00:00 2001 From: Aidan Mueller <10082900+aidan-mueller@users.noreply.github.com> Date: Sat, 1 Jul 2023 22:28:40 -0500 Subject: [PATCH] Fixed issue #5734 (FreeBoy Division by zero) (#6053) * Fixed issue #5734 (FreeBoy Division by zero). Added comments and used more descriptive variable names for noise channel initialization block. Also indented the nested for loop to improve code clarity. The reasons for doing this can be found in this answer: https://softwareengineering.stackexchange.com/a/362796 * Better initial div_ratio guess Allows us to skip r = 0 and a conditional in the loop below. --------- Co-authored-by: Spekular --- plugins/FreeBoy/FreeBoy.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/plugins/FreeBoy/FreeBoy.cpp b/plugins/FreeBoy/FreeBoy.cpp index f9ef2c5aa02..1fd3f2513cc 100644 --- a/plugins/FreeBoy/FreeBoy.cpp +++ b/plugins/FreeBoy/FreeBoy.cpp @@ -358,30 +358,34 @@ void FreeBoyInstrument::playNote(NotePlayHandle* nph, sampleFrame* workingBuffer if (tfp == 0) { - //PRNG Frequency = (1048576 Hz / (ratio + 1)) / 2 ^ (shiftclockfreq + 1) - char sopt = 0; - char ropt = 1; - float fopt = 524288.0 / (ropt * std::pow(2.0, sopt + 1.0)); - float f; + // Initialize noise channel... + // PRNG Frequency = (1048576 Hz / (ratio + 1)) / 2 ^ (shiftclockfreq + 1) + // When div_ratio = 0 the ratio should be 0.5. Since s = 0 is the only case where r = 0 gives + // a unique frequency, we can start by guessing s = r = 0 here and then skip r = 0 in the loop. + char clock_freq = 0; + char div_ratio = 0; + float closest_freq = 524288.0 / (0.5 * std::pow(2.0, clock_freq + 1.0)); + // This nested for loop iterates over all possible combinations of clock frequency and dividing + // ratio and chooses the combination whose resulting frequency is closest to the note frequency for (char s = 0; s < 16; ++s) { - for (char r = 0; r < 8; ++r) + for (char r = 1; r < 8; ++r) { - f = 524288.0 / (r * std::pow(2.0, s + 1.0)); - if (std::fabs(freq - fopt) > std::fabs(freq - f)) + float f = 524288.0 / (r * std::pow(2.0, s + 1.0)); + if (std::fabs(freq - closest_freq) > std::fabs(freq - f)) { - fopt = f; - ropt = r; - sopt = s; + closest_freq = f; + div_ratio = r; + clock_freq = s; } } } - data = sopt; + data = clock_freq; data = data << 1; data += m_ch4ShiftRegWidthModel.value(); data = data << 3; - data += ropt; + data += div_ratio; papu->writeRegister(0xff22, data); //channel 4 init