diff --git a/src/devices/sound/ymfm.cpp b/src/devices/sound/ymfm.cpp index 35fff69c3a0..2931b62ebbe 100644 --- a/src/devices/sound/ymfm.cpp +++ b/src/devices/sound/ymfm.cpp @@ -4,7 +4,7 @@ #include "emu.h" #include "ymfm.h" -//#define VERBOSE 1 +#define VERBOSE 1 #define LOG_OUTPUT_FUNC osd_printf_verbose #include "logmacro.h" @@ -640,31 +640,34 @@ void ymfm_operator::start_attack(u8 keycode) if (effective_rate(m_regs.attack_rate(), keycode) >= 62) m_env_attenuation = 0; - // log keys - LOG("KeyOn %d.%d: freq=%04X dt2=%d fb=%d alg=%d dt=%d mul=%X tl=%02X ksr=%d adsr=%02X/%02X/%02X/%X sl=%X pan=%c%c", - m_regs.chnum(), m_regs.opnum(), - m_regs.block_freq(), - m_regs.detune2(), - m_regs.feedback(), - m_regs.algorithm(), - m_regs.detune(), - m_regs.multiple(), - m_regs.total_level(), - m_regs.ksr(), - m_regs.attack_rate(), - m_regs.decay_rate(), - m_regs.sustain_rate(), - m_regs.release_rate(), - m_regs.sustain_level(), - m_regs.pan_left() ? 'L' : '-', - m_regs.pan_right() ? 'R' : '-'); - if (m_regs.ssg_eg_enabled()) - LOG(" ssg=%X", m_regs.ssg_eg_mode()); - if (m_regs.lfo_enabled() && ((m_regs.lfo_am_enabled() && m_regs.lfo_am_sensitivity() != 0) || m_regs.lfo_pm_sensitivity() != 0)) - LOG(" am=%d pm=%d w=%d", m_regs.lfo_am_enabled() ? m_regs.lfo_am_sensitivity() : 0, m_regs.lfo_pm_sensitivity(), m_regs.lfo_waveform()); - if (m_regs.noise_enabled() && m_regs.opnum() == 3 && m_regs.chnum() == 7) - LOG(" noise=1"); - LOG("\n"); + // log key on events under certain conditions + if (m_regs.lfo_waveform() == 3 && m_regs.lfo_enabled() && ((m_regs.lfo_am_enabled() && m_regs.lfo_am_sensitivity() != 0) || m_regs.lfo_pm_sensitivity() != 0)) + { + LOG("KeyOn %d.%d: freq=%04X dt2=%d fb=%d alg=%d dt=%d mul=%X tl=%02X ksr=%d adsr=%02X/%02X/%02X/%X sl=%X pan=%c%c", + m_regs.chnum(), m_regs.opnum(), + m_regs.block_freq(), + m_regs.detune2(), + m_regs.feedback(), + m_regs.algorithm(), + m_regs.detune(), + m_regs.multiple(), + m_regs.total_level(), + m_regs.ksr(), + m_regs.attack_rate(), + m_regs.decay_rate(), + m_regs.sustain_rate(), + m_regs.release_rate(), + m_regs.sustain_level(), + m_regs.pan_left() ? 'L' : '-', + m_regs.pan_right() ? 'R' : '-'); + if (m_regs.ssg_eg_enabled()) + LOG(" ssg=%X", m_regs.ssg_eg_mode()); + if (m_regs.lfo_enabled() && ((m_regs.lfo_am_enabled() && m_regs.lfo_am_sensitivity() != 0) || m_regs.lfo_pm_sensitivity() != 0)) + LOG(" am=%d pm=%d w=%d", m_regs.lfo_am_enabled() ? m_regs.lfo_am_sensitivity() : 0, m_regs.lfo_pm_sensitivity(), m_regs.lfo_waveform()); + if (m_regs.noise_enabled() && m_regs.opnum() == 3 && m_regs.chnum() == 7) + LOG(" noise=1"); + LOG("\n"); + } } @@ -1255,6 +1258,8 @@ ymfm_engine_base::ymfm_engine_base(device_t &device) : m_lfo_counter(0), m_noise_lfsr(0), m_noise_counter(0), + m_noise_state(0), + m_noise_lfo(0), m_lfo_am(0), m_status(0), m_clock_prescale(RegisterType::DEFAULT_PRESCALE), @@ -1291,6 +1296,8 @@ void ymfm_engine_base::save(device_t &device) device.save_item(YMFM_NAME(m_lfo_counter)); device.save_item(YMFM_NAME(m_noise_lfsr)); device.save_item(YMFM_NAME(m_noise_counter)); + device.save_item(YMFM_NAME(m_noise_state)); + device.save_item(YMFM_NAME(m_noise_lfo)); device.save_item(YMFM_NAME(m_lfo_am)); device.save_item(YMFM_NAME(m_status)); device.save_item(YMFM_NAME(m_clock_prescale)); @@ -1375,7 +1382,7 @@ void ymfm_engine_base::output(s32 &lsum, s32 &rsum, u8 rshift, s16 { // noise must be non-zero to use noise on OP4, so if it is enabled, // OR with 2 (since only the LSB is actually checked for the noise state) - u8 noise = (chnum == 7 && m_regs.noise_enabled()) ? (m_noise_lfsr | 2) : 0; + u8 noise = (chnum == 7 && m_regs.noise_enabled()) ? (m_noise_state | 2) : 0; m_channel[chnum]->output(m_lfo_am, noise, lsum, rsum, rshift, clipmax); } } @@ -1439,6 +1446,7 @@ s8 ymfm_engine_base::clock_lfo() // leading 1; this matches exactly the frequencies in the application // manual, though it might not be implemented exactly this way on chip u8 rate = m_regs.lfo_rate(); + u32 prev_counter = m_lfo_counter; m_lfo_counter += (0x10 | BIT(rate, 0, 4)) << BIT(rate, 4, 4); u8 lfo = BIT(m_lfo_counter, 22, 8); @@ -1470,11 +1478,12 @@ s8 ymfm_engine_base::clock_lfo() // noise: case 3: - // QUESTION: totally random guess here; does the LFO counter - // play into this? Is there a separate LFSR for the LFO noise? - // Do we sample & hold the noise at a certain point based on - // the LFO counter? - am = BIT(m_noise_lfsr, 0) ? 0xff : 0; + // QUESTION: this behavior is surmised but not yet verified: + // LFO noise value is accumulated over 8 bits of LFSR and + // clocked as the LFO value transitions + if (BIT(m_lfo_counter ^ prev_counter, 22, 8) != 0) + m_noise_lfo = m_noise_lfsr & 0xff; + am = m_noise_lfo; pm = am ^ 0x80; break; } @@ -1537,18 +1546,22 @@ void ymfm_engine_base::clock_noise() { // base noise frequency is measured at 2x 1/2 FM frequency; this means // each tick counts as two steps against the noise counter - m_noise_counter += 2; - - // compare against the frequency - u8 freq = m_regs.noise_frequency() + 1; - while (m_noise_counter >= freq) + u8 freq = m_regs.noise_frequency(); + for (int rep = 0; rep < 2; rep++) { - m_noise_counter -= freq; - - // note that the LFSR here contains the output bit in bit 0, with - // the current LFSR state in bits 1-17 + // evidence seems to suggest the LFSR is clocked continually and just + // sampled at the noise frequency for output purposes; clock it here + // twice; note that the low 8 bits are the most recent 8 bits of history + // while bits 8-24 contain the 17 bit LFSR state m_noise_lfsr >>= 1; - m_noise_lfsr |= (BIT(m_noise_lfsr, 0) ^ BIT(m_noise_lfsr, 3) ^ 1) << 17; + m_noise_lfsr |= (BIT(m_noise_lfsr, 7) ^ BIT(m_noise_lfsr, 10) ^ 1) << 24; + + // compare against the frequency and latch when we exceed it + if (m_noise_counter++ >= freq) + { + m_noise_counter = 0; + m_noise_state = BIT(m_noise_lfsr, 7); + } } } diff --git a/src/devices/sound/ymfm.h b/src/devices/sound/ymfm.h index 9d5c4197dad..33e307ed16f 100644 --- a/src/devices/sound/ymfm.h +++ b/src/devices/sound/ymfm.h @@ -799,6 +799,8 @@ private: u32 m_lfo_counter; // LFO counter u32 m_noise_lfsr; // noise LFSR state u8 m_noise_counter; // noise counter + u8 m_noise_state; // latched noise state + u8 m_noise_lfo; // latched LFO noise value u8 m_lfo_am; // current LFO AM value u8 m_status; // current status register u8 m_clock_prescale; // prescale factor (2/3/6)