mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-22 12:33:29 +00:00
Continues factoring this apart, albeit with a decision on whether to retain update-and-output still pending.
This commit is contained in:
parent
f52b40396a
commit
a424e867f9
@ -74,12 +74,11 @@ void Operator::update_adsr(
|
|||||||
if(!key_on) {
|
if(!key_on) {
|
||||||
state.adsr_phase_ = OperatorState::ADSRPhase::Release;
|
state.adsr_phase_ = OperatorState::ADSRPhase::Release;
|
||||||
} else if(!state.last_key_on_) {
|
} else if(!state.last_key_on_) {
|
||||||
// printf("---\n");
|
|
||||||
state.adsr_phase_ = OperatorState::ADSRPhase::Attack;
|
state.adsr_phase_ = OperatorState::ADSRPhase::Attack;
|
||||||
state.attack_time_ = 0;
|
state.attack_time_ = 0;
|
||||||
|
|
||||||
// TODO: should this happen only if current ADSR attenuation is 511?
|
// TODO: should this happen only if current ADSR attenuation is 511?
|
||||||
// state.raw_phase_ = 0;
|
state.raw_phase_ = 0;
|
||||||
}
|
}
|
||||||
state.last_key_on_ = key_on;
|
state.last_key_on_ = key_on;
|
||||||
|
|
||||||
@ -166,55 +165,9 @@ void Operator::update_adsr(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++state.attack_time_;
|
++state.attack_time_;
|
||||||
|
|
||||||
// if(key_on) {
|
|
||||||
// printf("%d\n", state.adsr_attenuation_);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Operator::update(
|
void Operator::apply_key_level_scaling(OperatorState &state, int channel_period, int channel_octave) {
|
||||||
OperatorState &state,
|
|
||||||
const OperatorState *phase_offset,
|
|
||||||
const LowFrequencyOscillator &oscillator,
|
|
||||||
bool key_on,
|
|
||||||
int channel_period,
|
|
||||||
int channel_octave,
|
|
||||||
const OperatorOverrides *overrides) {
|
|
||||||
state.attenuation.reset();
|
|
||||||
update_adsr(state, oscillator, key_on, channel_period, channel_octave, overrides);
|
|
||||||
|
|
||||||
// Per the documentation:
|
|
||||||
//
|
|
||||||
// Delta phase = ( [desired freq] * 2^19 / [input clock / 72] ) / 2 ^ (b - 1)
|
|
||||||
//
|
|
||||||
// After experimentation, I think this gives rate calculation as formulated below.
|
|
||||||
|
|
||||||
// This encodes the MUL -> multiple table given on page 12,
|
|
||||||
// multiplied by two.
|
|
||||||
constexpr int multipliers[] = {
|
|
||||||
1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30
|
|
||||||
};
|
|
||||||
const int top_freq = channel_period >> 7;
|
|
||||||
assert(top_freq < 8);
|
|
||||||
constexpr int vibrato_shifts[8] = {3, 1, 0, 1, 3, 1, 0, 1};
|
|
||||||
constexpr int vibrato_signs[2] = {1, -1};
|
|
||||||
const int vibrato = (top_freq >> vibrato_shifts[oscillator.vibrato]) * vibrato_signs[oscillator.vibrato >> 2] * int(apply_vibrato_);
|
|
||||||
|
|
||||||
// Update the raw phase.
|
|
||||||
state.raw_phase_ += multipliers[frequency_multiple_] * (channel_period + vibrato) << channel_octave;
|
|
||||||
|
|
||||||
// Hence calculate phase.
|
|
||||||
constexpr int waveforms[4][4] = {
|
|
||||||
{1023, 1023, 1023, 1023}, // Sine: don't mask in any quadrant.
|
|
||||||
{511, 511, 0, 0}, // Half sine: keep the first half intact, lock to 0 in the second half.
|
|
||||||
{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 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]);
|
|
||||||
|
|
||||||
|
|
||||||
// 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.
|
||||||
@ -235,7 +188,9 @@ void Operator::update(
|
|||||||
assert((channel_period >> 6) < 16);
|
assert((channel_period >> 6) < 16);
|
||||||
assert(channel_octave < 8);
|
assert(channel_octave < 8);
|
||||||
state.attenuation += (key_level_scales[channel_octave][channel_period >> 6] >> key_level_scale_shifts[key_level_scaling_]) << 7;
|
state.attenuation += (key_level_scales[channel_octave][channel_period >> 6] >> key_level_scale_shifts[key_level_scaling_]) << 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Operator::apply_attenuation_adsr(OperatorState &state, const LowFrequencyOscillator &oscillator, const OperatorOverrides *overrides) {
|
||||||
// Combine the ADSR attenuation and overall channel attenuation.
|
// Combine the ADSR attenuation and overall channel attenuation.
|
||||||
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
|
||||||
@ -252,4 +207,52 @@ void Operator::update(
|
|||||||
state.attenuation += int(apply_amplitude_modulation_) * oscillator.tremolo << 4;
|
state.attenuation += int(apply_amplitude_modulation_) * oscillator.tremolo << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Operator::update_phase(OperatorState &state, const LowFrequencyOscillator &oscillator, int channel_period, int channel_octave) {
|
||||||
|
// Per the documentation:
|
||||||
|
//
|
||||||
|
// Delta phase = ( [desired freq] * 2^19 / [input clock / 72] ) / 2 ^ (b - 1)
|
||||||
|
//
|
||||||
|
// After experimentation, I think this gives rate calculation as formulated below.
|
||||||
|
|
||||||
|
// This encodes the MUL -> multiple table given on page 12,
|
||||||
|
// multiplied by two.
|
||||||
|
constexpr int multipliers[] = {
|
||||||
|
1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30
|
||||||
|
};
|
||||||
|
const int top_freq = channel_period >> 7;
|
||||||
|
assert(top_freq < 8);
|
||||||
|
constexpr int vibrato_shifts[8] = {3, 1, 0, 1, 3, 1, 0, 1};
|
||||||
|
constexpr int vibrato_signs[2] = {1, -1};
|
||||||
|
const int vibrato = (top_freq >> vibrato_shifts[oscillator.vibrato]) * vibrato_signs[oscillator.vibrato >> 2] * int(apply_vibrato_);
|
||||||
|
|
||||||
|
// Update the raw phase.
|
||||||
|
state.raw_phase_ += multipliers[frequency_multiple_] * (channel_period + vibrato) << channel_octave;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Operator::update(
|
||||||
|
OperatorState &state,
|
||||||
|
const OperatorState *phase_offset,
|
||||||
|
const LowFrequencyOscillator &oscillator,
|
||||||
|
bool key_on,
|
||||||
|
int channel_period,
|
||||||
|
int channel_octave,
|
||||||
|
const OperatorOverrides *overrides) {
|
||||||
|
update_adsr(state, oscillator, key_on, channel_period, channel_octave, overrides);
|
||||||
|
update_phase(state, oscillator, channel_period, channel_octave);
|
||||||
|
|
||||||
|
// Calculate raw attenuation level.
|
||||||
|
constexpr int waveforms[4][4] = {
|
||||||
|
{1023, 1023, 1023, 1023}, // Sine: don't mask in any quadrant.
|
||||||
|
{511, 511, 0, 0}, // Half sine: keep the first half intact, lock to 0 in the second half.
|
||||||
|
{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 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]);
|
||||||
|
|
||||||
|
apply_key_level_scaling(state, channel_period, channel_octave);
|
||||||
|
apply_attenuation_adsr(state, oscillator, overrides);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: both the tremolo and ADSR envelopes should be half-resolution on an OPLL.
|
// TODO: both the tremolo and ADSR envelopes should be half-resolution on an OPLL.
|
||||||
|
@ -136,13 +136,24 @@ class Operator {
|
|||||||
Sine, HalfSine, AbsSine, PulseSine
|
Sine, HalfSine, AbsSine, PulseSine
|
||||||
} waveform_ = Waveform::Sine;
|
} waveform_ = Waveform::Sine;
|
||||||
|
|
||||||
void update_adsr(
|
/// Updates the ADSR envelope.
|
||||||
|
void update_adsr(
|
||||||
OperatorState &state,
|
OperatorState &state,
|
||||||
const LowFrequencyOscillator &oscillator,
|
const LowFrequencyOscillator &oscillator,
|
||||||
bool key_on,
|
bool key_on,
|
||||||
int channel_period,
|
int channel_period,
|
||||||
int channel_octave,
|
int channel_octave,
|
||||||
const OperatorOverrides *overrides);
|
const OperatorOverrides *overrides);
|
||||||
|
|
||||||
|
/// Updates the phase generator.
|
||||||
|
void update_phase(OperatorState &state, const LowFrequencyOscillator &oscillator, int channel_period, int channel_octave);
|
||||||
|
|
||||||
|
/// Adds key-level scaling to the current output state.
|
||||||
|
void apply_key_level_scaling(OperatorState &state, int channel_period, int channel_octave);
|
||||||
|
|
||||||
|
/// Adds ADSR and general channel attenuations to the output state.
|
||||||
|
void apply_attenuation_adsr(OperatorState &state, const LowFrequencyOscillator &oscillator, const OperatorOverrides *overrides);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user