diff --git a/Components/OPL2/Implementation/Channel.cpp b/Components/OPL2/Implementation/Channel.cpp index aafe43dfb..1a780ff68 100644 --- a/Components/OPL2/Implementation/Channel.cpp +++ b/Components/OPL2/Implementation/Channel.cpp @@ -36,15 +36,13 @@ void Channel::set_feedback_mode(uint8_t value) { int Channel::update(Operator *modulator, Operator *carrier, OperatorOverrides *modulator_overrides, OperatorOverrides *carrier_overrides) { if(use_fm_synthesis_) { // Get modulator level, use that as a phase-adjusting input to the carrier and then return the carrier level. - modulator->update(modulator_state_, key_on_, period_ << frequency_shift_, octave_, 0, modulator_overrides); - const auto modulator_level = modulator_state_.level(); - - carrier->update(carrier_state_, key_on_, period_ << frequency_shift_, octave_, modulator_level, carrier_overrides); + modulator->update(modulator_state_, key_on_, period_ << frequency_shift_, octave_, nullptr, modulator_overrides); + carrier->update(carrier_state_, key_on_, period_ << frequency_shift_, octave_, &modulator_state_, carrier_overrides); return carrier_state_.level(); } else { // Get modulator and carrier levels separately, return their sum. - modulator->update(modulator_state_, key_on_, period_ << frequency_shift_, octave_, 0, modulator_overrides); - carrier->update(carrier_state_, key_on_, period_ << frequency_shift_, octave_, 0, carrier_overrides); + modulator->update(modulator_state_, key_on_, period_ << frequency_shift_, octave_, nullptr, modulator_overrides); + carrier->update(carrier_state_, key_on_, period_ << frequency_shift_, octave_, nullptr, carrier_overrides); return (modulator_state_.level() + carrier_state_.level()); } } diff --git a/Components/OPL2/Implementation/Operator.cpp b/Components/OPL2/Implementation/Operator.cpp index 6eb72a6a9..d75aca14d 100644 --- a/Components/OPL2/Implementation/Operator.cpp +++ b/Components/OPL2/Implementation/Operator.cpp @@ -54,7 +54,7 @@ bool Operator::is_audible(OperatorState &state, OperatorOverrides *overrides) { return state.adsr_attenuation_ != 511; } -void Operator::update(OperatorState &state, bool key_on, int channel_period, int channel_octave, int phase_offset, OperatorOverrides *overrides) { +void Operator::update(OperatorState &state, bool key_on, int channel_period, int channel_octave, OperatorState *phase_offset, OperatorOverrides *overrides) { // Per the documentation: // // Delta phase = ( [desired freq] * 2^19 / [input clock / 72] ) / 2 ^ (b - 1) @@ -77,7 +77,8 @@ void Operator::update(OperatorState &state, bool key_on, int channel_period, int {511, 511, 511, 511}, // AbsSine: endlessly repeat the first half of the sine wave. {255, 0, 255, 0}, // PulseSine: act as if the first quadrant is in the first and third; lock the other two to 0. }; - const int phase = (state.raw_phase_ >> 11) + phase_offset; + const int scaled_phase_offset = phase_offset ? power_two(phase_offset->attenuation, 11) : 0; + const int phase = (state.raw_phase_ + scaled_phase_offset) >> 11; state.attenuation = negative_log_sin(phase & waveforms[int(waveform_)][(phase >> 8) & 3]); // Key-on logic: any time it is false, be in the release state. diff --git a/Components/OPL2/Implementation/Operator.hpp b/Components/OPL2/Implementation/Operator.hpp index 1c5f73b87..0ec73a40e 100644 --- a/Components/OPL2/Implementation/Operator.hpp +++ b/Components/OPL2/Implementation/Operator.hpp @@ -83,7 +83,7 @@ class Operator { void set_am_vibrato_hold_sustain_ksr_multiple(uint8_t value); /// Provides one clock tick to the operator, along with the relevant parameters of its channel. - void update(OperatorState &state, bool key_on, int channel_period, int channel_octave, int phase_offset, OperatorOverrides *overrides = nullptr); + void update(OperatorState &state, bool key_on, int channel_period, int channel_octave, OperatorState *phase_offset, OperatorOverrides *overrides = nullptr); /// @returns @c true if this channel currently has a non-zero output; @c false otherwise. bool is_audible(OperatorState &state, OperatorOverrides *overrides = nullptr); diff --git a/Components/OPL2/Implementation/Tables.hpp b/Components/OPL2/Implementation/Tables.hpp index c7839785d..8953cfca5 100644 --- a/Components/OPL2/Implementation/Tables.hpp +++ b/Components/OPL2/Implementation/Tables.hpp @@ -88,9 +88,10 @@ constexpr LogSign negative_log_sin(int x) { } /*! - Computes the linear value represented by the log-sign @c ls. + Computes the linear value represented by the log-sign @c ls, shifted left by @c fractional prior + to loss of precision. */ -constexpr int power_two(LogSign ls) { +constexpr int power_two(LogSign ls, int fractional = 0) { /// A derivative of the exponent table in a real OPL2; mapped_exp[x] = (source[c ^ 0xff] << 1) | 0x800. /// /// The ahead-of-time transformation represents fixed work the OPL2 does when reading its table @@ -142,7 +143,7 @@ constexpr int power_two(LogSign ls) { 2088, 2082, 2076, 2070, 2064, 2060, 2054, 2048, }; - return (mapped_exp[ls.log & 0xff] >> (ls.log >> 8)) * ls.sign; + return ((mapped_exp[ls.log & 0xff] << fractional) >> (ls.log >> 8)) * ls.sign; } /*