From 668f4b77f36e50b666f7b97dce14daa6df37dc25 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 8 May 2020 21:05:23 -0400 Subject: [PATCH] Implements feedback. --- Components/OPL2/Implementation/PhaseGenerator.hpp | 9 +++++++++ Components/OPL2/OPLL.cpp | 4 ++++ Components/OPL2/OPLL.hpp | 1 + 3 files changed, 14 insertions(+) diff --git a/Components/OPL2/Implementation/PhaseGenerator.hpp b/Components/OPL2/Implementation/PhaseGenerator.hpp index aaef60683..851b4073e 100644 --- a/Components/OPL2/Implementation/PhaseGenerator.hpp +++ b/Components/OPL2/Implementation/PhaseGenerator.hpp @@ -58,6 +58,15 @@ template class PhaseGenerator { return phase_ >> 1; } + /*! + Applies feedback based on two historic samples of a total output level, + plus the degree of feedback to apply + */ + void apply_feedback(LogSign first, LogSign second, int level) { + constexpr int masks[] = {0, ~0, ~0, ~0, ~0, ~0, ~0, ~0}; + phase_ += ((second.level(precision) + first.level(precision)) >> (8 - level)) & masks[level]; + } + /*! Sets the multiple for this phase generator, in the same terms as an OPL programmer, i.e. a 4-bit number that is used as a lookup into the internal multiples table. diff --git a/Components/OPL2/OPLL.cpp b/Components/OPL2/OPLL.cpp index 429035bcd..584439dfb 100644 --- a/Components/OPL2/OPLL.cpp +++ b/Components/OPL2/OPLL.cpp @@ -377,6 +377,10 @@ int OPLL::melodic_output(int channel) { auto modulation = WaveformGenerator::wave(channels_[channel].modulator_waveform, phase_generators_[channel + 9].phase()); modulation += envelope_generators_[channel + 9].attenuation() + (channels_[channel].modulator_attenuation << 5) + key_level_scalers_[channel + 9].attenuation(); + // Apply feedback, if any. + phase_generators_[channel + 9].apply_feedback(channels_[channel].modulator_output, modulation, channels_[channel].modulator_feedback); + channels_[channel].modulator_output = modulation; + auto carrier = WaveformGenerator::wave(channels_[channel].carrier_waveform, phase_generators_[channel].scaled_phase(), modulation); carrier += envelope_generators_[channel].attenuation() + (channels_[channel].attenuation << 7) + key_level_scalers_[channel].attenuation(); return carrier.level(); diff --git a/Components/OPL2/OPLL.hpp b/Components/OPL2/OPLL.hpp index 3c84fdc7c..086d8b1b5 100644 --- a/Components/OPL2/OPLL.hpp +++ b/Components/OPL2/OPLL.hpp @@ -91,6 +91,7 @@ class OPLL: public OPLBase { int carrier_key_rate_scale_multiplier = 0; int modulator_key_rate_scale_multiplier = 0; + LogSign modulator_output; int modulator_feedback = 0; bool use_sustain = false;