summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2021-05-29 02:37:19 -0700
committer Aaron Giles <aaron@aarongiles.com>2021-05-29 02:37:19 -0700
commit04027e4fa75d311d25dad4d80bdd1d680105efda (patch)
treeac1e04a6e2ee8ba2da26e8be7f0a214bf4b25b3d
parent52eee5fd27d142b57e8c158b489e70762e6f2768 (diff)
ymfm: Sync with upstream:
* Match OPN LFO frequencies to hardware measurements * Improve OPQ detune, reverb, and KSR
-rw-r--r--3rdparty/ymfm/src/ymfm.h2
-rw-r--r--3rdparty/ymfm/src/ymfm_fm.h2
-rw-r--r--3rdparty/ymfm/src/ymfm_fm.ipp7
-rw-r--r--3rdparty/ymfm/src/ymfm_opn.cpp7
-rw-r--r--3rdparty/ymfm/src/ymfm_opn.h2
-rw-r--r--3rdparty/ymfm/src/ymfm_opq.cpp44
-rw-r--r--3rdparty/ymfm/src/ymfm_opq.h37
-rw-r--r--3rdparty/ymfm/src/ymfm_opz.h1
8 files changed, 50 insertions, 52 deletions
diff --git a/3rdparty/ymfm/src/ymfm.h b/3rdparty/ymfm/src/ymfm.h
index 93c8dca22f4..cba731d9afa 100644
--- a/3rdparty/ymfm/src/ymfm.h
+++ b/3rdparty/ymfm/src/ymfm.h
@@ -266,7 +266,7 @@ enum envelope_state : uint32_t
EG_DECAY = 2,
EG_SUSTAIN = 3,
EG_RELEASE = 4,
- EG_REVERB = 5, // OPZ only; set EG_HAS_REVERB to enable
+ EG_REVERB = 5, // OPQ/OPZ only; set EG_HAS_REVERB to enable
EG_STATES = 6
};
diff --git a/3rdparty/ymfm/src/ymfm_fm.h b/3rdparty/ymfm/src/ymfm_fm.h
index 79f4c5a7305..c4d4982b8e0 100644
--- a/3rdparty/ymfm/src/ymfm_fm.h
+++ b/3rdparty/ymfm/src/ymfm_fm.h
@@ -110,7 +110,7 @@ public:
// the following constants are uncommon:
// bool DYNAMIC_OPS: True if ops/channel can be changed at runtime (OPL3+)
// bool EG_HAS_DEPRESS: True if the chip has a DP ("depress"?) envelope stage (OPLL)
- // bool EG_HAS_REVERB: True if the chip has a faux reverb envelope stage (OPZ)
+ // bool EG_HAS_REVERB: True if the chip has a faux reverb envelope stage (OPQ/OPZ)
// bool EG_HAS_SSG: True if the chip has SSG envelope support (OPN)
// bool MODULATOR_DELAY: True if the modulator is delayed by 1 sample (OPL pre-OPL3)
//
diff --git a/3rdparty/ymfm/src/ymfm_fm.ipp b/3rdparty/ymfm/src/ymfm_fm.ipp
index 0c51a1528cf..2e04330a40e 100644
--- a/3rdparty/ymfm/src/ymfm_fm.ipp
+++ b/3rdparty/ymfm/src/ymfm_fm.ipp
@@ -706,11 +706,8 @@ void fm_operator<RegisterType>::clock_envelope(uint32_t env_counter)
{
// glitch means that attack rates of 62/63 don't increment if
// changed after the initial key on (where they are handled
- // specially)
-
- // QUESTION: this check affects one of the operators on the gng credit sound
- // is it correct?
- // QUESTION: does this apply only to YM2612?
+ // specially); nukeykt confirms this happens on OPM, OPN, OPL/OPLL
+ // at least so assuming it is true for everyone
if (rate < 62)
m_env_attenuation += (~m_env_attenuation * increment) >> 4;
}
diff --git a/3rdparty/ymfm/src/ymfm_opn.cpp b/3rdparty/ymfm/src/ymfm_opn.cpp
index 00f7da46775..ed410a119ba 100644
--- a/3rdparty/ymfm/src/ymfm_opn.cpp
+++ b/3rdparty/ymfm/src/ymfm_opn.cpp
@@ -207,7 +207,12 @@ int32_t opn_registers_base<IsOpnA>::clock_noise_and_lfo()
// when we cross the divider count, add enough to zero it and cause an
// increment at bit 8; the 7-bit value lives from bits 8-14
if (subcount >= lfo_max_count[lfo_rate()])
- m_lfo_counter += subcount ^ 0xff;
+ {
+ // note: to match the published values this should be 0x100 - subcount;
+ // however, tests on the hardware and nuked bear out an off-by-one
+ // error exists that causes the max LFO rate to be faster than published
+ m_lfo_counter += 0x101 - subcount;
+ }
// AM value is 7 bits, staring at bit 8; grab the low 6 directly
m_lfo_am = bitfield(m_lfo_counter, 8, 6);
diff --git a/3rdparty/ymfm/src/ymfm_opn.h b/3rdparty/ymfm/src/ymfm_opn.h
index a9bb01d9763..31fd895ee7b 100644
--- a/3rdparty/ymfm/src/ymfm_opn.h
+++ b/3rdparty/ymfm/src/ymfm_opn.h
@@ -116,13 +116,11 @@ public:
static constexpr uint32_t CHANNELS = IsOpnA ? 6 : 3;
static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1;
static constexpr uint32_t OPERATORS = CHANNELS * 4;
- static constexpr bool DYNAMIC_OPS = false;
static constexpr uint32_t WAVEFORMS = 1;
static constexpr uint32_t REGISTERS = IsOpnA ? 0x200 : 0x100;
static constexpr uint32_t REG_MODE = 0x27;
static constexpr uint32_t DEFAULT_PRESCALE = 6;
static constexpr uint32_t EG_CLOCK_DIVIDER = 3;
- static constexpr bool EG_HAS_DEPRESS = false;
static constexpr bool EG_HAS_SSG = true;
static constexpr bool MODULATOR_DELAY = false;
static constexpr uint32_t CSM_TRIGGER_MASK = 1 << 2;
diff --git a/3rdparty/ymfm/src/ymfm_opq.cpp b/3rdparty/ymfm/src/ymfm_opq.cpp
index 02d8c35a5a8..493fae26592 100644
--- a/3rdparty/ymfm/src/ymfm_opq.cpp
+++ b/3rdparty/ymfm/src/ymfm_opq.cpp
@@ -31,7 +31,7 @@
#include "ymfm_opq.h"
#include "ymfm_fm.ipp"
-#define TEMPORARY_DEBUG_PRINTS (1)
+#define TEMPORARY_DEBUG_PRINTS (0)
//
// OPQ (aka YM3806/YM3533)
@@ -171,7 +171,7 @@ int32_t opq_registers::clock_noise_and_lfo()
// when we cross the divider count, add enough to zero it and cause an
// increment at bit 8; the 7-bit value lives from bits 8-14
if (subcount >= lfo_max_count[lfo_rate()])
- m_lfo_counter += subcount ^ 0xff;
+ m_lfo_counter += 0x101 - subcount;
// AM value is 7 bits, staring at bit 8; grab the low 6 directly
m_lfo_am = bitfield(m_lfo_counter, 8, 6);
@@ -228,7 +228,7 @@ void opq_registers::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata
cache.waveform = &m_waveform[op_waveform(opoffs)][0];
// get frequency from the appropriate registers
- uint32_t block_freq = cache.block_freq = (opoffs & 1) ? ch_block_freq_24(choffs) : ch_block_freq_13(choffs);
+ uint32_t block_freq = cache.block_freq = (opoffs & 8) ? ch_block_freq_24(choffs) : ch_block_freq_13(choffs);
// compute the keycode: block_freq is:
//
@@ -248,11 +248,16 @@ void opq_registers::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata
// for speed, we just look it up in a 16-bit constant
keycode |= bitfield(0xfe80, bitfield(block_freq, 8, 4));
- // detune adjustment; detune isn't really understood except that it is a
- // 6-bit value where the middle value (0x20) means no detune; range is +/-20 cents
- // this calculation gives a bit more, but shifting by 12 gives a bit less
- // also, the real calculation is probably something to do with keycodes
- cache.detune = ((op_detune(opoffs) - 0x20) * block_freq) >> 11;
+ // detune adjustment: the detune values supported by the OPQ are
+ // a much larger range (6 bits vs 3 bits) compared to any other
+ // known FM chip; based on experiments, it seems that the extra
+ // bits provide a bigger detune range rather than finer control,
+ // so until we get true measurements just assemble a net detune
+ // value by summing smaller detunes
+ int32_t detune = int32_t(op_detune(opoffs)) - 0x20;
+ int32_t abs_detune = std::abs(detune);
+ int32_t adjust = (abs_detune / 3) * detune_adjustment(3, keycode) + detune_adjustment(abs_detune % 3, keycode);
+ cache.detune = (detune >= 0) ? adjust : -adjust;
// multiple value, as an x.1 value (0 means 0.5)
static const uint8_t s_multiple_map[16] = { 1,2,4,6,8,10,12,14,16,18,20,24,30,32,34,36 };
@@ -273,15 +278,13 @@ void opq_registers::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata
cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10;
cache.eg_sustain <<= 5;
- // determine KSR adjustment for enevlope rates; KSR is supposedly 3 bits
- // not 2 like all other implementations, so unsure how this would work.
- // Maybe keycode is a larger range? For now, we'll just take the upper 2
- // bits and use that.
- uint32_t ksrval = keycode >> ((op_ksr(opoffs) >> 1) ^ 3);
+ // determine KSR adjustment for enevlope rates
+ uint32_t ksrval = keycode >> (op_ksr(opoffs) ^ 3);
cache.eg_rate[EG_ATTACK] = effective_rate(op_attack_rate(opoffs) * 2, ksrval);
cache.eg_rate[EG_DECAY] = effective_rate(op_decay_rate(opoffs) * 2, ksrval);
cache.eg_rate[EG_SUSTAIN] = effective_rate(op_sustain_rate(opoffs) * 2, ksrval);
cache.eg_rate[EG_RELEASE] = effective_rate(op_release_rate(opoffs) * 4 + 2, ksrval);
+ cache.eg_rate[EG_REVERB] = (ch_reverb(choffs) != 0) ? 5 : cache.eg_rate[EG_RELEASE];
cache.eg_shift = 0;
}
@@ -310,15 +313,12 @@ uint32_t opq_registers::compute_phase_step(uint32_t choffs, uint32_t opoffs, opd
fnum &= 0xfff;
}
- // this is likely not right, but should given the right approximate result
- fnum += cache.detune;
-
// apply block shift to compute phase step
uint32_t block = bitfield(cache.block_freq, 12, 3);
uint32_t phase_step = (fnum << block) >> 2;
- // apply detune based on the keycode -- this is probably where the real chip does it
-// phase_step += cache.detune;
+ // apply detune based on the keycode
+ phase_step += cache.detune;
// clamp to 17 bits in case detune overflows
// QUESTION: is this specific to the YM2612/3438?
@@ -341,10 +341,10 @@ std::string opq_registers::log_keyon(uint32_t choffs, uint32_t opoffs)
char buffer[256];
char *end = &buffer[0];
- end += sprintf(end, "%d.%02d freq=%04X dt=%d fb=%d alg=%X mul=%X tl=%02X ksr=%d adsr=%02X/%02X/%02X/%X sl=%X out=%c%c",
+ end += sprintf(end, "%d.%02d freq=%04X dt=%+2d fb=%d alg=%X mul=%X tl=%02X ksr=%d adsr=%02X/%02X/%02X/%X sl=%X out=%c%c",
chnum, opnum,
(opoffs & 1) ? ch_block_freq_24(choffs) : ch_block_freq_13(choffs),
- op_detune(opoffs),
+ int32_t(op_detune(opoffs)) - 0x20,
ch_feedback(choffs),
ch_algorithm(choffs),
op_multiple(opoffs),
@@ -366,8 +366,8 @@ std::string opq_registers::log_keyon(uint32_t choffs, uint32_t opoffs)
end += sprintf(end, " pm=%d", ch_lfo_pm_sens(choffs));
if (am || pm)
end += sprintf(end, " lfo=%02X", lfo_rate());
- if (ch_echo(choffs))
- end += sprintf(end, " echo");
+ if (ch_reverb(choffs))
+ end += sprintf(end, " reverb");
return buffer;
}
diff --git a/3rdparty/ymfm/src/ymfm_opq.h b/3rdparty/ymfm/src/ymfm_opq.h
index 10b91266e9d..f530ac070f1 100644
--- a/3rdparty/ymfm/src/ymfm_opq.h
+++ b/3rdparty/ymfm/src/ymfm_opq.h
@@ -63,7 +63,7 @@ namespace ymfm
// -x------ Pan left
// --xxx--- Feedback level for operator 1 (0-7)
// -----xxx Operator connection algorithm (0-7)
-// 18-1F x------- Echo
+// 18-1F x------- Reverb
// -xxx---- PM sensitivity
// ------xx AM shift
// 20-27 -xxx---- Block (0-7), Operator 2 & 4
@@ -77,7 +77,7 @@ namespace ymfm
// 40-5F 0-xxxxxx Detune value (0-63)
// 1---xxxx Multiple value (0-15)
// 60-7F -xxxxxxx Total level (0-127)
-// 80-9F xxx----- Key scale rate (0-7)
+// 80-9F xx------ Key scale rate (0-3)
// ---xxxxx Attack rate (0-31)
// A0-BF x------- LFO AM enable, retrigger disable
// x------ Waveform select
@@ -88,11 +88,10 @@ namespace ymfm
//
// Diffs from OPM:
// - 2 frequencies/channel
-// - KSR is 3 bits?
// - retrigger disable
// - 2 waveforms
// - uses FNUM
-// - echo behavior
+// - reverb behavior
// - larger detune range
//
// Questions:
@@ -108,14 +107,12 @@ public:
static constexpr uint32_t CHANNELS = 8;
static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1;
static constexpr uint32_t OPERATORS = CHANNELS * 4;
- static constexpr bool DYNAMIC_OPS = false;
static constexpr uint32_t WAVEFORMS = 2;
static constexpr uint32_t REGISTERS = 0x120;
static constexpr uint32_t REG_MODE = 0x03;
static constexpr uint32_t DEFAULT_PRESCALE = 2;
static constexpr uint32_t EG_CLOCK_DIVIDER = 3;
- static constexpr bool EG_HAS_DEPRESS = false;
- static constexpr bool EG_HAS_SSG = false;
+ static constexpr bool EG_HAS_REVERB = true;
static constexpr bool MODULATOR_DELAY = false;
static constexpr uint32_t CSM_TRIGGER_MASK = ALL_CHANNELS;
static constexpr uint8_t STATUS_TIMERA = 0;
@@ -175,17 +172,17 @@ public:
std::string log_keyon(uint32_t choffs, uint32_t opoffs);
// system-wide registers
- uint32_t timer_a_value() const { return 0; }
- uint32_t timer_b_value() const { return byte(0x03, 2, 6) | 0xc0; } // ???
- uint32_t csm() const { return 0; }
- uint32_t reset_timer_b() const { return byte(0x03, 0, 1); } // ???
- uint32_t reset_timer_a() const { return 0; }
- uint32_t enable_timer_b() const { return byte(0x03, 0, 1); } // ???
- uint32_t enable_timer_a() const { return 0; }
- uint32_t load_timer_b() const { return byte(0x03, 0, 1); } // ???
- uint32_t load_timer_a() const { return 0; }
- uint32_t lfo_enable() const { return byte(0x04, 3, 1) ^ 1; }
- uint32_t lfo_rate() const { return byte(0x04, 0, 3); }
+ uint32_t timer_a_value() const { return 0; }
+ uint32_t timer_b_value() const { return byte(0x03, 2, 6) | 0xc0; } // ???
+ uint32_t csm() const { return 0; }
+ uint32_t reset_timer_b() const { return byte(0x03, 0, 1); } // ???
+ uint32_t reset_timer_a() const { return 0; }
+ uint32_t enable_timer_b() const { return byte(0x03, 0, 1); } // ???
+ uint32_t enable_timer_a() const { return 0; }
+ uint32_t load_timer_b() const { return byte(0x03, 0, 1); } // ???
+ uint32_t load_timer_a() const { return 0; }
+ uint32_t lfo_enable() const { return byte(0x04, 3, 1) ^ 1; }
+ uint32_t lfo_rate() const { return byte(0x04, 0, 3); }
// per-channel registers
uint32_t ch_output_any(uint32_t choffs) const { return byte(0x10, 6, 2, choffs); }
@@ -195,7 +192,7 @@ public:
uint32_t ch_output_3(uint32_t choffs) const { return 0; }
uint32_t ch_feedback(uint32_t choffs) const { return byte(0x10, 3, 3, choffs); }
uint32_t ch_algorithm(uint32_t choffs) const { return byte(0x10, 0, 3, choffs); }
- uint32_t ch_echo(uint32_t choffs) const { return byte(0x18, 7, 1, choffs); }
+ uint32_t ch_reverb(uint32_t choffs) const { return byte(0x18, 7, 1, choffs); }
uint32_t ch_lfo_pm_sens(uint32_t choffs) const { return byte(0x18, 4, 3, choffs); }
uint32_t ch_lfo_am_sens(uint32_t choffs) const { return byte(0x18, 0, 2, choffs); }
uint32_t ch_block_freq_24(uint32_t choffs) const { return word(0x20, 0, 7, 0x30, 0, 8, choffs); }
@@ -205,7 +202,7 @@ public:
uint32_t op_detune(uint32_t opoffs) const { return byte(0x40, 0, 6, opoffs); }
uint32_t op_multiple(uint32_t opoffs) const { return byte(0x100, 0, 4, opoffs); }
uint32_t op_total_level(uint32_t opoffs) const { return byte(0x60, 0, 7, opoffs); }
- uint32_t op_ksr(uint32_t opoffs) const { return byte(0x80, 5, 3, opoffs); }
+ uint32_t op_ksr(uint32_t opoffs) const { return byte(0x80, 6, 2, opoffs); }
uint32_t op_attack_rate(uint32_t opoffs) const { return byte(0x80, 0, 5, opoffs); }
uint32_t op_lfo_am_enable(uint32_t opoffs) const { return byte(0xa0, 7, 1, opoffs); }
uint32_t op_waveform(uint32_t opoffs) const { return byte(0xa0, 6, 1, opoffs); }
diff --git a/3rdparty/ymfm/src/ymfm_opz.h b/3rdparty/ymfm/src/ymfm_opz.h
index c38dd246ab9..997ba32f9f2 100644
--- a/3rdparty/ymfm/src/ymfm_opz.h
+++ b/3rdparty/ymfm/src/ymfm_opz.h
@@ -138,6 +138,7 @@ public:
static constexpr uint32_t REGISTERS = 0x190;
static constexpr uint32_t DEFAULT_PRESCALE = 2;
static constexpr uint32_t EG_CLOCK_DIVIDER = 3;
+ static constexpr bool EG_HAS_REVERB = true;
static constexpr uint32_t CSM_TRIGGER_MASK = ALL_CHANNELS;
static constexpr uint32_t REG_MODE = 0x14;
static constexpr uint8_t STATUS_TIMERA = 0x01;