1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00

Feeds through drum volume levels.

This commit is contained in:
Thomas Harte 2020-04-30 19:35:09 -04:00
parent 7fffafdfd4
commit e4ef2c68bb
6 changed files with 53 additions and 57 deletions

View File

@ -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); 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_) { if(use_fm_synthesis_) {
// Get modulator level, use that as a phase-adjusting input to the carrier and then return the carrier level. // 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]); 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 { } else {
// Get modulator and carrier levels separately, return their sum. // 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) { int Channel::tom_tom_output(const Operator &modulator, const OperatorOverrides *overrides) const {
return modulator.melodic_output(states_[1]).level(); return modulator.melodic_output(states_[1], nullptr, overrides).level();
} }
int Channel::snare_output(Operator &carrier, OperatorOverrides *carrier_overrides) { int Channel::snare_output(const Operator &carrier, const OperatorOverrides *overrides) const {
return carrier.snare_output(states_[0]).level(); return carrier.snare_output(states_[0], overrides).level();
} }
int Channel::cymbal_output(Operator &modulator, Operator &carrier, Channel &channel8, OperatorOverrides *modulator_overrides) { 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]).level(); 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) { 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]).level(); return carrier.high_hat_output(states_[0], channel8.states_[1], overrides).level();
} }
bool Channel::is_audible(Operator *carrier, OperatorOverrides *carrier_overrides) { bool Channel::is_audible(Operator *carrier, OperatorOverrides *overrides) {
return carrier->is_audible(states_[0], carrier_overrides); return carrier->is_audible(states_[0], overrides);
} }

View File

@ -43,19 +43,19 @@ class Channel {
void update(bool modulator, const LowFrequencyOscillator &oscillator, Operator &op, bool force_key_on = false, OperatorOverrides *overrides = nullptr); 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. /// 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. /// 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. /// 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. /// 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. /// 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; /// @returns @c true if this channel is currently producing any audio; @c false otherwise;
bool is_audible(Operator *carrier, OperatorOverrides *carrier_overrides = nullptr); bool is_audible(Operator *carrier, OperatorOverrides *carrier_overrides = nullptr);

View File

@ -185,7 +185,7 @@ void Operator::update_phase(OperatorState &state, const LowFrequencyOscillator &
state.raw_phase_ += multipliers[frequency_multiple_] * (channel_period + vibrato) << channel_octave; 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, // 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 // converted into a fixed-point scheme. Compare with https://www.smspower.org/Development/RE12
// and apologies for the highly ad hoc indentation. // 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; 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 Operator::adsr_tremolo_attenuation(const OperatorState &state, const LowFrequencyOscillator &oscillator) const {
int attenuation = 0; // 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) { if(overrides) {
// Overrides here represent per-channel volume on an OPLL. The bits are defined to represent // 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 // 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). // 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 { } else {
// Overrides here represent per-channel volume on an OPLL. The bits are defined to represent // Overrides here represent per-channel volume on an OPLL. The bits are defined to represent
// attenuations of 24db to 0.75db. // 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( void Operator::update(
@ -237,7 +236,7 @@ void Operator::update(
update_adsr(state, oscillator, key_on, channel_period, channel_octave, overrides); update_adsr(state, oscillator, key_on, channel_period, channel_octave, overrides);
update_phase(state, oscillator, channel_period, channel_octave); update_phase(state, oscillator, channel_period, channel_octave);
state.key_level_scaling_ = key_level_scaling(state, 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; 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 // A heavy debt is owed to https://github.com/andete/ym2413/blob/master/results/rhythm/rhythm.md regarding
// the drum sound generation below. // 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. // Calculate raw attenuation level.
constexpr int waveforms[4][4] = { constexpr int waveforms[4][4] = {
{1023, 1023, 1023, 1023}, // Sine: don't mask in any quadrant. {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]); LogSign result = negative_log_sin(phase & waveforms[int(waveform_)][(phase >> 8) & 3]);
result += state.key_level_scaling_; result += state.key_level_scaling_;
result += state.channel_adsr_attenuation_; result += state.adsr_tremolo_attenuation_ + fixed_attenuation(state, overrides);
return result; return result;
} }
LogSign Operator::snare_output(const OperatorState &state) { LogSign Operator::snare_output(const OperatorState &state, const OperatorOverrides *overrides) const {
LogSign result; LogSign result;
// If noise is 0, output is positive. // 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 = negative_log_sin(sign + (level << 8));
result += state.key_level_scaling_; result += state.key_level_scaling_;
result += state.channel_adsr_attenuation_; result += state.adsr_tremolo_attenuation_ + fixed_attenuation(state, overrides);
return result; 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 = const int output =
((state.raw_phase_ >> 16) ^ (state.raw_phase_ >> 14)) & ((state.raw_phase_ >> 16) ^ (state.raw_phase_ >> 14)) &
((modulator.raw_phase_ >> 18) ^ (modulator.raw_phase_ >> 13)) & ((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]); LogSign result = negative_log_sin(angles[output & 1]);
result += state.key_level_scaling_; result += state.key_level_scaling_;
result += state.channel_adsr_attenuation_; result += state.adsr_tremolo_attenuation_ + fixed_attenuation(state, overrides);
return result; 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 = const int output =
((state.raw_phase_ >> 16) ^ (state.raw_phase_ >> 14)) & ((state.raw_phase_ >> 16) ^ (state.raw_phase_ >> 14)) &
((modulator.raw_phase_ >> 18) ^ (modulator.raw_phase_ >> 13)) & ((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)]); LogSign result = negative_log_sin(angles[(output & 1) | (state.lfsr_ << 1)]);
result += state.key_level_scaling_; result += state.key_level_scaling_;
result += state.channel_adsr_attenuation_; result += state.adsr_tremolo_attenuation_ + fixed_attenuation(state, overrides);
return result; return result;
} }

View File

@ -31,7 +31,7 @@ struct OperatorState {
int attack_time_ = 0; int attack_time_ = 0;
int key_level_scaling_; int key_level_scaling_;
int channel_adsr_attenuation_; int adsr_tremolo_attenuation_;
int lfsr_; int lfsr_;
bool last_key_on_ = false; bool last_key_on_ = false;
@ -95,18 +95,18 @@ class Operator {
bool is_audible(OperatorState &state, OperatorOverrides *overrides = nullptr); bool is_audible(OperatorState &state, OperatorOverrides *overrides = nullptr);
/// Provides ordinary melodic output, optionally with modulation. /// 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. /// 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, /// 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. /// 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, /// 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. /// 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: private:
/// If true then an amplitude modulation of "3.7Hz" is applied, /// 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); void update_phase(OperatorState &state, const LowFrequencyOscillator &oscillator, int channel_period, int channel_octave);
/// Adds key-level scaling to the current output state. /// 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. /// 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;
}; };

View File

@ -229,19 +229,19 @@ void OPLL::update_all_chanels() {
channels_[8].update(false, oscillator_, operators_[37], bool(depth_rhythm_control_ & 0x02)); channels_[8].update(false, oscillator_, operators_[37], bool(depth_rhythm_control_ & 0x02));
// Update channel 6 as if melodic, but with the bass instrument. // 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. // 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. // 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. // 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. // 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 { } else {
// Not in rhythm mode; channels 7, 8 and 9 are melodic. // Not in rhythm mode; channels 7, 8 and 9 are melodic.
for(int c = 6; c < 9; ++ c) { for(int c = 6; c < 9; ++ c) {

View File

@ -104,17 +104,12 @@ struct OPLL: public OPLBase<OPLL> {
using ::Yamaha::OPL::Channel::update; using ::Yamaha::OPL::Channel::update;
int melodic_output() { 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) { int melodic_output(const OperatorOverrides *overrides) {
// return Yamaha::OPL::Channel::update_melodic(oscillator, bass, bass + 1, key_on, nullptr, &overrides); return Yamaha::OPL::Channel::melodic_output(modulator[0], modulator[1], 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);
// }
bool is_audible() { bool is_audible() {
return Yamaha::OPL::Channel::is_audible(modulator + 1, &overrides); return Yamaha::OPL::Channel::is_audible(modulator + 1, &overrides);