diff options
| author | 2025-11-30 20:40:01 +0100 | |
|---|---|---|
| committer | 2025-11-30 20:40:14 +0100 | |
| commit | 66deabe1768df8e0ee3767688a8bfec32df27f72 (patch) | |
| tree | 4a3b44f98e32aba2f69a26364ed13f3f7c0f841b /3rdparty | |
| parent | 3c94fd6829d59e5f1cc17d854e277f3ef6cbf9b1 (diff) | |
ymfm: adpcm updates from https://github.com/aaronsgiles/ymfm/pull/40 [Aaron Giles]
Diffstat (limited to '3rdparty')
| -rw-r--r-- | 3rdparty/ymfm/src/ymfm_adpcm.cpp | 444 | ||||
| -rw-r--r-- | 3rdparty/ymfm/src/ymfm_adpcm.h | 89 | ||||
| -rw-r--r-- | 3rdparty/ymfm/src/ymfm_opl.cpp | 2 | ||||
| -rw-r--r-- | 3rdparty/ymfm/src/ymfm_opn.cpp | 5 |
4 files changed, 351 insertions, 189 deletions
diff --git a/3rdparty/ymfm/src/ymfm_adpcm.cpp b/3rdparty/ymfm/src/ymfm_adpcm.cpp index 4bc22beb2b0..0917e7c361a 100644 --- a/3rdparty/ymfm/src/ymfm_adpcm.cpp +++ b/3rdparty/ymfm/src/ymfm_adpcm.cpp @@ -390,13 +390,13 @@ void adpcm_b_registers::save_restore(ymfm_saved_state &state) adpcm_b_channel::adpcm_b_channel(adpcm_b_engine &owner, uint32_t addrshift) : m_address_shift(addrshift), m_status(STATUS_BRDY), - m_curnibble(0), - m_curbyte(0), - m_dummy_read(0), + m_buffer(0), + m_nibbles(0), m_position(0), m_curaddress(0), m_accumulator(0), - m_prev_accum(0), + m_output(0), + m_prev_output(0), m_adpcm_step(STEP_MIN), m_regs(owner.regs()), m_owner(owner) @@ -411,13 +411,13 @@ adpcm_b_channel::adpcm_b_channel(adpcm_b_engine &owner, uint32_t addrshift) : void adpcm_b_channel::reset() { m_status = STATUS_BRDY; - m_curnibble = 0; - m_curbyte = 0; - m_dummy_read = 0; + m_buffer = 0; + m_nibbles = 0; m_position = 0; m_curaddress = 0; m_accumulator = 0; - m_prev_accum = 0; + m_output = 0; + m_prev_output = 0; m_adpcm_step = STEP_MIN; } @@ -429,13 +429,13 @@ void adpcm_b_channel::reset() void adpcm_b_channel::save_restore(ymfm_saved_state &state) { state.save_restore(m_status); - state.save_restore(m_curnibble); - state.save_restore(m_curbyte); - state.save_restore(m_dummy_read); + state.save_restore(m_buffer); + state.save_restore(m_nibbles); state.save_restore(m_position); state.save_restore(m_curaddress); state.save_restore(m_accumulator); - state.save_restore(m_prev_accum); + state.save_restore(m_output); + state.save_restore(m_prev_output); state.save_restore(m_adpcm_step); } @@ -447,9 +447,11 @@ void adpcm_b_channel::save_restore(ymfm_saved_state &state) void adpcm_b_channel::clock() { // only process if active and not recording (which we don't support) - if (!m_regs.execute() || m_regs.record() || (m_status & STATUS_PLAYING) == 0) + if (!m_regs.execute() || m_regs.record() || (m_status & STATUS_INTERNAL_PLAYING) == 0) { - m_status &= ~STATUS_PLAYING; + m_prev_output = m_output; + m_position = 0; + set_reset_status(0, STATUS_INTERNAL_PLAYING); return; } @@ -459,76 +461,63 @@ void adpcm_b_channel::clock() if (position < 0x10000) return; - // if we're about to process nibble 0, fetch sample - if (m_curnibble == 0) + // if we have nibbles available, process them + if (m_nibbles != 0) { - // playing from RAM/ROM - if (m_regs.external()) - m_curbyte = m_owner.intf().ymfm_external_read(ACCESS_ADPCM_B, m_curaddress); - } + // fetch the next nibble + uint8_t data = consume_nibbles(1); - // extract the nibble from our current byte - uint8_t data = uint8_t(m_curbyte << (4 * m_curnibble)) >> 4; - m_curnibble ^= 1; + // forecast to next forecast: 1/8, 3/8, 5/8, 7/8, 9/8, 11/8, 13/8, 15/8 + int32_t delta = (2 * bitfield(data, 0, 3) + 1) * m_adpcm_step / 8; + if (bitfield(data, 3)) + delta = -delta; - // we just processed the last nibble - if (m_curnibble == 0) - { - // if playing from RAM/ROM, check the end/limit address or advance - if (m_regs.external()) - { - // handle the sample end, either repeating or stopping - if (at_end()) - { - // if repeating, go back to the start - if (m_regs.repeat()) - load_start(); - - // otherwise, done; set the EOS bit - else - { - m_accumulator = 0; - m_prev_accum = 0; - m_status = (m_status & ~STATUS_PLAYING) | STATUS_EOS; - debug::log_keyon("%s\n", "ADPCM EOS"); - return; - } - } + // add and clamp to 16 bits + m_accumulator = clamp(m_accumulator + delta, -32768, 32767); - // wrap at the limit address - else if (at_limit()) - m_curaddress = 0; + // scale the ADPCM step: 0.9, 0.9, 0.9, 0.9, 1.2, 1.6, 2.0, 2.4 + static uint8_t const s_step_scale[8] = { 57, 57, 57, 57, 77, 102, 128, 153 }; + m_adpcm_step = clamp((m_adpcm_step * s_step_scale[bitfield(data, 0, 3)]) / 64, STEP_MIN, STEP_MAX); - // otherwise, advance the current address - else - { - m_curaddress++; - m_curaddress &= 0xffffff; - } - } + // make the new output equal to the accumulator + m_prev_output = m_output; + m_output = m_accumulator; - // if CPU-driven, copy the next byte and request more - else + // if we've drained all the nibbles, that means we're at a repeat point or end of sample + if (m_nibbles == 0) { - m_curbyte = m_regs.cpudata(); - m_status |= STATUS_BRDY; + // reset the ADPCM state (but leave output alone) + m_accumulator = 0; + m_adpcm_step = STEP_MIN; + + // always set EOS bit, even if repeating + set_reset_status(STATUS_EOS); + debug::log_keyon("%s\n", "ADPCM EOS"); + + // clear playing flag if we're not repeating + if (!m_regs.repeat()) + set_reset_status(0, STATUS_INTERNAL_PLAYING); } } - // remember previous value for interpolation - m_prev_accum = m_accumulator; - - // forecast to next forecast: 1/8, 3/8, 5/8, 7/8, 9/8, 11/8, 13/8, 15/8 - int32_t delta = (2 * bitfield(data, 0, 3) + 1) * m_adpcm_step / 8; - if (bitfield(data, 3)) - delta = -delta; + // if we don't have at least 3 nibbles in the buffer, request more data + if ((m_status & STATUS_INTERNAL_PLAYING) != 0 && m_nibbles < 3) + { + // if we hit the end address after this fetch, handle looping/ending + if (request_data()) + { + // the final 3 samples are not played; chop them from the stream + consume_nibbles(3); - // add and clamp to 16 bits - m_accumulator = clamp(m_accumulator + delta, -32768, 32767); + // this should always end up as 1; the logic above assumes we will hit + // 0 nibbles after processing the next one + assert(m_nibbles == 1); - // scale the ADPCM step: 0.9, 0.9, 0.9, 0.9, 1.2, 1.6, 2.0, 2.4 - static uint8_t const s_step_scale[8] = { 57, 57, 57, 57, 77, 102, 128, 153 }; - m_adpcm_step = clamp((m_adpcm_step * s_step_scale[bitfield(data, 0, 3)]) / 64, STEP_MIN, STEP_MAX); + // if repeating, set the current address back to start for next fetch + if (m_regs.repeat()) + latch_addresses(); + } + } } @@ -545,7 +534,7 @@ void adpcm_b_channel::output(ymfm_output<NumOutputs> &output, uint32_t rshift) c return; // do a linear interpolation between samples - int32_t result = (m_prev_accum * int32_t((m_position ^ 0xffff) + 1) + m_accumulator * int32_t(m_position)) >> 16; + int32_t result = (m_prev_output * int32_t((m_position ^ 0xffff) + 1) + m_output * int32_t(m_position)) >> 16; // apply volume (level) in a linear fashion and reduce result = (result * int32_t(m_regs.level())) >> (8 + rshift); @@ -568,37 +557,8 @@ uint8_t adpcm_b_channel::read(uint32_t regnum) // register 8 reads over the bus under some conditions if (regnum == 0x08 && !m_regs.execute() && !m_regs.record() && m_regs.external()) - { - // two dummy reads are consumed first - if (m_dummy_read != 0) - { - load_start(); - m_dummy_read--; - } - - // read the data - else - { - // read from outside of the chip - result = m_owner.intf().ymfm_external_read(ACCESS_ADPCM_B, m_curaddress++); + result = read_ram(); - // did we hit the end? if so, signal EOS - if (at_end()) - { - m_status = STATUS_EOS | STATUS_BRDY; - debug::log_keyon("%s\n", "ADPCM EOS"); - } - else - { - // signal ready - m_status = STATUS_BRDY; - } - - // wrap at the limit address - if (at_limit()) - m_curaddress = 0; - } - } return result; } @@ -613,68 +573,76 @@ void adpcm_b_channel::write(uint32_t regnum, uint8_t value) // dummy read counter if (regnum == 0x00) { - if (m_regs.execute()) + // reset flag stops playback and holds output, but does not clear the + // externally-visible playing flag + if (m_regs.resetflag()) + set_reset_status(STATUS_BRDY | (((m_status & STATUS_INTERNAL_PLAYING) != 0) ? STATUS_EOS : 0), STATUS_INTERNAL_PLAYING); + + // all other modes set up for an operation + else { - load_start(); - - // don't log masked channels - if ((debug::GLOBAL_ADPCM_B_CHANNEL_MASK & 1) != 0) - debug::log_keyon("KeyOn ADPCM-B: rep=%d spk=%d pan=%d%d dac=%d 8b=%d rom=%d ext=%d rec=%d start=%04X end=%04X pre=%04X dn=%04X lvl=%02X lim=%04X\n", - m_regs.repeat(), - m_regs.speaker(), - m_regs.pan_left(), - m_regs.pan_right(), - m_regs.dac_enable(), - m_regs.dram_8bit(), - m_regs.rom_ram(), - m_regs.external(), - m_regs.record(), - m_regs.start(), - m_regs.end(), - m_regs.prescale(), - m_regs.delta_n(), - m_regs.level(), - m_regs.limit()); + // initialize the core state; appears to leave EOS flag alone until next execute + set_reset_status(STATUS_BRDY, STATUS_PLAYING | STATUS_INTERNAL_DRAIN | STATUS_INTERNAL_PLAYING | STATUS_INTERNAL_SUPPRESS_WRITE); + + // flag the address to be latched at the next access; this is necessary + // because it is allowed to program the start/stop addresses after this + // command byte is written + m_curaddress = LATCH_ADDRESS; + + // if playing, set the playing status + if (m_regs.execute()) + { + m_buffer = 0; + m_nibbles = 0; + m_position = 0; + m_accumulator = 0; + m_adpcm_step = STEP_MIN; + m_output = 0; + + set_reset_status(STATUS_PLAYING | STATUS_INTERNAL_PLAYING, STATUS_EOS); + + // don't log masked channels + if ((debug::GLOBAL_ADPCM_B_CHANNEL_MASK & 1) != 0) + debug::log_keyon("KeyOn ADPCM-B: rep=%d spk=%d pan=%d%d dac=%d 8b=%d rom=%d ext=%d rec=%d start=%04X end=%04X pre=%04X dn=%04X lvl=%02X lim=%04X\n", + m_regs.repeat(), + m_regs.speaker(), + m_regs.pan_left(), + m_regs.pan_right(), + m_regs.dac_enable(), + m_regs.dram_8bit(), + m_regs.rom_ram(), + m_regs.external(), + m_regs.record(), + m_regs.start(), + m_regs.end(), + m_regs.prescale(), + m_regs.delta_n(), + m_regs.level(), + m_regs.limit()); + } } - else - m_status &= ~STATUS_EOS; - if (m_regs.resetflag()) - reset(); - if (m_regs.external()) - m_dummy_read = 2; } // register 8 writes over the bus under some conditions else if (regnum == 0x08) { - // if writing from the CPU during execute, clear the ready flag - if (m_regs.execute() && !m_regs.record() && !m_regs.external()) - m_status &= ~STATUS_BRDY; - - // if writing during "record", pass through as data - else if (!m_regs.execute() && m_regs.record() && m_regs.external()) + // writing during execute + if (m_regs.execute()) { - // clear out dummy reads and set start address - if (m_dummy_read != 0) - { - load_start(); - m_dummy_read = 0; - } + // if writing from the CPU during execute, clear the ready flag; data will be picked + // up on next fetch + if (!m_regs.record() && !m_regs.external()) + set_reset_status(0, STATUS_BRDY); + } - // did we hit the end? if so, signal EOS - if (at_end()) - { - debug::log_keyon("%s\n", "ADPCM EOS"); - m_status = STATUS_EOS | STATUS_BRDY; - } + // if writing to external data, process record mode, which writes data to RAM + else if (m_regs.external() && m_regs.record()) + write_ram(value); - // otherwise, write the data and signal ready - else - { - m_owner.intf().ymfm_external_write(ACCESS_ADPCM_B, m_curaddress++, value); - m_status = STATUS_BRDY; - } - } + // writes in external non-record mode appear to behave like a read in that it will advance + // the address and consume a nibble, but the last written value will still be present + else + read_ram(); } } @@ -702,20 +670,164 @@ uint32_t adpcm_b_channel::address_shift() const //------------------------------------------------- -// load_start - load the start address and -// initialize the state +// advance_address - advance the address, checking +// for end/limit values at programmed boundaries; +// returns true if the end is hit //------------------------------------------------- -void adpcm_b_channel::load_start() +bool adpcm_b_channel::advance_address() { - m_status = (m_status & ~STATUS_EOS) | STATUS_PLAYING; - m_curaddress = m_regs.external() ? (m_regs.start() << address_shift()) : 0; - m_curnibble = 0; - m_curbyte = 0; - m_position = 0; - m_accumulator = 0; - m_prev_accum = 0; - m_adpcm_step = STEP_MIN; + // if we're fetching the last byte of a unit, check ending conditions + auto shift = address_shift(); + auto mask = (1 << shift) - 1; + + // should never get here with an uninitialized current address + assert(m_curaddress != LATCH_ADDRESS); + + // if at the end of a unit, check for end/limit + if ((m_curaddress & mask) == mask) + { + // shift off the low address bits and check against the end + uint32_t unitaddr = m_curaddress >> shift; + if (unitaddr == m_regs.end()) + return true; + + // wrap at the limit address; this does not report any status + else if (unitaddr == m_regs.limit()) + { + m_curaddress = 0; + return false; + } + } + + // advance the address + m_curaddress = (m_curaddress + 1) & 0xffffff; + return false; +} + + +//------------------------------------------------- +// request_data - request another byte of data +// for the buffer; used by both playback and +// data reading code +//------------------------------------------------- + +bool adpcm_b_channel::request_data() +{ + // pick up the current address if this is the first read + if (m_curaddress == LATCH_ADDRESS) + latch_addresses(); + + // if CPU-driven, just set the flag and return true + if (!m_regs.external()) + { + // if data was written, consume it + if ((m_status & STATUS_BRDY) == 0) + append_buffer_byte(m_regs.cpudata()); + set_reset_status(STATUS_BRDY); + return false; + } + + // append the new byte to our buffer; also write to the cpudata register to match + // behavior of dummy reads from real chip + uint8_t data = m_owner.intf().ymfm_external_read(ACCESS_ADPCM_B, m_curaddress); + append_buffer_byte(data); + m_regs.write(0x08, data); + + // advance the address, returning true if we hit the end + return advance_address(); +} + + +//------------------------------------------------- +// read_ram - perform a read cycle from RAM/ROM +//------------------------------------------------- + +uint8_t adpcm_b_channel::read_ram() +{ + // if this is the first read, ensure there is at least 2 bytes of data available, + // padding with the cpudata register if needed + if (m_curaddress == LATCH_ADDRESS) + { + set_reset_status(0, STATUS_INTERNAL_DRAIN); + while (m_nibbles < 4) + append_buffer_byte(m_regs.cpudata()); + } + + // if we have the nibbles, return them + uint8_t result = consume_nibbles(2); + set_reset_status(STATUS_BRDY); + + // if we previously hit the end and we're draining, see if we're out + if ((m_status & STATUS_INTERNAL_DRAIN) != 0) + { + // if we run out of nibbles, mark end of sample and reset the address + if (m_nibbles == 0) + { + set_reset_status(STATUS_EOS, STATUS_INTERNAL_DRAIN); + + // if repeating, add one dummy sample and issue a fetch of the first byte + if (m_regs.repeat()) + { + append_buffer_byte(m_regs.cpudata()); + m_curaddress = m_regs.start() << address_shift(); + request_data(); + } + + // otherwise, reset the address + else + m_curaddress = LATCH_ADDRESS; + } + } + + // if not draining, then request more data and start draining if we hit the end + else if (request_data()) + set_reset_status(STATUS_INTERNAL_DRAIN); + + return result; +} + + +//------------------------------------------------- +// write_ram - perform a write cycle to RAM +//------------------------------------------------- + +void adpcm_b_channel::write_ram(uint8_t value) +{ + // normal write case, unsuppressed + if ((m_status & STATUS_INTERNAL_SUPPRESS_WRITE) == 0) + { + // latch the current address if this is the first write + if (m_curaddress == LATCH_ADDRESS) + latch_addresses(); + + // write the data + m_owner.intf().ymfm_external_write(ACCESS_ADPCM_B, m_curaddress, value); + set_reset_status(STATUS_BRDY); + + // advance; if we hit the end, signal EOS and put ourselves back in the latching state + if (advance_address()) + { + set_reset_status(STATUS_EOS); + m_curaddress = LATCH_ADDRESS; + + // in the repeat case, suppress further writes + if (m_regs.repeat()) + set_reset_status(STATUS_INTERNAL_SUPPRESS_WRITE); + } + } + + // suppressed writes after reaching stop address in repeat mode; note that this runs + // immediately after the EOS condition above, as well as on subsequent writes + if ((m_status & STATUS_INTERNAL_SUPPRESS_WRITE) != 0) + { + // reset the buffer to 4 nibbles with 0 and the value written, then trigger a read + // cycle which will consume the 0 and clock in the next byte, leaving the value + // written as the next byte to consume + m_buffer = value << 16; + m_nibbles = 4; + read_ram(); + } } diff --git a/3rdparty/ymfm/src/ymfm_adpcm.h b/3rdparty/ymfm/src/ymfm_adpcm.h index 98f57121e5c..ef27b36427b 100644 --- a/3rdparty/ymfm/src/ymfm_adpcm.h +++ b/3rdparty/ymfm/src/ymfm_adpcm.h @@ -214,6 +214,8 @@ private: // ======================> adpcm_b_registers // +// See https://github.com/hyano/opna-analyze/blob/main/doc/OPNA.md for details on ADPCM timing +// // ADPCM-B register map: // // System-wide registers: @@ -263,6 +265,7 @@ public: void save_restore(ymfm_saved_state &state); // direct read/write access + uint8_t read(uint32_t index) const { return m_regdata[index]; } void write(uint32_t index, uint8_t data) { m_regdata[index] = data; } // system-wide registers @@ -301,11 +304,22 @@ class adpcm_b_channel static constexpr int32_t STEP_MIN = 127; static constexpr int32_t STEP_MAX = 24576; + static constexpr uint32_t LATCH_ADDRESS = 0xffffffff; + public: - static constexpr uint8_t STATUS_EOS = 0x01; - static constexpr uint8_t STATUS_BRDY = 0x02; - static constexpr uint8_t STATUS_PLAYING = 0x04; + // publicly visible status bits + static constexpr uint32_t STATUS_EOS = 0x01; + static constexpr uint32_t STATUS_BRDY = 0x02; + static constexpr uint32_t STATUS_PLAYING = 0x04; + +private: + // internal status bits + static constexpr uint32_t STATUS_EXTERNAL = STATUS_EOS | STATUS_BRDY | STATUS_PLAYING; + static constexpr uint32_t STATUS_INTERNAL_DRAIN = 0x08; + static constexpr uint32_t STATUS_INTERNAL_PLAYING = 0x10; + static constexpr uint32_t STATUS_INTERNAL_SUPPRESS_WRITE = 0x20; +public: // constructor adpcm_b_channel(adpcm_b_engine &owner, uint32_t addrshift); @@ -326,7 +340,10 @@ public: void output(ymfm_output<NumOutputs> &output, uint32_t rshift) const; // return the status register - uint8_t status() const { return m_status; } + uint8_t status() const { return m_status & STATUS_EXTERNAL; } + + // clear bits in the status register + void clear_status(uint8_t status) { m_status &= ~(status & STATUS_EXTERNAL); } // handle special register reads uint8_t read(uint32_t regnum); @@ -335,31 +352,56 @@ public: void write(uint32_t regnum, uint8_t value); private: - // helper - return the current address shift + // update the status register + void set_reset_status(uint32_t set, uint32_t reset = 0) { m_status = (m_status & ~reset) | set; } + + // return the current address shift uint32_t address_shift() const; - // load the start address - void load_start(); + // advance the address by one byte, return true if the end address was hit + bool advance_address(); + + // request the next byte of data + bool request_data(); - // limit checker; stops at the last byte of the chunk described by address_shift() - bool at_limit() const { return (m_curaddress == (((m_regs.limit() + 1) << address_shift()) - 1)); } + // perform a read cycle from RAM/ROM + uint8_t read_ram(); - // end checker; stops at the last byte of the chunk described by address_shift() - bool at_end() const { return (m_curaddress == (((m_regs.end() + 1) << address_shift()))); } + // perform a write cycle to RAM + void write_ram(uint8_t value); + + // latch the current address + void latch_addresses() { m_curaddress = m_regs.external() ? (m_regs.start() << address_shift()) : 0; } + + // append a byte to our internal buffer + void append_buffer_byte(uint8_t data) + { + m_buffer |= data << (24 - 4 * m_nibbles); + m_nibbles += 2; + } + + // consume the requested number of nibbles from the buffer + uint32_t consume_nibbles(uint8_t count) + { + uint32_t result = m_buffer >> (32 - 4 * count); + m_buffer <<= 4 * count; + m_nibbles = (m_nibbles > count) ? (m_nibbles - count) : 0; + return result; + } // internal state - uint32_t const m_address_shift; // address bits shift-left - uint32_t m_status; // currently playing? - uint32_t m_curnibble; // index of the current nibble - uint32_t m_curbyte; // current byte of data - uint32_t m_dummy_read; // dummy read tracker - uint32_t m_position; // current fractional position - uint32_t m_curaddress; // current address - int32_t m_accumulator; // accumulator - int32_t m_prev_accum; // previous accumulator (for linear interp) - int32_t m_adpcm_step; // next forecast - adpcm_b_registers &m_regs; // reference to registers - adpcm_b_engine &m_owner; // reference to our owner + uint32_t const m_address_shift; // address bits shift-left + uint32_t m_status; // currently playing? + uint32_t m_buffer; // buffer of bytes read, left-justified + uint32_t m_nibbles; // number of nibbles in m_bytebuffer + uint32_t m_position; // current fractional position + uint32_t m_curaddress; // current address + int32_t m_accumulator; // accumulator + int32_t m_output; // current output value + int32_t m_prev_output; // previous output value (for linear interp) + int32_t m_adpcm_step; // next forecast + adpcm_b_registers &m_regs; // reference to registers + adpcm_b_engine &m_owner; // reference to our owner }; @@ -392,6 +434,7 @@ public: // status uint8_t status() const { return m_channel->status(); } + void clear_status(uint8_t status) { m_channel->clear_status(status); } // return a reference to our interface ymfm_interface &intf() { return m_intf; } diff --git a/3rdparty/ymfm/src/ymfm_opl.cpp b/3rdparty/ymfm/src/ymfm_opl.cpp index 8e8025fd9cc..46f93c708df 100644 --- a/3rdparty/ymfm/src/ymfm_opl.cpp +++ b/3rdparty/ymfm/src/ymfm_opl.cpp @@ -1012,6 +1012,8 @@ void y8950::write_data(uint8_t data) { case 0x04: // IRQ control m_fm.write(m_address, data); + if ((data & STATUS_ADPCM_B_EOS) != 0) + m_adpcm_b.clear_status(adpcm_b_channel::STATUS_EOS); read_status(); break; diff --git a/3rdparty/ymfm/src/ymfm_opn.cpp b/3rdparty/ymfm/src/ymfm_opn.cpp index 9a8f5e99feb..5f418636a87 100644 --- a/3rdparty/ymfm/src/ymfm_opn.cpp +++ b/3rdparty/ymfm/src/ymfm_opn.cpp @@ -1237,7 +1237,10 @@ void ym2608::write_data_hi(uint8_t data) { // 110: IRQ flag control if (bitfield(data, 7)) + { m_fm.set_reset_status(0, 0xff); + m_adpcm_b.clear_status(adpcm_b_channel::STATUS_EOS | adpcm_b_channel::STATUS_PLAYING); + } else { m_flag_control = data; @@ -2024,6 +2027,8 @@ void ym2610::write_data(uint8_t data) // 1C: EOS flag reset m_flag_mask = ~data & EOS_FLAGS_MASK; m_eos_status &= ~(data & EOS_FLAGS_MASK); + if (bitfield(data, 7)) + m_adpcm_b.clear_status(adpcm_b_channel::STATUS_EOS); } else { |
