diff options
-rw-r--r-- | src/devices/sound/ymz770.cpp | 209 | ||||
-rw-r--r-- | src/devices/sound/ymz770.h | 5 |
2 files changed, 106 insertions, 108 deletions
diff --git a/src/devices/sound/ymz770.cpp b/src/devices/sound/ymz770.cpp index 968a1514072..491f0f8758e 100644 --- a/src/devices/sound/ymz770.cpp +++ b/src/devices/sound/ymz770.cpp @@ -14,10 +14,12 @@ TODO: - verify if pan 100% correct - sequencer timers and triggers not implemented (seems used in Deathsmiles ending tune) 774: -- find out how volume/pan delayed transition works (used few times in orleg2 attract mode) - 4 channel output - Equalizer -- Sequencer (not used) +- volume/pan delayed transition (used few times during orleg2 attract mode) +- channel pause/resume (seems not used in games) +- sequencer pause/resume (seems not used in games) +- sequencer off trigger (seems not used in games) ***************************************************************************/ @@ -26,8 +28,8 @@ TODO: #include "mpeg_audio.h" // device type definition -DEFINE_DEVICE_TYPE(YMZ770, ymz770_device, "ymz770", "Yamaha YMZ770C-F AMMS-A") -DEFINE_DEVICE_TYPE(YMZ774, ymz774_device, "ymz774", "Yamaha YMZ774-S AMMS2") +DEFINE_DEVICE_TYPE(YMZ770, ymz770_device, "ymz770", "Yamaha YMZ770C AMMS-A") +DEFINE_DEVICE_TYPE(YMZ774, ymz774_device, "ymz774", "Yamaha YMZ774 AMMS2") //------------------------------------------------- // ymz770_device - constructor @@ -71,6 +73,8 @@ void ymz770_device::device_start() } for (auto & sequence : m_sequences) sequence.is_playing = false; + for (auto & sqc : m_sqcs) + sqc.is_playing = false; // register for save states save_item(NAME(m_cur_reg)); @@ -109,6 +113,7 @@ void ymz770_device::device_start() save_item(NAME(m_sequences[ch].loop), ch); save_item(NAME(m_sequences[ch].bank), ch); save_item(NAME(m_sequences[ch].is_playing), ch); + save_item(NAME(m_sequences[ch].offset), ch); } for (int ch = 0; ch < 8; ch++) { @@ -116,6 +121,7 @@ void ymz770_device::device_start() save_item(NAME(m_sqcs[ch].loop), ch); save_item(NAME(m_sqcs[ch].is_playing), ch); save_item(NAME(m_sqcs[ch].is_waiting), ch); + save_item(NAME(m_sqcs[ch].offset), ch); } } @@ -276,27 +282,18 @@ void ymz770_device::sequencer() if (sequence.is_playing) { if (sequence.delay > 0) - { sequence.delay--; - } else { - int reg = *sequence.data++; - uint8_t data = *sequence.data++; + int reg = get_rom_byte(sequence.offset++); + uint8_t data = get_rom_byte(sequence.offset++); switch (reg) { case 0x0f: if (sequence.loop) - { - // loop sequence - uint8_t sqn = sequence.sequence; - uint32_t pptr = get_seq_offs(sqn); - sequence.data = &m_rom[pptr]; - } + sequence.offset = get_seq_offs(sequence.sequence); // loop sequence else - { sequence.is_playing = false; - } break; case 0x0e: sequence.delay = 32 - 1; @@ -322,9 +319,7 @@ WRITE8_MEMBER( ymz770_device::write ) internal_reg_write(m_cur_reg, data); } else - { m_cur_reg = data; - } } @@ -351,6 +346,7 @@ void ymz770_device::internal_reg_write(uint8_t reg, uint8_t data) // unused default: + logerror("unimplemented write %02X %02X\n", reg, data); break; } } @@ -386,9 +382,7 @@ void ymz770_device::internal_reg_write(uint8_t reg, uint8_t data) m_channels[ch].is_playing = true; } else - { m_channels[ch].is_playing = false; - } m_channels[ch].loop = (data & 1) ? 255 : 0; break; @@ -408,16 +402,12 @@ void ymz770_device::internal_reg_write(uint8_t reg, uint8_t data) case 1: if (data & 6) { - uint8_t sqn = m_sequences[ch].sequence; - uint32_t pptr = get_seq_offs(sqn); - m_sequences[ch].data = &m_rom[pptr]; + m_sequences[ch].offset = get_seq_offs(m_sequences[ch].sequence); m_sequences[ch].delay = 0; m_sequences[ch].is_playing = true; } else - { m_sequences[ch].is_playing = false; - } m_sequences[ch].loop = data & 1; break; @@ -523,81 +513,90 @@ void ymz774_device::internal_reg_write(uint8_t reg, uint8_t data) { if (m_bank == 0) { - if (reg < 0xb0) + int sq = reg & 7; + switch (reg & 0xf8) { - int sq = reg & 7; - switch (reg & 0xf8) + case 0x60: // sequence num H and L + case 0x68: + sq = (reg >> 1) & 7; + if (reg & 1) + m_sequences[sq].sequence = (m_sequences[sq].sequence & 0xff00) | data; + else + m_sequences[sq].sequence = (m_sequences[sq].sequence & 0x00ff) | ((data & 0x0f) << 8); + break; + case 0x70: // Start / Stop + if (data) { - case 0x60: // sequence num H and L - case 0x68: - sq = (reg >> 1) & 7; - if (reg & 1) - m_sequences[sq].sequence = (m_sequences[sq].sequence & 0xff00) | data; - else - m_sequences[sq].sequence = (m_sequences[sq].sequence & 0x00ff) | ((data & 0x0f) << 8); - break; - case 0x70: // Start / Stop - if (data) - { - uint32_t pptr = get_seq_offs(m_sequences[sq].sequence); - m_sequences[sq].data = &m_rom[pptr]; - m_sequences[sq].delay = 0; - m_sequences[sq].is_playing = true; - } - else - { - m_sequences[sq].is_playing = false; - } - break; - case 0x78: // Pause / Resume - if (data) logerror("SEQ pause/resume unimplemented %02X %02X\n", reg, data); - break; - case 0x80: // Loop count, 0 = off, 255 - infinite - m_sequences[sq].loop = data; - break; - case 0x88: // timer H and L - case 0x90: - sq = (reg - 0x88) >> 1; - if (reg & 1) - m_sequences[sq].timer = (m_sequences[sq].timer & 0xff00) | data; - else - m_sequences[sq].timer = (m_sequences[sq].timer & 0x00ff) | (data << 8); - break; - case 0x98: // Off trigger, bit4 = on/off, bits0-3 channel (end sequence when channel playback ends) - if (data) logerror("SEQ Off trigger unimplemented %02X %02X\n", reg, data); - break; - case 0xa0: // stop channel mask H and L, what it for ? stop chanels immediatelly or when sequence ends (so far assuming later) ? - case 0xa8: - sq = (reg >> 1) & 7; - if (reg & 1) - m_sequences[sq].stopchan = (m_sequences[sq].stopchan & 0xff00) | data; - else - m_sequences[sq].stopchan = (m_sequences[sq].stopchan & 0x00ff) | (data << 8); - break; + //logerror("SEQ %d start (%s)\n", sq, m_sequences[sq].is_playing ? "playing":"stopped"); + m_sequences[sq].offset = get_seq_offs(m_sequences[sq].sequence); + m_sequences[sq].delay = 0; + m_sequences[sq].is_playing = true; } - } - else - { - int sq = reg & 7; - switch (reg & 0xf8) + else { - case 0xb0: - m_sqcs[sq].sqc = data; - break; - case 0xb8: - if (data) - { - m_sqcs[sq].data = &m_rom[get_sqc_offs(m_sqcs[sq].sqc)]; - m_sqcs[sq].is_playing = true; - m_sqcs[sq].is_waiting = false; - } - else - m_sqcs[sq].is_playing = false; - break; - case 0xc0: - m_sqcs[sq].loop = data; - break; + //logerror("SEQ %d stop (%s)\n", sq, m_sequences[sq].is_playing ? "playing" : "stopped"); + if (m_sequences[sq].is_playing) + for (int ch = 0; ch < 16; ch++) + if (m_sequences[sq].stopchan & (1 << ch)) + m_channels[ch].is_playing = false; + m_sequences[sq].is_playing = false; + } + break; + case 0x78: // Pause / Resume + if (data) logerror("SEQ pause/resume unimplemented %02X %02X\n", reg, data); + break; + case 0x80: // Loop count, 0 = off, 255 - infinite + m_sequences[sq].loop = data; + break; + case 0x88: // timer H and L + case 0x90: + sq = (reg - 0x88) >> 1; + if (reg & 1) + m_sequences[sq].timer = (m_sequences[sq].timer & 0xff00) | data; + else + m_sequences[sq].timer = (m_sequences[sq].timer & 0x00ff) | (data << 8); + break; + case 0x98: // Off trigger, bit4 = on/off, bits0-3 channel (end sequence when channel playback ends) + if (data) logerror("SEQ Off trigger unimplemented %02X %02X\n", reg, data); + break; + case 0xa0: // stop channel mask H and L, what it for ? stop chanels immediatelly or when sequence ends (so far assuming later) ? + case 0xa8: + sq = (reg >> 1) & 7; + if (reg & 1) + m_sequences[sq].stopchan = (m_sequences[sq].stopchan & 0xff00) | data; + else + m_sequences[sq].stopchan = (m_sequences[sq].stopchan & 0x00ff) | (data << 8); + if (data) logerror("Check me: SEQ Stop Channels used %02X %02X\n", reg, data); + break; + case 0xb0: + m_sqcs[sq].sqc = data; + break; + case 0xb8: + if (data) + { + //logerror("SQC %d start (%s)\n", sq, m_sqcs[sq].is_playing ? "playing" : "stopped"); + m_sqcs[sq].offset = get_sqc_offs(m_sqcs[sq].sqc); + m_sqcs[sq].is_playing = true; + m_sqcs[sq].is_waiting = false; } + else + { + //logerror("SQC %d stop (%s)\n", sq, m_sqcs[sq].is_playing ? "playing" : "stopped"); + m_sqcs[sq].is_playing = false; + // stop SEQ too, is this right ? at least kof98umh never manually stop SEQ + if (m_sequences[sq].is_playing) + for (int ch = 0; ch < 16; ch++) + if (m_sequences[sq].stopchan & (1 << ch)) + m_channels[ch].is_playing = false; + m_sequences[sq].is_playing = false; + } + break; + case 0xc0: + m_sqcs[sq].loop = data; + break; + default: + logerror("unimplemented write %02X %02X\n", reg, data); + break; } } // else bank1 - Equalizer control @@ -632,25 +631,24 @@ void ymz774_device::sequencer() if (sqc.is_playing && !sqc.is_waiting) { - sequence.sequence = ((sqc.data[0] << 8) | sqc.data[1]) & 0xfff; - sequence.loop = sqc.data[2]; - sequence.data = &m_rom[get_seq_offs(sequence.sequence)]; + sequence.sequence = ((get_rom_byte(sqc.offset) << 8) | get_rom_byte(sqc.offset + 1)) & 0xfff; + sqc.offset += 2; + sequence.loop = get_rom_byte(sqc.offset++); + sequence.offset = get_seq_offs(sequence.sequence); sequence.delay = 0; sequence.is_playing = true; sqc.is_waiting = true; - if (sqc.data[3] == 0xff) + if (get_rom_byte(sqc.offset++) == 0xff) { if (sqc.loop) { if (sqc.loop != 255) --sqc.loop; - sqc.data = &m_rom[get_sqc_offs(sqc.sqc)]; + sqc.offset = get_sqc_offs(sqc.sqc); } else sqc.is_playing = false; } - else - sqc.data += 4; } if (sequence.is_playing) @@ -661,8 +659,8 @@ void ymz774_device::sequencer() } else { - int reg = *sequence.data++; - uint8_t data = *sequence.data++; + int reg = get_rom_byte(sequence.offset++); + uint8_t data = get_rom_byte(sequence.offset++); switch (reg) { case 0xff: // end @@ -673,8 +671,7 @@ void ymz774_device::sequencer() { if (sequence.loop != 255) --sequence.loop; - uint32_t pptr = get_seq_offs(sequence.sequence); - sequence.data = &m_rom[pptr]; + sequence.offset = get_seq_offs(sequence.sequence); } else { diff --git a/src/devices/sound/ymz770.h b/src/devices/sound/ymz770.h index 6723ac2bf1c..9fb38946dea 100644 --- a/src/devices/sound/ymz770.h +++ b/src/devices/sound/ymz770.h @@ -55,6 +55,7 @@ protected: virtual uint32_t get_phrase_offs(int phrase) { return m_rom[(4 * phrase) + 1] << 16 | m_rom[(4 * phrase) + 2] << 8 | m_rom[(4 * phrase) + 3]; }; virtual uint32_t get_seq_offs(int sqn) { return m_rom[(4 * sqn) + 1 + 0x400] << 16 | m_rom[(4 * sqn) + 2 + 0x400] << 8 | m_rom[(4 * sqn) + 3 + 0x400]; }; virtual void sequencer(); + uint8_t get_rom_byte(uint32_t offset) { return m_rom[offset % m_rom.bytes()]; }; // need optimise or its good as is ? ymz770_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t sclock); @@ -100,7 +101,7 @@ protected: uint16_t timer; uint16_t stopchan; uint8_t loop; - uint8_t *data; + uint32_t offset; uint8_t bank; bool is_playing; }; @@ -108,7 +109,7 @@ protected: { uint8_t sqc; uint8_t loop; - uint8_t *data; + uint32_t offset; bool is_playing; bool is_waiting; }; |