mirror of
https://github.com/holub/mame
synced 2025-06-06 21:03:47 +03:00
ymfm: Sync with upstream:
* Match OPN LFO frequencies to hardware measurements * Improve OPQ detune, reverb, and KSR
This commit is contained in:
parent
52eee5fd27
commit
04027e4fa7
2
3rdparty/ymfm/src/ymfm.h
vendored
2
3rdparty/ymfm/src/ymfm.h
vendored
@ -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
|
||||
};
|
||||
|
||||
|
2
3rdparty/ymfm/src/ymfm_fm.h
vendored
2
3rdparty/ymfm/src/ymfm_fm.h
vendored
@ -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)
|
||||
//
|
||||
|
7
3rdparty/ymfm/src/ymfm_fm.ipp
vendored
7
3rdparty/ymfm/src/ymfm_fm.ipp
vendored
@ -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;
|
||||
}
|
||||
|
7
3rdparty/ymfm/src/ymfm_opn.cpp
vendored
7
3rdparty/ymfm/src/ymfm_opn.cpp
vendored
@ -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);
|
||||
|
2
3rdparty/ymfm/src/ymfm_opn.h
vendored
2
3rdparty/ymfm/src/ymfm_opn.h
vendored
@ -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;
|
||||
|
44
3rdparty/ymfm/src/ymfm_opq.cpp
vendored
44
3rdparty/ymfm/src/ymfm_opq.cpp
vendored
@ -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;
|
||||
}
|
||||
|
15
3rdparty/ymfm/src/ymfm_opq.h
vendored
15
3rdparty/ymfm/src/ymfm_opq.h
vendored
@ -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;
|
||||
@ -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); }
|
||||
|
1
3rdparty/ymfm/src/ymfm_opz.h
vendored
1
3rdparty/ymfm/src/ymfm_opz.h
vendored
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user