summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/spg2xx_audio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/spg2xx_audio.cpp')
-rw-r--r--src/devices/machine/spg2xx_audio.cpp348
1 files changed, 256 insertions, 92 deletions
diff --git a/src/devices/machine/spg2xx_audio.cpp b/src/devices/machine/spg2xx_audio.cpp
index 3fb15b07213..05fea0b4724 100644
--- a/src/devices/machine/spg2xx_audio.cpp
+++ b/src/devices/machine/spg2xx_audio.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Ryan Holtz
+// copyright-holders:Ryan Holtz,Jonathan Gevaryahu
/*****************************************************************************
SunPlus SPG2xx-series SoC peripheral emulation (Audio)
@@ -10,7 +10,7 @@
or at least not per-channel)
SPG110 Beat interrupt frequency might be different too, seems to
- trigger an FIQ, but music is very slow in jak_spdmo
+ trigger an IRQ, but music is very slow in jak_spdmo
GCM394 has 32 channels, and potentially a different register layout
it looks close but might be different enough to split off
@@ -24,15 +24,15 @@ DEFINE_DEVICE_TYPE(SPG2XX_AUDIO, spg2xx_audio_device, "spg2xx_audio", "SPG2xx-se
DEFINE_DEVICE_TYPE(SPG110_AUDIO, spg110_audio_device, "spg110_audio", "SPG110-series System-on-a-Chip Audio")
DEFINE_DEVICE_TYPE(SUNPLUS_GCM394_AUDIO, sunplus_gcm394_audio_device, "gcm394_audio", "SunPlus GCM394 System-on-a-Chip (Audio)")
-#define LOG_SPU_READS (1U << 0)
-#define LOG_SPU_WRITES (1U << 1)
-#define LOG_UNKNOWN_SPU (1U << 2)
-#define LOG_CHANNEL_READS (1U << 3)
-#define LOG_CHANNEL_WRITES (1U << 4)
-#define LOG_ENVELOPES (1U << 5)
-#define LOG_SAMPLES (1U << 6)
-#define LOG_RAMPDOWN (1U << 7)
-#define LOG_BEAT (1U << 8)
+#define LOG_SPU_READS (1U << 1)
+#define LOG_SPU_WRITES (1U << 2)
+#define LOG_UNKNOWN_SPU (1U << 3)
+#define LOG_CHANNEL_READS (1U << 4)
+#define LOG_CHANNEL_WRITES (1U << 5)
+#define LOG_ENVELOPES (1U << 6)
+#define LOG_SAMPLES (1U << 7)
+#define LOG_RAMPDOWN (1U << 8)
+#define LOG_BEAT (1U << 9)
#define LOG_ALL (LOG_SPU_READS | LOG_SPU_WRITES | LOG_UNKNOWN_SPU | LOG_CHANNEL_READS | LOG_CHANNEL_WRITES \
| LOG_ENVELOPES | LOG_SAMPLES | LOG_RAMPDOWN | LOG_BEAT)
@@ -41,13 +41,18 @@ DEFINE_DEVICE_TYPE(SUNPLUS_GCM394_AUDIO, sunplus_gcm394_audio_device, "gcm394_au
#include "logmacro.h"
#define SPG_DEBUG_AUDIO (0)
+#define SPG_LOG_ADPCM36 (0)
+#if SPG_LOG_ADPCM36
+static FILE *adpcm_file[16] = {};
+#endif
spg2xx_audio_device::spg2xx_audio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, device_sound_interface(mconfig, *this)
- , m_space_read_cb(*this)
+ , m_space_read_cb(*this, 0)
, m_irq_cb(*this)
+ , m_ch_irq_cb(*this)
{
}
@@ -66,10 +71,9 @@ sunplus_gcm394_audio_device::sunplus_gcm394_audio_device(const machine_config &m
{
}
-
void spg2xx_audio_device::device_start()
{
- m_audio_beat = timer_alloc(TIMER_BEAT);
+ m_audio_beat = timer_alloc(FUNC(spg2xx_audio_device::audio_beat_tick), this);
m_audio_beat->adjust(attotime::never);
m_stream = stream_alloc(0, 2, 281250/4);
@@ -85,7 +89,6 @@ void spg2xx_audio_device::device_start()
save_item(NAME(m_sample_shift));
save_item(NAME(m_sample_count));
- save_item(NAME(m_sample_addr));
save_item(NAME(m_channel_rate));
save_item(NAME(m_channel_rate_accum));
save_item(NAME(m_rampdown_frame));
@@ -94,15 +97,18 @@ void spg2xx_audio_device::device_start()
save_item(NAME(m_channel_debug));
save_item(NAME(m_audio_curr_beat_base_count));
-
for (int i = 0; i < 16; i++)
{
save_item(NAME(m_adpcm[i].m_signal), i);
save_item(NAME(m_adpcm[i].m_step), i);
- }
+ save_item(NAME(m_adpcm36_state[i].m_header), i);
+ save_item(NAME(m_adpcm36_state[i].m_prevsamp), i);
+
+ memset(m_adpcm36_state + i, 0, sizeof(adpcm36_state));
- m_space_read_cb.resolve_safe(0);
- m_irq_cb.resolve();
+ m_channel_irq[i] = timer_alloc(FUNC(spg2xx_audio_device::irq_tick), this);
+ m_channel_irq[i]->adjust(attotime::never);
+ }
}
void spg2xx_audio_device::device_reset()
@@ -113,7 +119,6 @@ void spg2xx_audio_device::device_reset()
memset(m_sample_shift, 0, 16);
memset(m_sample_count, 0, sizeof(uint32_t) * 16);
- memset(m_sample_addr, 0, sizeof(uint32_t) * 16);
memset(m_channel_rate, 0, sizeof(double) * 16);
memset(m_channel_rate_accum, 0, sizeof(double) * 16);
memset(m_rampdown_frame, 0, sizeof(uint32_t) * 16);
@@ -128,16 +133,32 @@ void spg2xx_audio_device::device_reset()
m_audio_ctrl_regs[AUDIO_CHANNEL_ENV_MODE] = 0x3f;
m_audio_beat->adjust(attotime::from_ticks(4, 281250), 0, attotime::from_ticks(4, 281250));
+
+ for (int i = 0; i < 16; i++)
+ {
+ m_channel_irq[i]->adjust(attotime::never);
+ }
}
+void spg2xx_audio_device::device_stop()
+{
+#if SPG_LOG_ADPCM36
+ for (int i = 0; i < 16; i++)
+ {
+ if (adpcm_file[i])
+ {
+ fclose(adpcm_file[i]);
+ }
+ }
+#endif
+}
-void spg2xx_audio_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(spg2xx_audio_device::irq_tick)
{
- switch (id)
+ if (!BIT(m_audio_ctrl_regs[AUDIO_CHANNEL_FIQ_STATUS], param))
{
- case TIMER_BEAT:
- audio_beat_tick();
- break;
+ m_audio_ctrl_regs[AUDIO_CHANNEL_FIQ_STATUS] |= (1 << param);
+ m_ch_irq_cb(1);
}
}
@@ -161,7 +182,7 @@ void spg2xx_audio_device::check_irqs(const uint16_t changed)
}
}
-READ16_MEMBER(spg2xx_audio_device::audio_ctrl_r)
+uint16_t spg2xx_audio_device::audio_ctrl_r(offs_t offset)
{
uint16_t data = m_audio_ctrl_regs[offset];
@@ -293,7 +314,7 @@ READ16_MEMBER(spg2xx_audio_device::audio_ctrl_r)
return data;
}
-READ16_MEMBER(spg2xx_audio_device::audio_r)
+uint16_t spg2xx_audio_device::audio_r(offs_t offset)
{
const uint16_t channel = (offset & 0x01f0) >> 4;
uint16_t data = m_audio_regs[offset];
@@ -371,7 +392,7 @@ READ16_MEMBER(spg2xx_audio_device::audio_r)
}
-READ16_MEMBER(spg2xx_audio_device::audio_phase_r)
+uint16_t spg2xx_audio_device::audio_phase_r(offs_t offset)
{
const uint16_t channel = (offset & 0x01f0) >> 4;
uint16_t data = m_audio_phase_regs[offset];
@@ -419,14 +440,16 @@ READ16_MEMBER(spg2xx_audio_device::audio_phase_r)
return data;
}
-WRITE16_MEMBER(spg2xx_audio_device::audio_ctrl_w)
+void spg2xx_audio_device::audio_ctrl_w(offs_t offset, uint16_t data)
{
switch (offset)
{
case AUDIO_CHANNEL_ENABLE:
{
LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Enable: %04x\n", data);
- const uint16_t changed = m_audio_ctrl_regs[AUDIO_CHANNEL_ENABLE] ^ data;
+ const uint16_t old = m_audio_ctrl_regs[offset];
+ m_audio_ctrl_regs[offset] = data;
+ const uint16_t changed = old ^ m_audio_ctrl_regs[offset];
for (uint32_t channel_bit = 0; channel_bit < 16; channel_bit++)
{
const uint16_t mask = 1 << channel_bit;
@@ -435,30 +458,24 @@ WRITE16_MEMBER(spg2xx_audio_device::audio_ctrl_w)
if (data & mask)
{
+ LOGMASKED(LOG_SPU_WRITES, "Enabling channel %d, rate %f\n", channel_bit, m_channel_rate[channel_bit]);
+ if (m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] & mask)
+ continue;
+
if (!(m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] & mask))
{
- LOGMASKED(LOG_SPU_WRITES, "Enabling channel %d\n", channel_bit);
- m_audio_ctrl_regs[offset] |= mask;
- if (!(m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] & mask))
- {
- LOGMASKED(LOG_SPU_WRITES, "Stop not set, starting playback on channel %d, mask %04x\n", channel_bit, mask);
- m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] |= mask;
- m_sample_addr[channel_bit] = get_wave_addr(channel_bit);
- m_envelope_addr[channel_bit] = get_envelope_addr(channel_bit);
- set_envelope_count(channel_bit, get_envelope_load(channel_bit));
- }
- m_adpcm[channel_bit].reset();
- m_sample_shift[channel_bit] = 0;
- m_sample_count[channel_bit] = 0;
+ LOGMASKED(LOG_SPU_WRITES, "Stop not set, starting playback on channel %d, mask %04x\n", channel_bit, mask);
+ start_channel(channel_bit);
}
}
else
{
- stop_channel(channel_bit);
- //m_audio_ctrl_regs[offset] &= ~mask;
- //m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] &= ~mask;
- //m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] |= mask;
- //m_audio_ctrl_regs[AUDIO_CHANNEL_TONE_RELEASE] &= ~mask;
+ LOGMASKED(LOG_SPU_WRITES, "Disabling channel %d\n", channel_bit);
+ if (m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] & mask)
+ {
+ LOGMASKED(LOG_SPU_WRITES, "Stopping channel %d\n", channel_bit);
+ stop_channel(channel_bit);
+ }
}
}
break;
@@ -476,7 +493,12 @@ WRITE16_MEMBER(spg2xx_audio_device::audio_ctrl_w)
case AUDIO_CHANNEL_FIQ_STATUS:
LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel FIQ Acknowledge: %04x\n", data);
+ //machine().debug_break();
m_audio_ctrl_regs[offset] &= ~(data & AUDIO_CHANNEL_FIQ_STATUS_MASK);
+ if (!m_audio_ctrl_regs[offset])
+ {
+ m_ch_irq_cb(0);
+ }
break;
case AUDIO_BEAT_BASE_COUNT:
@@ -570,9 +592,29 @@ WRITE16_MEMBER(spg2xx_audio_device::audio_ctrl_w)
}
case AUDIO_CHANNEL_STOP:
+ {
LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Stop Status: %04x\n", data);
+ const uint16_t old = m_audio_ctrl_regs[offset];
m_audio_ctrl_regs[offset] &= ~data;
+ const uint16_t changed = old ^ m_audio_ctrl_regs[offset];
+ for (uint32_t channel_bit = 0; channel_bit < 16; channel_bit++)
+ {
+ const uint16_t mask = 1 << channel_bit;
+ if (!(changed & mask))
+ continue;
+
+ LOGMASKED(LOG_SPU_WRITES, "Clearing stop status of channel %d, rate %f\n", channel_bit, m_channel_rate[channel_bit]);
+ if (!(m_audio_ctrl_regs[AUDIO_CHANNEL_ENABLE] & mask))
+ continue;
+
+ if (!(m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] & mask))
+ {
+ LOGMASKED(LOG_SPU_WRITES, "Enable set, starting playback on channel %d, mask %04x\n", channel_bit, mask);
+ start_channel(channel_bit);
+ }
+ }
break;
+ }
case AUDIO_CHANNEL_ZERO_CROSS:
LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Channel Zero-Cross Enable: %04x\n", data);
@@ -601,11 +643,13 @@ WRITE16_MEMBER(spg2xx_audio_device::audio_ctrl_w)
case AUDIO_WAVE_IN_L:
LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Wave In (L) / FIFO Write Data: %04x\n", data);
+ m_stream->update();
m_audio_ctrl_regs[offset] = data;
break;
case AUDIO_WAVE_IN_R:
LOGMASKED(LOG_SPU_WRITES, "audio_ctrl_w: Wave In (R) / Software Channel FIFO IRQ Control: %04x\n", data);
+ m_stream->update();
m_audio_ctrl_regs[offset] = data;
break;
@@ -681,7 +725,7 @@ WRITE16_MEMBER(spg2xx_audio_device::audio_ctrl_w)
}
}
-WRITE16_MEMBER(spg2xx_audio_device::audio_phase_w)
+void spg2xx_audio_device::audio_phase_w(offs_t offset, uint16_t data)
{
const uint16_t channel = (offset & 0x01f0) >> 4;
@@ -740,7 +784,7 @@ WRITE16_MEMBER(spg2xx_audio_device::audio_phase_w)
}
-WRITE16_MEMBER(spg2xx_audio_device::audio_w)
+void spg2xx_audio_device::audio_w(offs_t offset, uint16_t data)
{
const uint16_t channel = (offset & 0x01f0) >> 4;
@@ -827,12 +871,9 @@ WRITE16_MEMBER(spg2xx_audio_device::audio_w)
}
}
-void spg2xx_audio_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void spg2xx_audio_device::sound_stream_update(sound_stream &stream)
{
- stream_sample_t *out_l = outputs[0];
- stream_sample_t *out_r = outputs[1];
-
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < stream.samples(); i++)
{
int32_t left_total = 0;
int32_t right_total = 0;
@@ -882,26 +923,39 @@ void spg2xx_audio_device::sound_stream_update(sound_stream &stream, stream_sampl
const uint16_t mask = (1 << channel);
if (m_audio_ctrl_regs[AUDIO_ENV_RAMP_DOWN] & mask)
{
+ if (m_rampdown_frame[channel] > 0)
+ {
+ m_rampdown_frame[channel]--;
+ }
+
if (m_rampdown_frame[channel] == 0)
{
LOGMASKED(LOG_RAMPDOWN, "Ticking rampdown for channel %d\n", channel);
audio_rampdown_tick(channel);
}
- m_rampdown_frame[channel]--;
}
else if (!(m_audio_ctrl_regs[AUDIO_CHANNEL_ENV_MODE] & mask))
{
+ if (m_envclk_frame[channel] > 0)
+ {
+ m_envclk_frame[channel]--;
+ }
+
if (m_envclk_frame[channel] == 0)
{
LOGMASKED(LOG_ENVELOPES, "Ticking envelope for channel %d\n", channel);
audio_envelope_tick(channel);
m_envclk_frame[channel] = get_envclk_frame_count(channel);
}
- m_envclk_frame[channel]--;
}
}
}
+ if (m_audio_ctrl_regs[AUDIO_WAVE_IN_L])
+ left_total += (int32_t)(m_audio_ctrl_regs[AUDIO_WAVE_IN_L] - 0x8000);
+ if (m_audio_ctrl_regs[AUDIO_WAVE_IN_R])
+ right_total += (int32_t)(m_audio_ctrl_regs[AUDIO_WAVE_IN_R] - 0x8000);
+
switch (get_vol_sel())
{
case 0: // 1/16
@@ -915,19 +969,54 @@ void spg2xx_audio_device::sound_stream_update(sound_stream &stream, stream_sampl
right_total >>= 2;
break;
}
- *out_l++ = (left_total * (int16_t)m_audio_ctrl_regs[AUDIO_MAIN_VOLUME]) >> 7;
- *out_r++ = (right_total * (int16_t)m_audio_ctrl_regs[AUDIO_MAIN_VOLUME]) >> 7;
+
+ int32_t left_final = (int16_t)((left_total * (int16_t)m_audio_ctrl_regs[AUDIO_MAIN_VOLUME]) >> 7);
+ int32_t right_final = (int16_t)((right_total * (int16_t)m_audio_ctrl_regs[AUDIO_MAIN_VOLUME]) >> 7);
+
+ stream.put_int(0, i, int16_t(left_final), 32768);
+ stream.put_int(1, i, int16_t(right_final), 32768);
+ }
+}
+
+inline void spg2xx_audio_device::start_channel(const uint32_t channel)
+{
+ if (BIT(m_audio_ctrl_regs[AUDIO_CHANNEL_FIQ_ENABLE], channel))
+ {
+ m_channel_irq[channel]->adjust(attotime::from_hz(m_channel_rate[channel]), channel, attotime::from_hz(m_channel_rate[channel]));
+ }
+ else
+ {
+ m_channel_irq[channel]->adjust(attotime::never);
+ }
+
+ m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] |= (1 << channel);
+ m_envelope_addr[channel] = get_envelope_addr(channel);
+ set_envelope_count(channel, get_envelope_load(channel));
+
+ m_adpcm[channel].reset();
+ m_sample_shift[channel] = 0;
+ m_sample_count[channel] = 0;
+
+ if (get_adpcm36_bit(channel))
+ {
+ memset(m_adpcm36_state + channel, 0, sizeof(adpcm36_state));
}
}
inline void spg2xx_audio_device::stop_channel(const uint32_t channel)
{
- // TODO: IRQs
- m_audio_ctrl_regs[AUDIO_CHANNEL_ENABLE] &= ~(1 << channel);
m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] &= ~(1 << channel);
m_audio_regs[(channel << 4) | AUDIO_MODE] &= ~AUDIO_ADPCM_MASK;
m_audio_ctrl_regs[AUDIO_CHANNEL_TONE_RELEASE] &= ~(1 << channel);
m_audio_ctrl_regs[AUDIO_ENV_RAMP_DOWN] &= ~(1 << channel);
+ m_channel_irq[channel]->adjust(attotime::never);
+#if SPG_LOG_ADPCM36
+ if (get_adpcm36_bit(channel))
+ {
+ fclose(adpcm_file[channel]);
+ adpcm_file[channel] = nullptr;
+ }
+#endif
}
bool spg2xx_audio_device::advance_channel(const uint32_t channel)
@@ -951,20 +1040,24 @@ bool spg2xx_audio_device::advance_channel(const uint32_t channel)
if (!playing)
break;
- if (get_adpcm_bit(channel))
+ if (get_adpcm_bit(channel) || get_adpcm36_bit(channel))
{
// ADPCM mode
m_sample_shift[channel] += 4;
if (m_sample_shift[channel] >= 16)
{
m_sample_shift[channel] = 0;
- m_sample_addr[channel]++;
+ inc_wave_addr(channel);
+ if (get_adpcm36_bit(channel))
+ {
+ m_adpcm36_state[channel].m_remaining--;
+ }
}
}
else if (get_16bit_bit(channel))
{
// 16-bit mode
- m_sample_addr[channel]++;
+ inc_wave_addr(channel);
}
else
{
@@ -973,7 +1066,7 @@ bool spg2xx_audio_device::advance_channel(const uint32_t channel)
if (m_sample_shift[channel] >= 16)
{
m_sample_shift[channel] = 0;
- m_sample_addr[channel]++;
+ inc_wave_addr(channel);
}
}
}
@@ -986,6 +1079,40 @@ uint16_t spg2xx_audio_device::read_space(offs_t offset)
return m_space_read_cb(offset);
}
+uint16_t spg2xx_audio_device::decode_adpcm36_nybble(const uint32_t channel, const uint8_t data)
+{
+ /*static const int8_t s_filter_coef[16][2] =
+ {
+ { 0, 0 },
+ { 60, 0 },
+ { 115,-52 },
+ { 98,-55 },
+ { 122,-60 },
+ { 122,-60 },
+ { 122,-60 },
+ { 122,-60 },
+ { 0, 0 },
+ { 60, 0 },
+ { 115,-52 },
+ { 98,-55 },
+ { 122,-60 },
+ { 122,-60 },
+ { 122,-60 },
+ { 122,-60 },
+ };*/
+
+ adpcm36_state &state = m_adpcm36_state[channel];
+ int32_t shift = state.m_header & 0xf;
+ int16_t filter = (state.m_header & 0x3f0) >> 4;
+ int16_t f0 = filter | ((filter & 0x20) ? ~0x3f : 0); // sign extend
+ int32_t f1 = 0;
+ int16_t sdata = data << 12;
+ sdata = (sdata >> shift) + (((state.m_prevsamp[0] * f0) + (state.m_prevsamp[1] * f1) + 32) >> 12);
+ state.m_prevsamp[1] = state.m_prevsamp[0];
+ state.m_prevsamp[0] = sdata;
+ return (uint16_t)sdata ^ 0x8000;
+}
+
bool spg2xx_audio_device::fetch_sample(const uint32_t channel)
{
const uint32_t channel_mask = channel << 4;
@@ -993,11 +1120,39 @@ bool spg2xx_audio_device::fetch_sample(const uint32_t channel)
const uint32_t wave_data_reg = channel_mask | AUDIO_WAVE_DATA;
const uint16_t tone_mode = get_tone_mode(channel);
- uint16_t raw_sample = tone_mode ? read_space(m_sample_addr[channel]) : m_audio_regs[wave_data_reg];
- LOGMASKED(LOG_SAMPLES, "Channel %d: Raw sample %04x\n", channel, raw_sample);
+ if (get_adpcm36_bit(channel) && tone_mode != 0 && m_adpcm36_state[channel].m_remaining == 0)
+ {
+ m_adpcm36_state[channel].m_header = read_space(get_wave_addr(channel));
+ m_adpcm36_state[channel].m_remaining = 8;
+ inc_wave_addr(channel);
+ }
+
+ uint16_t raw_sample = tone_mode ? read_space(get_wave_addr(channel)) : m_audio_regs[wave_data_reg];
- if (get_adpcm_bit(channel))
+#if SPG_LOG_ADPCM36
+ if (get_adpcm36_bit(channel))
+ {
+ static int adpcm_file_counts[16] = {};
+
+ if (adpcm_file[channel] == nullptr)
+ {
+ char file_buf[256];
+ snprintf(file_buf, 256, "adpcm36_chan%d_%d.bin", channel, adpcm_file_counts[channel]);
+ adpcm_file[channel] = fopen(file_buf, "wb");
+ }
+ static int blah[16] = {};
+ if ((blah[channel] & 3) == 0)
+ {
+ LOGMASKED(LOG_SAMPLES, "Channel %d: Raw sample %04x\n", channel, raw_sample);
+ fwrite(&raw_sample, sizeof(uint16_t), 1, adpcm_file[channel]);
+ }
+ blah[channel]++;
+ blah[channel] &= 3;
+ }
+#endif
+
+ if (get_adpcm_bit(channel) || get_adpcm36_bit(channel))
{
// ADPCM mode
if (tone_mode != 0 && raw_sample == 0xffff)
@@ -1006,6 +1161,7 @@ bool spg2xx_audio_device::fetch_sample(const uint32_t channel)
{
LOGMASKED(LOG_SAMPLES, "ADPCM stopped after %d samples\n", m_sample_count[channel]);
m_sample_count[channel] = 0;
+ m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] |= (1 << channel);
stop_channel(channel);
return false;
}
@@ -1022,7 +1178,10 @@ bool spg2xx_audio_device::fetch_sample(const uint32_t channel)
m_audio_regs[wave_data_reg] = raw_sample;
m_audio_regs[wave_data_reg] >>= m_sample_shift[channel];
const uint8_t adpcm_sample = (uint8_t)(m_audio_regs[wave_data_reg] & 0x000f);
- m_audio_regs[wave_data_reg] = (uint16_t)(m_adpcm[channel].clock(adpcm_sample) << 4) ^ 0x8000;
+ if (get_adpcm36_bit(channel))
+ m_audio_regs[wave_data_reg] = decode_adpcm36_nybble(channel, adpcm_sample);
+ else
+ m_audio_regs[wave_data_reg] = (uint16_t)(m_adpcm[channel].clock(adpcm_sample)) ^ 0x8000;
}
m_sample_count[channel]++;
}
@@ -1069,6 +1228,7 @@ bool spg2xx_audio_device::fetch_sample(const uint32_t channel)
{
LOGMASKED(LOG_SAMPLES, "Channel %d: 8-bit PCM stopped after %d samples\n", channel, m_sample_count[channel]);
m_sample_count[channel] = 0;
+ m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] |= (1 << channel);
stop_channel(channel);
return false;
}
@@ -1092,19 +1252,31 @@ bool spg2xx_audio_device::fetch_sample(const uint32_t channel)
inline void spg2xx_audio_device::loop_channel(const uint32_t channel)
{
- m_sample_addr[channel] = get_loop_addr(channel);
+ set_wave_addr(channel, get_loop_addr(channel));
m_sample_shift[channel] = 0;
- LOGMASKED(LOG_SAMPLES, "Channel %d: Looping to address %08x\n", channel, m_sample_addr[channel]);
+ LOGMASKED(LOG_SAMPLES, "Channel %d: Looping to address %08x\n", channel, get_wave_addr(channel));
}
-void spg2xx_audio_device::audio_beat_tick()
+TIMER_CALLBACK_MEMBER(spg2xx_audio_device::audio_beat_tick)
{
+ if (m_audio_curr_beat_base_count > 0)
+ {
+ m_audio_curr_beat_base_count--;
+ }
+
if (m_audio_curr_beat_base_count == 0)
{
LOGMASKED(LOG_BEAT, "Beat base count elapsed, reloading with %d\n", m_audio_ctrl_regs[AUDIO_BEAT_BASE_COUNT]);
m_audio_curr_beat_base_count = m_audio_ctrl_regs[AUDIO_BEAT_BASE_COUNT];
uint16_t beat_count = m_audio_ctrl_regs[AUDIO_BEAT_COUNT] & AUDIO_BEAT_COUNT_MASK;
+
+ if (beat_count > 0)
+ {
+ beat_count--;
+ m_audio_ctrl_regs[AUDIO_BEAT_COUNT] = (m_audio_ctrl_regs[AUDIO_BEAT_COUNT] & ~AUDIO_BEAT_COUNT_MASK) | beat_count;
+ }
+
if (beat_count == 0)
{
if (m_audio_ctrl_regs[AUDIO_BEAT_COUNT] & AUDIO_BIE_MASK)
@@ -1118,13 +1290,7 @@ void spg2xx_audio_device::audio_beat_tick()
LOGMASKED(LOG_BEAT, "Beat count elapsed but IRQ not enabled\n");
}
}
- else
- {
- beat_count--;
- m_audio_ctrl_regs[AUDIO_BEAT_COUNT] = (m_audio_ctrl_regs[AUDIO_BEAT_COUNT] & ~AUDIO_BEAT_COUNT_MASK) | beat_count;
- }
}
- m_audio_curr_beat_base_count--;
}
void spg2xx_audio_device::audio_rampdown_tick(const uint32_t channel)
@@ -1146,11 +1312,8 @@ void spg2xx_audio_device::audio_rampdown_tick(const uint32_t channel)
{
LOGMASKED(LOG_RAMPDOWN, "Stopping channel %d due to rampdown\n", channel);
const uint16_t channel_mask = 1 << channel;
- m_audio_ctrl_regs[AUDIO_CHANNEL_ENABLE] &= ~channel_mask;
- m_audio_ctrl_regs[AUDIO_CHANNEL_STATUS] &= ~channel_mask;
m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] |= channel_mask;
- m_audio_ctrl_regs[AUDIO_ENV_RAMP_DOWN] &= ~channel_mask;
- m_audio_ctrl_regs[AUDIO_CHANNEL_TONE_RELEASE] &= ~channel_mask;
+ stop_channel(channel);
}
}
@@ -1193,6 +1356,12 @@ bool spg2xx_audio_device::audio_envelope_tick(const uint32_t channel)
const uint16_t curr_edd = get_edd(channel);
LOGMASKED(LOG_ENVELOPES, "envelope %d tick, count is %04x, curr edd is %04x\n", channel, new_count, curr_edd);
bool edd_changed = false;
+ if (new_count > 0)
+ {
+ new_count--;
+ set_envelope_count(channel, new_count);
+ }
+
if (new_count == 0)
{
const uint16_t target = get_envelope_target(channel);
@@ -1213,6 +1382,7 @@ bool spg2xx_audio_device::audio_envelope_tick(const uint32_t channel)
if (new_edd == 0)
{
LOGMASKED(LOG_ENVELOPES, "Envelope %d at 0, stopping channel\n", channel);
+ m_audio_ctrl_regs[AUDIO_CHANNEL_STOP] |= (1 << channel);
stop_channel(channel);
return true;
}
@@ -1271,18 +1441,13 @@ bool spg2xx_audio_device::audio_envelope_tick(const uint32_t channel)
edd_changed = true;
LOGMASKED(LOG_ENVELOPES, "Setting channel %d edd to %04x, register is %04x\n", channel, new_edd, m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA]);
}
- else
- {
- new_count--;
- set_envelope_count(channel, new_count);
- }
LOGMASKED(LOG_ENVELOPES, "envelope %d post-tick, count is now %04x, register is %04x\n", channel, new_count, m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA]);
return edd_changed;
}
-WRITE16_MEMBER(spg110_audio_device::audio_w)
+void spg110_audio_device::audio_w(offs_t offset, uint16_t data)
{
const uint16_t channel = (offset & 0x00f0) >> 4;
@@ -1296,7 +1461,7 @@ WRITE16_MEMBER(spg110_audio_device::audio_w)
return;
}
- spg2xx_audio_device::audio_w(space,offset,data,mem_mask);
+ spg2xx_audio_device::audio_w(offset,data);
}
uint16_t sunplus_gcm394_audio_device::control_group16_r(uint8_t group, uint8_t offset)
@@ -1313,13 +1478,13 @@ void sunplus_gcm394_audio_device::control_group16_w(uint8_t group, uint8_t offse
// offset 0x0b = triggers?
}
-READ16_MEMBER(sunplus_gcm394_audio_device::control_r)
+uint16_t sunplus_gcm394_audio_device::control_r(offs_t offset)
{
return control_group16_r(offset & 0x20 ? 1 : 0, offset & 0x1f);
}
-WRITE16_MEMBER(sunplus_gcm394_audio_device::control_w)
+void sunplus_gcm394_audio_device::control_w(offs_t offset, uint16_t data)
{
control_group16_w(offset & 0x20 ? 1 : 0, offset & 0x1f, data);
}
@@ -1331,5 +1496,4 @@ void sunplus_gcm394_audio_device::device_start()
for (int i = 0; i < 2; i++)
for (int j = 0; j < 0x20; j++)
m_control[i][j] = 0x0000;
-
}