diff --git a/Components/OPL2/Implementation/Channel.cpp b/Components/OPL2/Implementation/Channel.cpp index 9c92feb77..6387b5e00 100644 --- a/Components/OPL2/Implementation/Channel.cpp +++ b/Components/OPL2/Implementation/Channel.cpp @@ -37,33 +37,33 @@ void Channel::update(bool modulator, const LowFrequencyOscillator &oscillator, O op.update(states_[int(modulator)], oscillator, key_on_ || force_key_on, period_ << frequency_shift_, octave_, overrides); } -int Channel::melodic_output(Operator &modulator, Operator &carrier, OperatorOverrides *modulator_overrides, OperatorOverrides *carrier_overrides) { +int Channel::melodic_output(const Operator &modulator, const Operator &carrier, const OperatorOverrides *overrides) const { if(use_fm_synthesis_) { // Get modulator level, use that as a phase-adjusting input to the carrier and then return the carrier level. const LogSign modulator_output = modulator.melodic_output(states_[1]); - return carrier.melodic_output(states_[0], &modulator_output).level(); + return carrier.melodic_output(states_[0], &modulator_output, overrides).level(); } else { // Get modulator and carrier levels separately, return their sum. - return (carrier.melodic_output(states_[0]).level() + modulator.melodic_output(states_[1]).level()) >> 1; + return (carrier.melodic_output(states_[0], nullptr, overrides).level() + modulator.melodic_output(states_[1], nullptr, overrides).level()) >> 1; } } -int Channel::tom_tom_output(Operator &modulator, OperatorOverrides *modulator_overrides) { - return modulator.melodic_output(states_[1]).level(); +int Channel::tom_tom_output(const Operator &modulator, const OperatorOverrides *overrides) const { + return modulator.melodic_output(states_[1], nullptr, overrides).level(); } -int Channel::snare_output(Operator &carrier, OperatorOverrides *carrier_overrides) { - return carrier.snare_output(states_[0]).level(); +int Channel::snare_output(const Operator &carrier, const OperatorOverrides *overrides) const { + return carrier.snare_output(states_[0], overrides).level(); } -int Channel::cymbal_output(Operator &modulator, Operator &carrier, Channel &channel8, OperatorOverrides *modulator_overrides) { - return carrier.cymbal_output(states_[0], channel8.states_[1]).level(); +int Channel::cymbal_output(const Operator &modulator, const Operator &carrier, const Channel &channel8, const OperatorOverrides *overrides) const { + return carrier.cymbal_output(states_[0], channel8.states_[1], overrides).level(); } -int Channel::high_hat_output(Operator &modulator, Operator &carrier, Channel &channel8, OperatorOverrides *modulator_overrides) { - return carrier.high_hat_output(states_[0], channel8.states_[1]).level(); +int Channel::high_hat_output(const Operator &modulator, const Operator &carrier, const Channel &channel8, const OperatorOverrides *overrides) const { + return carrier.high_hat_output(states_[0], channel8.states_[1], overrides).level(); } -bool Channel::is_audible(Operator *carrier, OperatorOverrides *carrier_overrides) { - return carrier->is_audible(states_[0], carrier_overrides); +bool Channel::is_audible(Operator *carrier, OperatorOverrides *overrides) { + return carrier->is_audible(states_[0], overrides); } diff --git a/Components/OPL2/Implementation/Channel.hpp b/Components/OPL2/Implementation/Channel.hpp index 3f21b1498..7872c7b5d 100644 --- a/Components/OPL2/Implementation/Channel.hpp +++ b/Components/OPL2/Implementation/Channel.hpp @@ -43,19 +43,19 @@ class Channel { void update(bool modulator, const LowFrequencyOscillator &oscillator, Operator &op, bool force_key_on = false, OperatorOverrides *overrides = nullptr); /// Gets regular 'melodic' output for this channel, i.e. the output you'd expect from all channels when not in rhythm mode. - int melodic_output(Operator &modulator, Operator &carrier, OperatorOverrides *modulator_overrides = nullptr, OperatorOverrides *carrier_overrides = nullptr); + int melodic_output(const Operator &modulator, const Operator &carrier, const OperatorOverrides *overrides = nullptr) const; /// Generates tom tom output using this channel's modulator. - int tom_tom_output(Operator &modulator, OperatorOverrides *modulator_overrides = nullptr); + int tom_tom_output(const Operator &modulator, const OperatorOverrides *overrides = nullptr) const; /// Generates snare output, using this channel's carrier. - int snare_output(Operator &carrier, OperatorOverrides *carrier_overrides = nullptr); + int snare_output(const Operator &carrier, const OperatorOverrides *overrides = nullptr) const; /// Generates cymbal output, using this channel's modulator and @c channel8 's carrier. - int cymbal_output(Operator &modulator, Operator &carrier, Channel &channel8, OperatorOverrides *modulator_overrides = nullptr); + int cymbal_output(const Operator &modulator, const Operator &carrier, const Channel &channel8, const OperatorOverrides *overrides = nullptr) const; /// Generates cymbal output, using this channel's modulator and @c channel8 's carrier. - int high_hat_output(Operator &modulator, Operator &carrier, Channel &channel8, OperatorOverrides *modulator_overrides = nullptr); + int high_hat_output(const Operator &modulator, const Operator &carrier, const Channel &channel8, const OperatorOverrides *overrides = nullptr) const; /// @returns @c true if this channel is currently producing any audio; @c false otherwise; bool is_audible(Operator *carrier, OperatorOverrides *carrier_overrides = nullptr); diff --git a/Components/OPL2/Implementation/Operator.cpp b/Components/OPL2/Implementation/Operator.cpp index 0c03db714..6e14e538b 100644 --- a/Components/OPL2/Implementation/Operator.cpp +++ b/Components/OPL2/Implementation/Operator.cpp @@ -185,7 +185,7 @@ void Operator::update_phase(OperatorState &state, const LowFrequencyOscillator & state.raw_phase_ += multipliers[frequency_multiple_] * (channel_period + vibrato) << channel_octave; } -int Operator::key_level_scaling(OperatorState &state, int channel_period, int channel_octave) { +int Operator::key_level_scaling(const OperatorState &state, int channel_period, int channel_octave) const { // Calculate key-level scaling. Table is as per p14 of the YM3812 application manual, // converted into a fixed-point scheme. Compare with https://www.smspower.org/Development/RE12 // and apologies for the highly ad hoc indentation. @@ -208,23 +208,22 @@ int Operator::key_level_scaling(OperatorState &state, int channel_period, int ch return (key_level_scales[channel_octave][channel_period >> 6] >> key_level_scale_shifts[key_level_scaling_]) << 7; } -int Operator::attenuation_adsr(OperatorState &state, const LowFrequencyOscillator &oscillator, const OperatorOverrides *overrides) { - int attenuation = 0; +int Operator::adsr_tremolo_attenuation(const OperatorState &state, const LowFrequencyOscillator &oscillator) const { + // Add optional tremolo to the current ADSR attenuation. + return (state.adsr_attenuation_ << 3) + (int(apply_amplitude_modulation_) * oscillator.tremolo << 4); +} - // Combine the ADSR attenuation and overall channel attenuation. +int Operator::fixed_attenuation(const OperatorState &state, const OperatorOverrides *overrides) const { if(overrides) { // Overrides here represent per-channel volume on an OPLL. The bits are defined to represent // attenuations of 24db to 3db; the main envelope generator is stated to have a resolution of // 0.325db (which I've assumed is supposed to say 0.375db). - attenuation += (state.adsr_attenuation_ << 3) + (overrides->attenuation << 7); + return overrides->attenuation << 7; } else { // Overrides here represent per-channel volume on an OPLL. The bits are defined to represent // attenuations of 24db to 0.75db. - attenuation += (state.adsr_attenuation_ << 3) + (attenuation_ << 5); + return attenuation_ << 5; } - - // Add optional tremolo. - return attenuation + (int(apply_amplitude_modulation_) * oscillator.tremolo << 4); } void Operator::update( @@ -237,7 +236,7 @@ void Operator::update( update_adsr(state, oscillator, key_on, channel_period, channel_octave, overrides); update_phase(state, oscillator, channel_period, channel_octave); state.key_level_scaling_ = key_level_scaling(state, channel_period, channel_octave); - state.channel_adsr_attenuation_ = attenuation_adsr(state, oscillator, overrides); + state.adsr_tremolo_attenuation_ = adsr_tremolo_attenuation(state, oscillator); state.lfsr_ = oscillator.lfsr; } @@ -248,7 +247,7 @@ void Operator::update( // A heavy debt is owed to https://github.com/andete/ym2413/blob/master/results/rhythm/rhythm.md regarding // the drum sound generation below. -LogSign Operator::melodic_output(const OperatorState &state, const LogSign *phase_offset) { +LogSign Operator::melodic_output(const OperatorState &state, const LogSign *phase_offset, const OperatorOverrides *overrides) const { // Calculate raw attenuation level. constexpr int waveforms[4][4] = { {1023, 1023, 1023, 1023}, // Sine: don't mask in any quadrant. @@ -261,11 +260,11 @@ LogSign Operator::melodic_output(const OperatorState &state, const LogSign *phas LogSign result = negative_log_sin(phase & waveforms[int(waveform_)][(phase >> 8) & 3]); result += state.key_level_scaling_; - result += state.channel_adsr_attenuation_; + result += state.adsr_tremolo_attenuation_ + fixed_attenuation(state, overrides); return result; } -LogSign Operator::snare_output(const OperatorState &state) { +LogSign Operator::snare_output(const OperatorState &state, const OperatorOverrides *overrides) const { LogSign result; // If noise is 0, output is positive. @@ -276,11 +275,11 @@ LogSign Operator::snare_output(const OperatorState &state) { result = negative_log_sin(sign + (level << 8)); result += state.key_level_scaling_; - result += state.channel_adsr_attenuation_; + result += state.adsr_tremolo_attenuation_ + fixed_attenuation(state, overrides); return result; } -LogSign Operator::cymbal_output(const OperatorState &state, const OperatorState &modulator) { +LogSign Operator::cymbal_output(const OperatorState &state, const OperatorState &modulator, const OperatorOverrides *overrides) const { const int output = ((state.raw_phase_ >> 16) ^ (state.raw_phase_ >> 14)) & ((modulator.raw_phase_ >> 18) ^ (modulator.raw_phase_ >> 13)) & @@ -290,11 +289,11 @@ LogSign Operator::cymbal_output(const OperatorState &state, const OperatorState LogSign result = negative_log_sin(angles[output & 1]); result += state.key_level_scaling_; - result += state.channel_adsr_attenuation_; + result += state.adsr_tremolo_attenuation_ + fixed_attenuation(state, overrides); return result; } -LogSign Operator::high_hat_output(const OperatorState &state, const OperatorState &modulator) { +LogSign Operator::high_hat_output(const OperatorState &state, const OperatorState &modulator, const OperatorOverrides *overrides) const { const int output = ((state.raw_phase_ >> 16) ^ (state.raw_phase_ >> 14)) & ((modulator.raw_phase_ >> 18) ^ (modulator.raw_phase_ >> 13)) & @@ -304,6 +303,6 @@ LogSign Operator::high_hat_output(const OperatorState &state, const OperatorStat LogSign result = negative_log_sin(angles[(output & 1) | (state.lfsr_ << 1)]); result += state.key_level_scaling_; - result += state.channel_adsr_attenuation_; + result += state.adsr_tremolo_attenuation_ + fixed_attenuation(state, overrides); return result; } diff --git a/Components/OPL2/Implementation/Operator.hpp b/Components/OPL2/Implementation/Operator.hpp index 9552d1ab8..aa73c5dcb 100644 --- a/Components/OPL2/Implementation/Operator.hpp +++ b/Components/OPL2/Implementation/Operator.hpp @@ -31,7 +31,7 @@ struct OperatorState { int attack_time_ = 0; int key_level_scaling_; - int channel_adsr_attenuation_; + int adsr_tremolo_attenuation_; int lfsr_; bool last_key_on_ = false; @@ -95,18 +95,18 @@ class Operator { bool is_audible(OperatorState &state, OperatorOverrides *overrides = nullptr); /// Provides ordinary melodic output, optionally with modulation. - LogSign melodic_output(const OperatorState &state, const LogSign *phase_offset = nullptr); + LogSign melodic_output(const OperatorState &state, const LogSign *phase_offset = nullptr, const OperatorOverrides *overrides = nullptr) const; /// Provides snare drum output, which is a function of phase and the captured LFSR level. - LogSign snare_output(const OperatorState &state); + LogSign snare_output(const OperatorState &state, const OperatorOverrides *overrides = nullptr) const; /// Provides cymbal output, which is a function of the phase given by @c state, ordinarily the carrier of channel 8, /// and the phase of @c modulator, which is ordinarily the modulator of channel 7. - LogSign cymbal_output(const OperatorState &state, const OperatorState &modulator); + LogSign cymbal_output(const OperatorState &state, const OperatorState &modulator, const OperatorOverrides *overrides = nullptr) const; /// Provides high-hat output, which is a function of the phase given by @c state, ordinarily the carrier of channel 8, /// and the phase of @c modulator, which is ordinarily the modulator of channel 7. - LogSign high_hat_output(const OperatorState &state, const OperatorState &modulator); + LogSign high_hat_output(const OperatorState &state, const OperatorState &modulator, const OperatorOverrides *overrides = nullptr) const; private: /// If true then an amplitude modulation of "3.7Hz" is applied, @@ -161,10 +161,12 @@ class Operator { void update_phase(OperatorState &state, const LowFrequencyOscillator &oscillator, int channel_period, int channel_octave); /// Adds key-level scaling to the current output state. - int key_level_scaling(OperatorState &state, int channel_period, int channel_octave); + int key_level_scaling(const OperatorState &state, int channel_period, int channel_octave) const; /// Adds ADSR and general channel attenuations to the output state. - int attenuation_adsr(OperatorState &state, const LowFrequencyOscillator &oscillator, const OperatorOverrides *overrides); + int adsr_tremolo_attenuation(const OperatorState &state, const LowFrequencyOscillator &oscillator) const; + + int fixed_attenuation(const OperatorState &state, const OperatorOverrides *overrides) const; }; diff --git a/Components/OPL2/OPL2.cpp b/Components/OPL2/OPL2.cpp index 1d39e2d78..a945a39e5 100644 --- a/Components/OPL2/OPL2.cpp +++ b/Components/OPL2/OPL2.cpp @@ -229,19 +229,19 @@ void OPLL::update_all_chanels() { channels_[8].update(false, oscillator_, operators_[37], bool(depth_rhythm_control_ & 0x02)); // Update channel 6 as if melodic, but with the bass instrument. - output_levels_[2] = output_levels_[15] = VOLUME(channels_[6].melodic_output()); + output_levels_[2] = output_levels_[15] = VOLUME(channels_[6].melodic_output(&rhythm_overrides_[1])); // Use the carrier from channel 7 for the snare. - output_levels_[6] = output_levels_[16] = VOLUME(channels_[7].snare_output(operators_[35])); + output_levels_[6] = output_levels_[16] = VOLUME(channels_[7].snare_output(operators_[35], &rhythm_overrides_[3])); // Use the modulator from channel 8 for the tom tom. - output_levels_[1] = output_levels_[14] = VOLUME(channels_[8].tom_tom_output(operators_[37])); + output_levels_[1] = output_levels_[14] = VOLUME(channels_[8].tom_tom_output(operators_[37], &rhythm_overrides_[4])); // Use the channel 7 modulator and the channel 8 carrier for a cymbal. - output_levels_[7] = output_levels_[17] = VOLUME(channels_[7].cymbal_output(operators_[36], operators_[35], channels_[8])); + output_levels_[7] = output_levels_[17] = VOLUME(channels_[7].cymbal_output(operators_[36], operators_[35], channels_[8], &rhythm_overrides_[5])); // Use the channel 7 modulator and the channel 8 modulator (?) for a high-hat. - output_levels_[0] = output_levels_[13] = VOLUME(channels_[7].high_hat_output(operators_[36], operators_[35], channels_[8])); + output_levels_[0] = output_levels_[13] = VOLUME(channels_[7].high_hat_output(operators_[36], operators_[35], channels_[8], &rhythm_overrides_[2])); } else { // Not in rhythm mode; channels 7, 8 and 9 are melodic. for(int c = 6; c < 9; ++ c) { diff --git a/Components/OPL2/OPL2.hpp b/Components/OPL2/OPL2.hpp index 4b22502be..e9949c73a 100644 --- a/Components/OPL2/OPL2.hpp +++ b/Components/OPL2/OPL2.hpp @@ -104,17 +104,12 @@ struct OPLL: public OPLBase { using ::Yamaha::OPL::Channel::update; int melodic_output() { - return Yamaha::OPL::Channel::melodic_output(modulator[0], modulator[1]); + return Yamaha::OPL::Channel::melodic_output(modulator[0], modulator[1], &overrides); } -// int update_bass(const LowFrequencyOscillator &oscillator, Operator *bass, bool key_on) { -// return Yamaha::OPL::Channel::update_melodic(oscillator, bass, bass + 1, key_on, nullptr, &overrides); -// } -// -// int update_tom_tom(const LowFrequencyOscillator &oscillator, Operator *bass, bool key_on) { -// // TODO: should overrides be applied here? -// return Yamaha::OPL::Channel::update_tom_tom(oscillator, bass, key_on, &overrides); -// } + int melodic_output(const OperatorOverrides *overrides) { + return Yamaha::OPL::Channel::melodic_output(modulator[0], modulator[1], overrides); + } bool is_audible() { return Yamaha::OPL::Channel::is_audible(modulator + 1, &overrides);