diff options
Diffstat (limited to 'src/devices/machine/spg2xx_audio.cpp')
-rw-r--r-- | src/devices/machine/spg2xx_audio.cpp | 348 |
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; - } |