summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2021-04-21 09:10:29 -0700
committer Aaron Giles <aaron@aarongiles.com>2021-04-21 09:10:29 -0700
commit987a9af492e2beba9107a3c17e3468a49f984141 (patch)
treef3b93f4de63c0bbc1f826e10ba3b507aaa2f6cae
parentb13e15fbfda231df67796c1597a36433fefac042 (diff)
Clean up delay implementation a bit. Move delay setting to immediately after operator 2. Re-add early out code after operator 2 is computed. Removed const on channel outputs so we can get rid of mutable. Set feedback on rhythm channels for consistency.ymfm-delay
-rw-r--r--src/devices/sound/ymfm.cpp41
-rw-r--r--src/devices/sound/ymfm.h14
2 files changed, 32 insertions, 23 deletions
diff --git a/src/devices/sound/ymfm.cpp b/src/devices/sound/ymfm.cpp
index 2ab497776d6..c4f2bfa085e 100644
--- a/src/devices/sound/ymfm.cpp
+++ b/src/devices/sound/ymfm.cpp
@@ -2622,7 +2622,7 @@ void ymfm_channel<RegisterType>::clock(u32 env_counter, s32 lfo_raw_pm)
//-------------------------------------------------
template<class RegisterType>
-void ymfm_channel<RegisterType>::output_2op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
+void ymfm_channel<RegisterType>::output_2op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax)
{
// The first 2 operators should be populated
assert(m_op[0] != nullptr);
@@ -2676,7 +2676,7 @@ void ymfm_channel<RegisterType>::output_2op(s32 outputs[RegisterType::OUTPUTS],
//-------------------------------------------------
template<class RegisterType>
-void ymfm_channel<RegisterType>::output_4op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
+void ymfm_channel<RegisterType>::output_4op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax)
{
// all 4 operators should be populated
assert(m_op[0] != nullptr);
@@ -2728,15 +2728,18 @@ void ymfm_channel<RegisterType>::output_4op(s32 outputs[RegisterType::OUTPUTS],
(op2in | (op3in << 1) | (op4in << 4) | (delay << 7) | (op1out << 10) | (op2out << 11) | (op3out << 12))
static u16 const s_algorithm_ops[8+4] =
{
- ALGORITHM(1,4,3, 2, 0,0,0), // 0: O1 -> O2 -> (delay) -> O3 -> O4 -> out (O4)
- ALGORITHM(0,4,3, 5, 0,0,0), // 1: (O1 + O2) -> (delay) -> O3 -> O4 -> out (O4)
- ALGORITHM(0,4,6, 2, 0,0,0), // 2: (O1 + (O2 -> (delay) -> O3)) -> O4 -> out (O4)
- ALGORITHM(1,0,7, 2, 0,0,0), // 3: ((O1 -> O2 -> (delay)) + O3) -> O4 -> out (O4)
+ // OPM/OPN algorithms
+ ALGORITHM(1,4,3, 2, 0,0,0), // 0: O1 -> O2 -> delay -> O3 -> O4 -> out (O4)
+ ALGORITHM(0,4,3, 5, 0,0,0), // 1: (O1 + O2) -> delay -> O3 -> O4 -> out (O4)
+ ALGORITHM(0,4,6, 2, 0,0,0), // 2: (O1 + (O2 -> delay -> O3)) -> O4 -> out (O4)
+ ALGORITHM(1,0,7, 2, 0,0,0), // 3: ((O1 -> O2 -> delay) + O3) -> O4 -> out (O4)
ALGORITHM(1,0,3, 0, 0,1,0), // 4: ((O1 -> O2) + (O3 -> O4)) -> out (O2+O4)
- ALGORITHM(1,4,1, 1, 0,1,1), // 5: ((O1 -> O2) + (O1 -> (delay) -> O3) + (O1 -> O4)) -> out (O2+O3+O4)
+ ALGORITHM(1,4,1, 1, 0,1,1), // 5: ((O1 -> O2) + (O1 -> delay -> O3) + (O1 -> O4)) -> out (O2+O3+O4)
ALGORITHM(1,0,0, 0, 0,1,1), // 6: ((O1 -> O2) + O3 + O4) -> out (O2+O3+O4)
ALGORITHM(0,0,0, 0, 1,1,1), // 7: (O1 + O2 + O3 + O4) -> out (O1+O2+O3+O4)
- ALGORITHM(1,2,3, 0, 0,0,0), // 8: O1 -> O2 -> O3 -> O4 -> out (O4) [same as 0]
+
+ // OPL3+ algorithms
+ ALGORITHM(1,2,3, 0, 0,0,0), // 8: O1 -> O2 -> O3 -> O4 -> out (O4) [same as 0, but no delay]
ALGORITHM(0,2,3, 0, 1,0,0), // 9: (O1 + (O2 -> O3 -> O4)) -> out (O1+O4) [unique]
ALGORITHM(1,0,3, 0, 0,1,0), // 10: ((O1 -> O2) + (O3 -> O4)) -> out (O2+O4) [same as 4]
ALGORITHM(0,2,0, 0, 1,0,1) // 11: (O1 + (O2 -> O3) + O4) -> out (O1+O3+O4) [unique]
@@ -2754,6 +2757,15 @@ void ymfm_channel<RegisterType>::output_4op(s32 outputs[RegisterType::OUTPUTS],
opout[2] = m_op[1]->compute_volume(m_op[1]->phase() + opmod, am_offset);
opout[5] = opout[1] + opout[2];
+ // set the delay value for the next sample; delay only depends on the output
+ // of operators 1 or 2 (or their sum)
+ m_delay_in = opout[BIT(algorithm_ops, 7, 3)];
+
+ // now that both feedback and delay have been computed, skip the rest if all
+ // volumes are clear; no need to do all this work for nothing
+ if (m_regs.ch_output_any(m_choffs) == 0)
+ return;
+
// compute the 14-bit volume/value of operator 3
opmod = opout[BIT(algorithm_ops, 1, 3)] >> 1;
opout[3] = m_op[2]->compute_volume(m_op[2]->phase() + opmod, am_offset);
@@ -2772,9 +2784,6 @@ void ymfm_channel<RegisterType>::output_4op(s32 outputs[RegisterType::OUTPUTS],
}
result >>= rshift;
- // set the delay value for the next sample
- m_delay_in = opout[BIT(algorithm_ops, 7, 3)];
-
// optionally add OP1, OP2, OP3
s32 clipmin = -clipmax - 1;
if (BIT(algorithm_ops, 10) != 0)
@@ -2796,7 +2805,7 @@ void ymfm_channel<RegisterType>::output_4op(s32 outputs[RegisterType::OUTPUTS],
//-------------------------------------------------
template<class RegisterType>
-void ymfm_channel<RegisterType>::output_rhythm_ch6(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
+void ymfm_channel<RegisterType>::output_rhythm_ch6(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax)
{
// AM amount is the same across all operators; compute it once
u32 am_offset = m_regs.lfo_am_offset(m_choffs);
@@ -2831,7 +2840,7 @@ void ymfm_channel<RegisterType>::output_rhythm_ch6(s32 outputs[RegisterType::OUT
//-------------------------------------------------
template<class RegisterType>
-void ymfm_channel<RegisterType>::output_rhythm_ch7(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
+void ymfm_channel<RegisterType>::output_rhythm_ch7(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax)
{
// AM amount is the same across all operators; compute it once
u32 am_offset = m_regs.lfo_am_offset(m_choffs);
@@ -2841,7 +2850,7 @@ void ymfm_channel<RegisterType>::output_rhythm_ch7(u32 phase_select, s32 outputs
// and a combination of noise and the operator 13/17 phase select
// to compute the phase
u32 phase = (phase_select << 9) | (0xd0 >> (2 * (noise_state ^ phase_select)));
- s32 result = m_op[0]->compute_volume(phase, am_offset) >> rshift;
+ s32 result = m_feedback_in = m_op[0]->compute_volume(phase, am_offset) >> rshift;
// Snare Drum: this uses the envelope from operator 16 (channel 7),
// and a combination of noise and operator 13 phase to pick a phase
@@ -2862,13 +2871,13 @@ void ymfm_channel<RegisterType>::output_rhythm_ch7(u32 phase_select, s32 outputs
//-------------------------------------------------
template<class RegisterType>
-void ymfm_channel<RegisterType>::output_rhythm_ch8(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const
+void ymfm_channel<RegisterType>::output_rhythm_ch8(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax)
{
// AM amount is the same across all operators; compute it once
u32 am_offset = m_regs.lfo_am_offset(m_choffs);
// Tom Tom: this is just a single operator processed normally
- s32 result = m_op[0]->compute_volume(m_op[0]->phase(), am_offset) >> rshift;
+ s32 result = m_feedback_in = m_op[0]->compute_volume(m_op[0]->phase(), am_offset) >> rshift;
// Top Cymbal: this uses the envelope from operator 17 (channel 8),
// and the operator 13/17 phase select to compute the phase
diff --git a/src/devices/sound/ymfm.h b/src/devices/sound/ymfm.h
index 9d898775d55..86f916c7f81 100644
--- a/src/devices/sound/ymfm.h
+++ b/src/devices/sound/ymfm.h
@@ -1209,13 +1209,13 @@ public:
void clock(u32 env_counter, s32 lfo_raw_pm);
// specific 2-operator and 4-operator output handlers
- void output_2op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const;
- void output_4op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const;
+ void output_2op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax);
+ void output_4op(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax);
// compute the special OPL rhythm channel outputs
- void output_rhythm_ch6(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const;
- void output_rhythm_ch7(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const;
- void output_rhythm_ch8(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax) const;
+ void output_rhythm_ch6(s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax);
+ void output_rhythm_ch7(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax);
+ void output_rhythm_ch8(u32 phase_select, s32 outputs[RegisterType::OUTPUTS], u32 rshift, s32 clipmax);
// are we a 4-operator channel or a 2-operator one?
bool is4op() const
@@ -1245,8 +1245,8 @@ private:
// internal state
u32 m_choffs; // channel offset in registers
s16 m_feedback[2]; // feedback memory for operator 1
- mutable s16 m_feedback_in; // next input value for op 1 feedback (set in output)
- mutable s16 m_delay_in; // next delay value (set in output)
+ s16 m_feedback_in; // next input value for op 1 feedback (set in output)
+ s16 m_delay_in; // next delay value (set in output)
ymfm_operator<RegisterType> *m_op[4]; // up to 4 operators
RegisterType &m_regs; // direct reference to registers
ymfm_engine_base<RegisterType> &m_owner; // reference to the owning engine