diff options
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 |
commit | 04027e4fa75d311d25dad4d80bdd1d680105efda (patch) | |
tree | ac1e04a6e2ee8ba2da26e8be7f0a214bf4b25b3d | |
parent | 52eee5fd27d142b57e8c158b489e70762e6f2768 (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.h | 2 | ||||
-rw-r--r-- | 3rdparty/ymfm/src/ymfm_fm.h | 2 | ||||
-rw-r--r-- | 3rdparty/ymfm/src/ymfm_fm.ipp | 7 | ||||
-rw-r--r-- | 3rdparty/ymfm/src/ymfm_opn.cpp | 7 | ||||
-rw-r--r-- | 3rdparty/ymfm/src/ymfm_opn.h | 2 | ||||
-rw-r--r-- | 3rdparty/ymfm/src/ymfm_opq.cpp | 44 | ||||
-rw-r--r-- | 3rdparty/ymfm/src/ymfm_opq.h | 37 | ||||
-rw-r--r-- | 3rdparty/ymfm/src/ymfm_opz.h | 1 |
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; |