1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-02 20:30:00 +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);
}
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);
}

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);
/// 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);

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;
}
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;
}

View File

@ -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;
};

View File

@ -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) {

View File

@ -104,17 +104,12 @@ struct OPLL: public OPLBase<OPLL> {
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);