summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/acan.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/audio/acan.cpp')
-rw-r--r--src/mame/audio/acan.cpp234
1 files changed, 140 insertions, 94 deletions
diff --git a/src/mame/audio/acan.cpp b/src/mame/audio/acan.cpp
index 5f999368625..b881f2e65ac 100644
--- a/src/mame/audio/acan.cpp
+++ b/src/mame/audio/acan.cpp
@@ -22,9 +22,11 @@ acan_sound_device::acan_sound_device(const machine_config &mconfig, const char *
, device_sound_interface(mconfig, *this)
, m_stream(nullptr)
, m_timer(nullptr)
- , m_irq_handler(*this)
+ , m_timer_irq_handler(*this)
+ , m_dma_irq_handler(*this)
, m_ram_read(*this)
, m_active_channels(0)
+ , m_dma_channels(0)
{
}
@@ -35,11 +37,13 @@ void acan_sound_device::device_start()
m_mix = std::make_unique<int32_t[]>((clock() / 16 / 5) * 2);
m_timer = timer_alloc(0);
- m_irq_handler.resolve();
+ m_timer_irq_handler.resolve_safe();
+ m_dma_irq_handler.resolve_safe();
m_ram_read.resolve_safe(0);
// 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));
@@ -47,6 +51,7 @@ void acan_sound_device::device_start()
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));
@@ -58,19 +63,19 @@ void acan_sound_device::device_start()
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();
- if (!m_irq_handler.isnull())
- m_irq_handler(0);
+ m_timer_irq_handler(0);
+ m_dma_irq_handler(0);
}
void acan_sound_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
if (m_regs[0x14] & 0x40)
{
- if (!m_irq_handler.isnull())
- m_irq_handler(1);
+ m_timer_irq_handler(1);
// Update frequency
uint16_t period = (m_regs[0x12] << 8) + m_regs[0x11];
@@ -82,7 +87,7 @@ void acan_sound_device::sound_stream_update(sound_stream &stream, std::vector<re
{
std::fill_n(&m_mix[0], outputs[0].samples() * 2, 0);
- for (int i = 0; i < 15 && m_active_channels != 0; i++)
+ for (int i = 0; i < 16 && m_active_channels != 0; i++)
{
if (BIT(m_active_channels, i))
{
@@ -103,7 +108,12 @@ void acan_sound_device::sound_stream_update(sound_stream &stream, std::vector<re
if (channel.curr_addr >= channel.end_addr)
{
- if (channel.one_shot)
+ if (channel.register9)
+ {
+ m_dma_irq_handler(1);
+ keyon_voice(i);
+ }
+ else if (channel.one_shot)
{
m_active_channels &= ~(1 << i);
}
@@ -128,13 +138,28 @@ uint8_t acan_sound_device::read(offs_t offset)
{
if (offset == 0x14)
{
- // acknowledge timer (?)
- if (!m_irq_handler.isnull())
- m_irq_handler(0);
+ // 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;
@@ -144,107 +169,128 @@ void acan_sound_device::write(offs_t offset, uint8_t data)
switch (upper)
{
- case 0x1:
- if (lower == 0x7) // Keyon/keyoff
- {
- const uint16_t mask = 1 << (data & 0xf);
- if (data & 0xf0)
- m_active_channels |= mask;
- else
- m_active_channels &= ~mask;
- }
- else if (lower == 0x4) // Timer control
- {
- if (data & 0x80)
- {
- // Update frequency
- uint16_t period = (m_regs[0x12] << 8) + m_regs[0x11];
- m_timer->adjust(clocks_to_attotime(10 * (0x10000 - period)), 0);
- }
- // the meaning of the data that is actually written is unknown
- LOG("Sound timer control: %02x = %02x\n", offset, data);
- }
- else if (lower != 0x1 && lower != 0x2)
- {
- LOG("Unknown audio register: %02x = %02x\n", offset, data);
- }
+ 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: // Pitch (low byte)
- if (lower < 0xf)
- {
- acan_channel &channel = m_channels[lower];
- channel.pitch &= 0xff00;
- channel.pitch |= data;
- channel.addr_increment = (uint32_t)channel.pitch << 6;
- channel.frac = 0;
- }
+ case 0x2: // Timer frequency (high byte)
+ LOG("%s: Sound timer frequency (high byte) = %02x\n", machine().describe_context(), data);
break;
- case 0x3: // Pitch (high byte)
- if (lower < 0xf)
+ 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))
{
- acan_channel &channel = m_channels[lower];
- channel.pitch &= 0x00ff;
- channel.pitch |= data << 8;
- channel.addr_increment = (uint32_t)channel.pitch << 6;
- channel.frac = 0;
+ // Update frequency
+ uint16_t period = (m_regs[0x12] << 8) + m_regs[0x11];
+ m_timer->adjust(clocks_to_attotime(10 * (0x10000 - period)), 0);
}
break;
- case 0x5: // Waveform length
- if (lower < 0xf)
- {
- acan_channel &channel = m_channels[lower];
- //channel.length = (data & ~0x01) << 6;
- channel.length = (data & 0x0e) << 6; // Temporary hack to make jttlaugh audible. Not the proper fix!
- channel.end_addr = channel.curr_addr + channel.length;
- channel.one_shot = BIT(data, 0);
- }
+ 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 0x6: // Waveform address (divided by 0x40, high byte)
- if (lower < 0xf)
+ 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)
{
- acan_channel &channel = m_channels[lower];
- channel.start_addr &= 0x00ff;
- channel.start_addr |= data << 8;
- channel.curr_addr = channel.start_addr << 6;
- channel.end_addr = channel.curr_addr + channel.length;
+ keyon_voice(data & 0xf);
}
- break;
-
- case 0x7: // Waveform address (divided by 0x40, low byte)
- if (lower < 0xf)
+ else
{
- acan_channel &channel = m_channels[lower];
- channel.start_addr &= 0xff00;
- channel.start_addr |= data;
- channel.curr_addr = channel.start_addr << 6;
- channel.end_addr = channel.curr_addr + channel.length;
+ m_active_channels &= ~mask;
}
break;
+ }
- case 0xa: // Envelope Parameters? (not yet known)
- case 0xb:
- case 0xc:
- case 0xd:
- if (lower < 0xf)
- m_channels[lower].envelope[upper - 0xa] = data;
+ default:
+ LOG("Unknown sound register: %02x = %02x\n", offset, data);
break;
+ }
+ break;
- case 0xe: // Volume
- if (lower < 0xf)
- {
- acan_channel &channel = m_channels[lower];
- channel.volume = data;
- channel.volume_l = (data & 0xf0) | (data >> 4);
- channel.volume_r = (data & 0x0f) | (data << 4);
- }
- 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;
+ }
- default:
- LOG("Unknown audio register: %02x = %02x\n", offset, data);
- 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;
}
}