diff options
Diffstat (limited to '3rdparty/ymfm/src/ymfm_fm.ipp')
-rw-r--r-- | 3rdparty/ymfm/src/ymfm_fm.ipp | 65 |
1 files changed, 58 insertions, 7 deletions
diff --git a/3rdparty/ymfm/src/ymfm_fm.ipp b/3rdparty/ymfm/src/ymfm_fm.ipp index ab5fc064e30..78e3a62d9c8 100644 --- a/3rdparty/ymfm/src/ymfm_fm.ipp +++ b/3rdparty/ymfm/src/ymfm_fm.ipp @@ -448,6 +448,8 @@ void fm_operator<RegisterType>::clock(uint32_t env_counter, int32_t lfo_raw_pm) // clock the SSG-EG state (OPN/OPNA) if (m_regs.op_ssg_eg_enable(m_opoffs)) clock_ssg_eg_state(); + else + m_ssg_inverted = false; // clock the envelope if on an envelope cycle; env_counter is a x.2 value if (bitfield(env_counter, 0, 2) == 0) @@ -881,6 +883,23 @@ void fm_channel<RegisterType>::clock(uint32_t env_counter, int32_t lfo_raw_pm) for (uint32_t opnum = 0; opnum < array_size(m_op); opnum++) if (m_op[opnum] != nullptr) m_op[opnum]->clock(env_counter, lfo_raw_pm); + +/* +useful temporary code for envelope debugging +if (m_choffs == 0x101) +{ + for (uint32_t opnum = 0; opnum < array_size(m_op); opnum++) + { + auto &op = *m_op[((opnum & 1) << 1) | ((opnum >> 1) & 1)]; + printf(" %c%03X%c%c ", + "PADSRV"[op.debug_eg_state()], + op.debug_eg_attenuation(), + op.debug_ssg_inverted() ? '-' : '+', + m_regs.op_ssg_eg_enable(op.opoffs()) ? '0' + m_regs.op_ssg_eg_mode(op.opoffs()) : ' '); + } +printf(" -- "); +} +*/ } @@ -928,7 +947,8 @@ void fm_channel<RegisterType>::output_2op(output_data &output, uint32_t rshift, } else { - result = op1value + (m_op[1]->compute_volume(m_op[1]->phase(), am_offset) >> rshift); + result = (RegisterType::MODULATOR_DELAY ? m_feedback[1] : op1value) >> rshift; + result += m_op[1]->compute_volume(m_op[1]->phase(), am_offset) >> rshift; int32_t clipmin = -clipmax - 1; result = clamp(result, clipmin, clipmax); } @@ -1165,6 +1185,7 @@ fm_engine_base<RegisterType>::fm_engine_base(ymfm_interface &intf) : m_irq_mask(STATUS_TIMERA | STATUS_TIMERB), m_irq_state(0), m_timer_running{0,0}, + m_total_clocks(0), m_active_channels(ALL_CHANNELS), m_modified_channels(ALL_CHANNELS), m_prepare_count(0) @@ -1180,6 +1201,11 @@ fm_engine_base<RegisterType>::fm_engine_base(ymfm_interface &intf) : for (uint32_t opnum = 0; opnum < OPERATORS; opnum++) m_operator[opnum] = std::make_unique<fm_operator<RegisterType>>(*this, RegisterType::operator_offset(opnum)); +#if (YMFM_DEBUG_LOG_WAVFILES) + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + m_wavfile[chnum].set_index(chnum); +#endif + // do the initial operator assignment assign_operators(); } @@ -1227,6 +1253,7 @@ void fm_engine_base<RegisterType>::save_restore(ymfm_saved_state &state) state.save_restore(m_irq_state); state.save_restore(m_timer_running[0]); state.save_restore(m_timer_running[1]); + state.save_restore(m_total_clocks); // save the register/family data m_regs.save_restore(state); @@ -1252,6 +1279,9 @@ void fm_engine_base<RegisterType>::save_restore(ymfm_saved_state &state) template<class RegisterType> uint32_t fm_engine_base<RegisterType>::clock(uint32_t chanmask) { + // update the clock counter + m_total_clocks++; + // if something was modified, prepare // also prepare every 4k samples to catch ending notes if (m_modified_channels != 0 || m_prepare_count++ >= 4096) @@ -1303,7 +1333,8 @@ void fm_engine_base<RegisterType>::output(output_data &output, uint32_t rshift, chanmask &= debug::GLOBAL_FM_CHANNEL_MASK; // mask out inactive channels - chanmask &= m_active_channels; + if (!YMFM_DEBUG_LOG_WAVFILES) + chanmask &= m_active_channels; // handle the rhythm case, where some of the operators are dedicated // to percussion (this is an OPL-specific feature) @@ -1321,6 +1352,9 @@ void fm_engine_base<RegisterType>::output(output_data &output, uint32_t rshift, for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) if (bitfield(chanmask, chnum)) { +#if (YMFM_DEBUG_LOG_WAVFILES) + auto reference = output; +#endif if (chnum == 6) m_channel[chnum]->output_rhythm_ch6(output, rshift, clipmax); else if (chnum == 7) @@ -1331,6 +1365,9 @@ void fm_engine_base<RegisterType>::output(output_data &output, uint32_t rshift, m_channel[chnum]->output_4op(output, rshift, clipmax); else m_channel[chnum]->output_2op(output, rshift, clipmax); +#if (YMFM_DEBUG_LOG_WAVFILES) + m_wavfile[chnum].add(output, reference); +#endif } } else @@ -1339,10 +1376,16 @@ void fm_engine_base<RegisterType>::output(output_data &output, uint32_t rshift, for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) if (bitfield(chanmask, chnum)) { +#if (YMFM_DEBUG_LOG_WAVFILES) + auto reference = output; +#endif if (m_channel[chnum]->is4op()) m_channel[chnum]->output_4op(output, rshift, clipmax); else m_channel[chnum]->output_2op(output, rshift, clipmax); +#if (YMFM_DEBUG_LOG_WAVFILES) + m_wavfile[chnum].add(output, reference); +#endif } } } @@ -1428,7 +1471,7 @@ void fm_engine_base<RegisterType>::assign_operators() //------------------------------------------------- template<class RegisterType> -void fm_engine_base<RegisterType>::update_timer(uint32_t tnum, uint32_t enable) +void fm_engine_base<RegisterType>::update_timer(uint32_t tnum, uint32_t enable, int32_t delta_clocks) { // if the timer is live, but not currently enabled, set the timer if (enable && !m_timer_running[tnum]) @@ -1436,6 +1479,9 @@ void fm_engine_base<RegisterType>::update_timer(uint32_t tnum, uint32_t enable) // period comes from the registers, and is different for each uint32_t period = (tnum == 0) ? (1024 - m_regs.timer_a_value()) : 16 * (256 - m_regs.timer_b_value()); + // caller can also specify a delta to account for other effects + period += delta_clocks; + // reset it m_intf.ymfm_set_timer(tnum, period * OPERATORS * m_clock_prescale); m_timer_running[tnum] = 1; @@ -1468,11 +1514,14 @@ void fm_engine_base<RegisterType>::engine_timer_expired(uint32_t tnum) if (tnum == 0 && m_regs.csm()) for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) if (bitfield(RegisterType::CSM_TRIGGER_MASK, chnum)) + { m_channel[chnum]->keyonoff(1, KEYON_CSM, chnum); + m_modified_channels |= 1 << chnum; + } // reset m_timer_running[tnum] = false; - update_timer(tnum, 1); + update_timer(tnum, 1, 0); } @@ -1530,9 +1579,11 @@ void fm_engine_base<RegisterType>::engine_mode_write(uint8_t data) reset_mask |= RegisterType::STATUS_TIMERA; set_reset_status(0, reset_mask); - // load timers - update_timer(1, m_regs.load_timer_b()); - update_timer(0, m_regs.load_timer_a()); + // load timers; note that timer B gets a small negative adjustment because + // the *16 multiplier is free-running, so the first tick of the clock + // is a bit shorter + update_timer(1, m_regs.load_timer_b(), -(m_total_clocks & 15)); + update_timer(0, m_regs.load_timer_a(), 0); } } |