From 8e7642c070561bd39535b692703d6e911328c2c5 Mon Sep 17 00:00:00 2001 From: angelosa Date: Sun, 8 Sep 2024 19:18:44 +0200 Subject: funtech/acan: rename to umc6619_sound.cpp/.h, add minor notes --- src/mame/funtech/acan.cpp | 292 ----------------------------------- src/mame/funtech/acan.h | 70 --------- src/mame/funtech/supracan.cpp | 12 +- src/mame/funtech/umc6619_sound.cpp | 303 +++++++++++++++++++++++++++++++++++++ src/mame/funtech/umc6619_sound.h | 70 +++++++++ 5 files changed, 380 insertions(+), 367 deletions(-) delete mode 100644 src/mame/funtech/acan.cpp delete mode 100644 src/mame/funtech/acan.h create mode 100644 src/mame/funtech/umc6619_sound.cpp create mode 100644 src/mame/funtech/umc6619_sound.h diff --git a/src/mame/funtech/acan.cpp b/src/mame/funtech/acan.cpp deleted file mode 100644 index e92928695bc..00000000000 --- a/src/mame/funtech/acan.cpp +++ /dev/null @@ -1,292 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz, superctr -/*************************************************************************** - - Super A'Can sound driver - - Currently has a number of unknown registers and functionality. - -****************************************************************************/ - -#include "emu.h" -#include "acan.h" - -#define VERBOSE (0) -#include "logmacro.h" - -// device type definition -DEFINE_DEVICE_TYPE(ACANSND, acan_sound_device, "acansound", "Super A'Can Audio") - -acan_sound_device::acan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, ACANSND, tag, owner, clock) - , device_sound_interface(mconfig, *this) - , m_stream(nullptr) - , m_timer(nullptr) - , m_timer_irq_handler(*this) - , m_dma_irq_handler(*this) - , m_ram_read(*this, 0) - , m_active_channels(0) - , m_dma_channels(0) -{ -} - - -void acan_sound_device::device_start() -{ - m_stream = stream_alloc(0, 2, clock() / 16 / 5); - m_mix = std::make_unique((clock() / 16 / 5) * 2); - m_timer = timer_alloc(FUNC(acan_sound_device::channel_irq), this); - - // register for savestates - save_item(NAME(m_active_channels)); - save_item(NAME(m_dma_channels)); - save_item(STRUCT_MEMBER(m_channels, pitch)); - save_item(STRUCT_MEMBER(m_channels, length)); - save_item(STRUCT_MEMBER(m_channels, start_addr)); - save_item(STRUCT_MEMBER(m_channels, curr_addr)); - save_item(STRUCT_MEMBER(m_channels, end_addr)); - save_item(STRUCT_MEMBER(m_channels, addr_increment)); - save_item(STRUCT_MEMBER(m_channels, frac)); - save_item(STRUCT_MEMBER(m_channels, register9)); - save_item(STRUCT_MEMBER(m_channels, envelope)); - save_item(STRUCT_MEMBER(m_channels, volume)); - save_item(STRUCT_MEMBER(m_channels, volume_l)); - save_item(STRUCT_MEMBER(m_channels, volume_r)); - save_item(STRUCT_MEMBER(m_channels, one_shot)); - save_item(NAME(m_regs)); -} - -void acan_sound_device::device_reset() -{ - m_active_channels = 0; - m_dma_channels = 0; - std::fill(std::begin(m_regs), std::end(m_regs), 0); - - m_timer->reset(); - m_timer_irq_handler(0); - m_dma_irq_handler(0); -} - -TIMER_CALLBACK_MEMBER(acan_sound_device::channel_irq) -{ - if (m_regs[0x14] & 0x40) - { - m_timer_irq_handler(1); - - // Update frequency - uint16_t period = (m_regs[0x12] << 8) + m_regs[0x11]; - m_timer->adjust(clocks_to_attotime(10 * (0x10000 - period)), 0); - } -} - -void acan_sound_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) -{ - std::fill_n(&m_mix[0], outputs[0].samples() * 2, 0); - - for (int i = 0; i < 16 && m_active_channels != 0; i++) - { - if (BIT(m_active_channels, i)) - { - acan_channel &channel = m_channels[i]; - int32_t *mixp = &m_mix[0]; - - for (int s = 0; s < outputs[0].samples(); s++) - { - uint8_t data = m_ram_read(channel.curr_addr) + 0x80; - int16_t sample = (int16_t)(data << 8); - - channel.frac += channel.addr_increment; - channel.curr_addr += (uint16_t)(channel.frac >> 16); - channel.frac = (uint16_t)channel.frac; - - *mixp++ += (sample * channel.volume_l) >> 8; - *mixp++ += (sample * channel.volume_r) >> 8; - - if (channel.curr_addr >= channel.end_addr) - { - if (channel.register9) - { - m_dma_irq_handler(1); - keyon_voice(i); - } - else if (channel.one_shot) - { - m_active_channels &= ~(1 << i); - } - else - { - channel.curr_addr -= channel.length; - } - } - } - } - } - - int32_t *mixp = &m_mix[0]; - for (int i = 0; i < outputs[0].samples(); i++) - { - outputs[0].put_int(i, *mixp++, 32768 << 4); - outputs[1].put_int(i, *mixp++, 32768 << 4); - } -} - -uint8_t acan_sound_device::read(offs_t offset) -{ - if (offset == 0x14) - { - // acknowledge timer IRQ? - m_timer_irq_handler(0); - } - else if (offset == 0x16) - { - // acknowledge DMA IRQ? - m_dma_irq_handler(0); - } - return m_regs[offset]; -} - -void acan_sound_device::keyon_voice(uint8_t voice) -{ - acan_channel &channel = m_channels[voice]; - channel.curr_addr = channel.start_addr << 6; - channel.end_addr = channel.curr_addr + channel.length; - - m_active_channels |= (1 << voice); - - //printf("Keyon voice %d\n", voice); -} - -void acan_sound_device::write(offs_t offset, uint8_t data) -{ - const uint8_t upper = (offset >> 4) & 0x0f; - const uint8_t lower = offset & 0x0f; - - m_regs[offset] = data; - - switch (upper) - { - case 0x1: - switch (lower) - { - case 0x1: // Timer frequency (low byte) - LOG("%s: Sound timer frequency (low byte) = %02x\n", machine().describe_context(), data); - break; - - case 0x2: // Timer frequency (high byte) - LOG("%s: Sound timer frequency (high byte) = %02x\n", machine().describe_context(), data); - break; - - case 0x4: // Timer control - // The meaning of the data that is actually written is unknown - LOG("%s: Sound timer control = %02x\n", machine().describe_context(), data); - if (BIT(data, 7)) - { - // Update frequency - uint16_t period = (m_regs[0x12] << 8) + m_regs[0x11]; - m_timer->adjust(clocks_to_attotime(10 * (0x10000 - period)), 0); - } - break; - - case 0x6: // DMA-driven channel flags? - // The meaning of the data that is actually written is unknown - m_dma_channels = data << 8; - LOG("%s: DMA-driven channel flag(?) = %02x\n", machine().describe_context(), data); - break; - - case 0x7: // Keyon/keyoff - { - LOG("%s: Sound key control, voice %02x key%s\n", machine().describe_context(), data & 0xf, (data & 0xf0) ? "on" : "off"); - const uint16_t mask = 1 << (data & 0xf); - if (data & 0xf0) - { - keyon_voice(data & 0xf); - } - else - { - m_active_channels &= ~mask; - } - break; - } - - default: - LOG("Unknown sound register: %02x = %02x\n", offset, data); - break; - } - break; - - case 0x2: // Pitch (low byte) - { - acan_channel &channel = m_channels[lower]; - channel.pitch &= 0xff00; - channel.pitch |= data; - channel.addr_increment = (uint32_t)channel.pitch << 6; - break; - } - - case 0x3: // Pitch (high byte) - { - acan_channel &channel = m_channels[lower]; - channel.pitch &= 0x00ff; - channel.pitch |= data << 8; - channel.addr_increment = (uint32_t)channel.pitch << 6; - break; - } - - case 0x5: // Waveform length - { - acan_channel &channel = m_channels[lower]; - channel.length = 0x40 << ((data & 0x0e) >> 1); - channel.one_shot = BIT(data, 0); - LOG("%s: Waveform length and attributes (voice %02x): %02x\n", machine().describe_context(), lower, data); - break; - } - - case 0x6: // Waveform address (divided by 0x40, high byte) - { - acan_channel &channel = m_channels[lower]; - channel.start_addr &= 0x00ff; - channel.start_addr |= data << 8; - LOG("%s: Waveform address (high) (voice %02x): %02x, will be %04x\n", machine().describe_context(), lower, data, channel.start_addr << 6); - break; - } - - case 0x7: // Waveform address (divided by 0x40, low byte) - { - acan_channel &channel = m_channels[lower]; - channel.start_addr &= 0xff00; - channel.start_addr |= data; - LOG("%s: Waveform address (low) (voice %02x): %02x, will be %04x\n", machine().describe_context(), lower, data, channel.start_addr << 6); - break; - } - - case 0x9: // Unknown (set to 0xFF for DMA-driven channels) - { - acan_channel &channel = m_channels[lower]; - channel.register9 = data; - LOG("%s: Unknown voice register 9 (voice %02x): %02x\n", machine().describe_context(), lower, data); - break; - } - - case 0xa: // Envelope Parameters? (not yet known) - case 0xb: - case 0xc: - case 0xd: - m_channels[lower].envelope[upper - 0xa] = data; - LOG("%s: Envelope parameter %d (voice %02x) = %02x\n", machine().describe_context(), upper - 0xa, lower, data); - break; - - case 0xe: // Volume - { - acan_channel &channel = m_channels[lower]; - channel.volume = data; - channel.volume_l = (data & 0xf0) | (data >> 4); - channel.volume_r = (data & 0x0f) | (data << 4); - LOG("%s: Volume register (voice %02x) = = %02x\n", machine().describe_context(), lower, data); - break; - } - - default: - LOG("Unknown sound register: %02x = %02x\n", offset, data); - break; - } -} diff --git a/src/mame/funtech/acan.h b/src/mame/funtech/acan.h deleted file mode 100644 index 8828768219e..00000000000 --- a/src/mame/funtech/acan.h +++ /dev/null @@ -1,70 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz, superctr -/********************************************************************** - - Super A'Can sound driver - -**********************************************************************/ - -#ifndef MAME_FUNTECH_ACAN_H -#define MAME_FUNTECH_ACAN_H - -#pragma once - -class acan_sound_device : public device_t, public device_sound_interface -{ -public: - acan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - auto ram_read() { return m_ram_read.bind(); } - auto timer_irq_handler() { return m_timer_irq_handler.bind(); } - auto dma_irq_handler() { return m_dma_irq_handler.bind(); } - - uint8_t read(offs_t offset); - void write(offs_t offset, uint8_t data); - -protected: - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - - // sound stream update overrides - virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; - - TIMER_CALLBACK_MEMBER(channel_irq); - -private: - struct acan_channel - { - uint16_t pitch; - uint16_t length; - uint16_t start_addr; - uint16_t curr_addr; - uint16_t end_addr; - uint32_t addr_increment; - uint32_t frac; - uint8_t register9; - uint8_t envelope[4]; - uint8_t volume; - uint8_t volume_l; - uint8_t volume_r; - bool one_shot; - }; - - void keyon_voice(uint8_t voice); - - sound_stream *m_stream; - emu_timer *m_timer; - devcb_write_line m_timer_irq_handler; - devcb_write_line m_dma_irq_handler; - devcb_read8 m_ram_read; - uint16_t m_active_channels; - uint16_t m_dma_channels; - acan_channel m_channels[16]; - uint8_t m_regs[256]; - std::unique_ptr m_mix; -}; - -DECLARE_DEVICE_TYPE(ACANSND, acan_sound_device) - -#endif // MAME_FUNTECH_ACAN_H diff --git a/src/mame/funtech/supracan.cpp b/src/mame/funtech/supracan.cpp index a789b8f6de6..66e229f12e8 100644 --- a/src/mame/funtech/supracan.cpp +++ b/src/mame/funtech/supracan.cpp @@ -64,16 +64,18 @@ STATUS: **************************************************************************************************/ #include "emu.h" -#include "cpu/m68000/m68000.h" -#include "cpu/m6502/m65c02.h" + #include "bus/generic/slot.h" #include "bus/generic/carts.h" -#include "acan.h" +#include "cpu/m68000/m68000.h" +#include "cpu/m6502/m65c02.h" + #include "emupal.h" #include "screen.h" #include "softlist_dev.h" #include "speaker.h" #include "tilemap.h" +#include "umc6619_sound.h" #include "umc6650.h" #define LOG_UNKNOWNS (1U << 1) @@ -185,7 +187,7 @@ private: required_shared_ptr m_vram; required_shared_ptr m_soundram; - required_device m_sound; + required_device m_sound; required_device m_gfxdecode; required_device m_screen; @@ -2255,7 +2257,7 @@ void supracan_state::supracan(machine_config &config) SPEAKER(config, "rspeaker").front_right(); // TODO: derive and verify from U13_CLOCK - ACANSND(config, m_sound, XTAL(3'579'545)); + UMC6619_SOUND(config, m_sound, XTAL(3'579'545)); m_sound->ram_read().set(FUNC(supracan_state::sound_ram_read)); m_sound->timer_irq_handler().set(FUNC(supracan_state::sound_timer_irq)); m_sound->dma_irq_handler().set(FUNC(supracan_state::sound_dma_irq)); diff --git a/src/mame/funtech/umc6619_sound.cpp b/src/mame/funtech/umc6619_sound.cpp new file mode 100644 index 00000000000..bf847eb12c7 --- /dev/null +++ b/src/mame/funtech/umc6619_sound.cpp @@ -0,0 +1,303 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, superctr +/*************************************************************************** + + Super A'Can UMC 6619 sound driver + + Currently has a number of unknown registers and functionality. + +****************************************************************************/ + +#include "emu.h" +#include "umc6619_sound.h" + +#define VERBOSE (0) +#include "logmacro.h" + +// device type definition +DEFINE_DEVICE_TYPE(UMC6619_SOUND, umc6619_sound_device, "umc6619_sound", "UMC UM6619 Sound Engine") + +umc6619_sound_device::umc6619_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, UMC6619_SOUND, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , m_stream(nullptr) + , m_timer(nullptr) + , m_timer_irq_handler(*this) + , m_dma_irq_handler(*this) + , m_ram_read(*this, 0) + , m_active_channels(0) + , m_dma_channels(0) +{ +} + + +void umc6619_sound_device::device_start() +{ + m_stream = stream_alloc(0, 2, clock() / 16 / 5); + m_mix = std::make_unique((clock() / 16 / 5) * 2); + m_timer = timer_alloc(FUNC(umc6619_sound_device::channel_irq), this); + + // register for savestates + save_item(NAME(m_active_channels)); + save_item(NAME(m_dma_channels)); + save_item(STRUCT_MEMBER(m_channels, pitch)); + save_item(STRUCT_MEMBER(m_channels, length)); + save_item(STRUCT_MEMBER(m_channels, start_addr)); + save_item(STRUCT_MEMBER(m_channels, curr_addr)); + save_item(STRUCT_MEMBER(m_channels, end_addr)); + save_item(STRUCT_MEMBER(m_channels, addr_increment)); + save_item(STRUCT_MEMBER(m_channels, frac)); + save_item(STRUCT_MEMBER(m_channels, register9)); + save_item(STRUCT_MEMBER(m_channels, envelope)); + save_item(STRUCT_MEMBER(m_channels, volume)); + save_item(STRUCT_MEMBER(m_channels, volume_l)); + save_item(STRUCT_MEMBER(m_channels, volume_r)); + save_item(STRUCT_MEMBER(m_channels, one_shot)); + save_item(NAME(m_regs)); +} + +void umc6619_sound_device::device_reset() +{ + m_active_channels = 0; + m_dma_channels = 0; + std::fill(std::begin(m_regs), std::end(m_regs), 0); + + for (auto &channel : m_channels) + { + channel.register9 = 0; + } + + m_timer->reset(); + m_timer_irq_handler(0); + m_dma_irq_handler(0); +} + +TIMER_CALLBACK_MEMBER(umc6619_sound_device::channel_irq) +{ + if (m_regs[0x14] & 0x40) + { + m_timer_irq_handler(1); + + // Update frequency + uint16_t period = (m_regs[0x12] << 8) + m_regs[0x11]; + m_timer->adjust(clocks_to_attotime(10 * (0x10000 - period)), 0); + } +} + +void umc6619_sound_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) +{ + std::fill_n(&m_mix[0], outputs[0].samples() * 2, 0); + + for (int i = 0; i < 16 && m_active_channels != 0; i++) + { + if (BIT(m_active_channels, i)) + { + acan_channel &channel = m_channels[i]; + int32_t *mixp = &m_mix[0]; + + for (int s = 0; s < outputs[0].samples(); s++) + { + uint8_t data = m_ram_read(channel.curr_addr) + 0x80; + int16_t sample = (int16_t)(data << 8); + + channel.frac += channel.addr_increment; + channel.curr_addr += (uint16_t)(channel.frac >> 16); + channel.frac = (uint16_t)channel.frac; + + *mixp++ += (sample * channel.volume_l) >> 8; + *mixp++ += (sample * channel.volume_r) >> 8; + + if (channel.curr_addr >= channel.end_addr) + { + if (channel.register9) + { + m_dma_irq_handler(1); + keyon_voice(i); + } + else if (channel.one_shot) + { + m_active_channels &= ~(1 << i); + } + else + { + channel.curr_addr -= channel.length; + } + } + } + } + } + + int32_t *mixp = &m_mix[0]; + for (int i = 0; i < outputs[0].samples(); i++) + { + outputs[0].put_int(i, *mixp++, 32768 << 4); + outputs[1].put_int(i, *mixp++, 32768 << 4); + } +} + +uint8_t umc6619_sound_device::read(offs_t offset) +{ + if (offset == 0x14) + { + // acknowledge timer IRQ? + m_timer_irq_handler(0); + } + else if (offset == 0x16) + { + // acknowledge DMA IRQ? + m_dma_irq_handler(0); + } + // TODO: offset 0x15 (read by streaming DMAs) + return m_regs[offset]; +} + +void umc6619_sound_device::keyon_voice(uint8_t voice) +{ + acan_channel &channel = m_channels[voice]; + channel.curr_addr = channel.start_addr << 6; + channel.end_addr = channel.curr_addr + channel.length; + + m_active_channels |= (1 << voice); + + //printf("Keyon voice %d\n", voice); +} + +void umc6619_sound_device::write(offs_t offset, uint8_t data) +{ + const uint8_t upper = (offset >> 4) & 0x0f; + const uint8_t lower = offset & 0x0f; + + m_stream->update(); + m_regs[offset] = data; + + switch (upper) + { + case 0x1: + switch (lower) + { + case 0x1: // Timer frequency (low byte) + LOG("%s: Sound timer frequency (low byte) = %02x\n", machine().describe_context(), data); + break; + + case 0x2: // Timer frequency (high byte) + LOG("%s: Sound timer frequency (high byte) = %02x\n", machine().describe_context(), data); + break; + + case 0x4: // Timer control + // The meaning of the data that is actually written is unknown + LOG("%s: Sound timer control = %02x\n", machine().describe_context(), data); + if (BIT(data, 7)) + { + // Update frequency + uint16_t period = (m_regs[0x12] << 8) + m_regs[0x11]; + m_timer->adjust(clocks_to_attotime(10 * (0x10000 - period)), 0); + } + break; + + case 0x6: // DMA-driven channel flags? + // The meaning of the data that is actually written is unknown + m_dma_channels = data << 8; + LOG("%s: DMA-driven channel flag(?) = %02x\n", machine().describe_context(), data); + break; + + case 0x7: // Keyon/keyoff + { + LOG("%s: Sound key control, voice %02x key%s\n", machine().describe_context(), data & 0xf, (data & 0xf0) ? "on" : "off"); + const uint16_t mask = 1 << (data & 0xf); + if (data & 0xf0) + { + keyon_voice(data & 0xf); + } + else + { + m_active_channels &= ~mask; + } + break; + } + + default: + LOG("Unknown sound register: %02x = %02x\n", offset, data); + break; + } + break; + + case 0x2: // Pitch (low byte) + { + acan_channel &channel = m_channels[lower]; + channel.pitch &= 0xff00; + channel.pitch |= data; + channel.addr_increment = (uint32_t)channel.pitch << 6; + break; + } + + case 0x3: // Pitch (high byte) + { + acan_channel &channel = m_channels[lower]; + channel.pitch &= 0x00ff; + channel.pitch |= data << 8; + channel.addr_increment = (uint32_t)channel.pitch << 6; + break; + } + + case 0x5: // Waveform length + { + acan_channel &channel = m_channels[lower]; + channel.length = 0x40 << ((data & 0x0e) >> 1); + channel.one_shot = BIT(data, 0); + LOG("%s: Waveform length and attributes (voice %02x): %02x\n", machine().describe_context(), lower, data); + break; + } + + case 0x6: // Waveform address (divided by 0x40, high byte) + { + acan_channel &channel = m_channels[lower]; + channel.start_addr &= 0x00ff; + channel.start_addr |= data << 8; + LOG("%s: Waveform address (high) (voice %02x): %02x, will be %04x\n", machine().describe_context(), lower, data, channel.start_addr << 6); + break; + } + + case 0x7: // Waveform address (divided by 0x40, low byte) + { + acan_channel &channel = m_channels[lower]; + channel.start_addr &= 0xff00; + channel.start_addr |= data; + LOG("%s: Waveform address (low) (voice %02x): %02x, will be %04x\n", machine().describe_context(), lower, data, channel.start_addr << 6); + break; + } + + case 0x9: // Unknown (set to 0xFF for DMA-driven channels) + { + acan_channel &channel = m_channels[lower]; + channel.register9 = data; + LOG("%s: Unknown voice register 9 (voice %02x): %02x\n", machine().describe_context(), lower, data); + break; + } + + case 0xa: // Envelope Parameters? (not yet known) + case 0xb: + case 0xc: + case 0xd: + m_channels[lower].envelope[upper - 0xa] = data; + LOG("%s: Envelope parameter %d (voice %02x) = %02x\n", machine().describe_context(), upper - 0xa, lower, data); + break; + + case 0xe: // Volume + { + acan_channel &channel = m_channels[lower]; + channel.volume = data; + channel.volume_l = (data & 0xf0) | (data >> 4); + channel.volume_r = (data & 0x0f) | (data << 4); + LOG("%s: Volume register (voice %02x) = = %02x\n", machine().describe_context(), lower, data); + break; + } + + // case 4: + // Normally 0x03 for keyon channels, 0x01 for streaming DMAs + // (staiwbbl, formduel, sangofgt) + + default: + LOG("Unknown sound register: %02x = %02x\n", offset, data); + break; + } +} diff --git a/src/mame/funtech/umc6619_sound.h b/src/mame/funtech/umc6619_sound.h new file mode 100644 index 00000000000..d607735c7c9 --- /dev/null +++ b/src/mame/funtech/umc6619_sound.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, superctr +/********************************************************************** + + Super A'Can sound driver + +**********************************************************************/ + +#ifndef MAME_FUNTECH_UM6619_SOUND_H +#define MAME_FUNTECH_UM6619_SOUND_H + +#pragma once + +class umc6619_sound_device : public device_t, public device_sound_interface +{ +public: + umc6619_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto ram_read() { return m_ram_read.bind(); } + auto timer_irq_handler() { return m_timer_irq_handler.bind(); } + auto dma_irq_handler() { return m_dma_irq_handler.bind(); } + + uint8_t read(offs_t offset); + void write(offs_t offset, uint8_t data); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + + TIMER_CALLBACK_MEMBER(channel_irq); + +private: + struct acan_channel + { + uint16_t pitch; + uint16_t length; + uint16_t start_addr; + uint16_t curr_addr; + uint16_t end_addr; + uint32_t addr_increment; + uint32_t frac; + uint8_t register9; + uint8_t envelope[4]; + uint8_t volume; + uint8_t volume_l; + uint8_t volume_r; + bool one_shot; + }; + + void keyon_voice(uint8_t voice); + + sound_stream *m_stream; + emu_timer *m_timer; + devcb_write_line m_timer_irq_handler; + devcb_write_line m_dma_irq_handler; + devcb_read8 m_ram_read; + uint16_t m_active_channels; + uint16_t m_dma_channels; + acan_channel m_channels[16]; + uint8_t m_regs[256]; + std::unique_ptr m_mix; +}; + +DECLARE_DEVICE_TYPE(UMC6619_SOUND, umc6619_sound_device) + +#endif // MAME_FUNTECH_UM6619_SOUND_H -- cgit v1.2.3