diff options
author | mooglyguy <therealmogminer@gmail.com> | 2018-10-09 23:43:53 +0200 |
---|---|---|
committer | mooglyguy <therealmogminer@gmail.com> | 2018-10-09 23:44:04 +0200 |
commit | 61f191cce6c605b827e8f7eb8159708ad86a2249 (patch) | |
tree | 78630d6c0fe490063a3d7e7e46bb6206279db168 | |
parent | 43a31bde96d299b83e6ea4214bf2ee298aea651d (diff) |
spg2xx: Added rudimentary envelope support, needs more work. [Ryan Holtz]
-rw-r--r-- | src/devices/machine/spg2xx.cpp | 233 | ||||
-rw-r--r-- | src/devices/machine/spg2xx.h | 18 |
2 files changed, 221 insertions, 30 deletions
diff --git a/src/devices/machine/spg2xx.cpp b/src/devices/machine/spg2xx.cpp index b9d875a46bd..85b896bb4da 100644 --- a/src/devices/machine/spg2xx.cpp +++ b/src/devices/machine/spg2xx.cpp @@ -36,7 +36,9 @@ inline void spg2xx_device::verboselog(int n_level, const char *s_fmt, ...) } #define SPG_DEBUG_VIDEO (0) -#define SPG_DEBUG_AUDIO (1) +#define SPG_DEBUG_AUDIO (0) +#define SPG_DEBUG_ENVELOPES (0) +#define SPG_DEBUG_SAMPLES (0) #define IO_IRQ_ENABLE m_io_regs[0x21] #define IO_IRQ_STATUS m_io_regs[0x22] @@ -107,7 +109,7 @@ void spg2xx_device::device_start() m_screenpos_timer->adjust(attotime::never); m_audio_beat = timer_alloc(TIMER_BEAT); - m_audio_beat->adjust(attotime::from_ticks(4, 281250), 0, attotime::from_ticks(4, 281250)); + m_audio_beat->adjust(attotime::never); m_stream = stream_alloc(0, 2, 44100); } @@ -121,6 +123,8 @@ void spg2xx_device::device_reset() memset(m_channel_rate, 0, sizeof(double) * 6); memset(m_channel_rate_accum, 0, sizeof(double) * 6); memset(m_rampdown_frame, 0, sizeof(uint32_t) * 6); + memset(m_envclk_frame, 4, sizeof(uint32_t) * 6); + memset(m_envelope_addr, 0, sizeof(uint32_t) * 6); memset(m_video_regs, 0, 0x100 * sizeof(uint16_t)); memset(m_io_regs, 0, 0x200 * sizeof(uint16_t)); @@ -141,6 +145,8 @@ void spg2xx_device::device_reset() m_audio_regs[AUDIO_CHANNEL_REPEAT] = 0x3f; m_audio_regs[AUDIO_CHANNEL_ENV_MODE] = 0x3f; + + m_audio_beat->adjust(attotime::from_ticks(4, 281250), 0, attotime::from_ticks(4, 281250)); } @@ -523,7 +529,7 @@ WRITE16_MEMBER(spg2xx_device::video_w) verboselog(5, "video_w: Video IRQ Acknowledge = %04x (%04x)\n", data, mem_mask); const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS; VIDEO_IRQ_STATUS &= ~data; - verboselog(4, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS); + //verboselog(4, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS); const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS); if (changed) check_video_irq(); @@ -581,7 +587,7 @@ WRITE_LINE_MEMBER(spg2xx_device::vblank) const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS; VIDEO_IRQ_STATUS |= 1; - verboselog(4, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS); + verboselog(5, "Setting video IRQ status to %04x\n", VIDEO_IRQ_STATUS); const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS); if (changed) check_video_irq(); @@ -1030,7 +1036,7 @@ READ16_MEMBER(spg2xx_device::audio_r) break; case AUDIO_CHANNEL_STATUS: - verboselog(0, "audio_r: Channel Status: %04x\n", data); + verboselog(5, "audio_r: Channel Status: %04x\n", data); break; case AUDIO_WAVE_IN_L: @@ -1230,6 +1236,8 @@ WRITE16_MEMBER(spg2xx_device::audio_w) //printf("Stop not set, starting playback on channel %d, mask %04x\n", channel_bit, mask); m_audio_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, get_envelope_load(channel)); } m_adpcm[channel_bit].reset(); m_sample_shift[channel_bit] = 0; @@ -1284,14 +1292,55 @@ WRITE16_MEMBER(spg2xx_device::audio_w) } case AUDIO_ENVCLK: + { verboselog(0, "audio_w: Envelope Interval (lo): %04x\n", data); + const uint16_t old = m_audio_regs[offset]; m_audio_regs[offset] = data; + const uint16_t changed = old ^ m_audio_regs[offset]; + + if (!changed) + { + if (SPG_DEBUG_ENVELOPES) logerror("No change, %04x %04x %04x\n", old, data, m_audio_regs[offset]); + break; + } + + for (uint8_t channel_bit = 0; channel_bit < 4; channel_bit++) + { + const uint8_t shift = channel_bit << 2; + const uint16_t mask = 0x0f << shift; + if (changed & mask) + { + m_envclk_frame[channel_bit] = get_envclk_frame_count(channel_bit); + if (SPG_DEBUG_ENVELOPES) logerror("envclk_frame %d: %08x\n", channel_bit, m_envclk_frame[channel_bit]); + } + } break; + } case AUDIO_ENVCLK_HIGH: + { verboselog(0, "audio_w: Envelope Interval (hi): %04x\n", data); + const uint16_t old = m_audio_regs[offset]; m_audio_regs[offset] = data & AUDIO_ENVCLK_HIGH_MASK; + const uint16_t changed = old ^ m_audio_regs[offset]; + if (!changed) + { + if (SPG_DEBUG_ENVELOPES) logerror("No change, %04x %04x %04x\n", old, data, m_audio_regs[offset]); + break; + } + + for (uint8_t channel_bit = 0; channel_bit < 2; channel_bit++) + { + const uint8_t shift = channel_bit << 2; + const uint16_t mask = 0x0f << shift; + if (changed & mask) + { + m_envclk_frame[channel_bit + 4] = get_envclk_frame_count(channel_bit); + if (SPG_DEBUG_ENVELOPES) logerror("envclk_frame %d: %08x\n", channel_bit + 4, m_envclk_frame[channel_bit + 4]); + } + } break; + } case AUDIO_ENV_RAMP_DOWN: { @@ -1576,7 +1625,6 @@ void spg2xx_device::sound_stream_update(sound_stream &stream, stream_sample_t ** for (uint32_t ch_index = 0; ch_index < 6; ch_index++) { - // TODO: Envelopes, volume, panning if (!get_channel_status(ch_index)) { continue; @@ -1597,8 +1645,7 @@ void spg2xx_device::sound_stream_update(sound_stream &stream, stream_sample_t ** sample += prev_sample; } - if (get_envelope_enable(ch_index)) - sample = (sample * (int16_t)get_edd(ch_index)) >> 7; + sample = (sample * (int16_t)get_edd(ch_index)) >> 7; active_count++; @@ -1727,14 +1774,14 @@ bool spg2xx_device::fetch_sample(address_space &space, const uint32_t channel) { if (tone_mode == AUDIO_TONE_MODE_HW_ONESHOT) { - //printf("ADPCM stopped after %d samples\n", m_sample_count[channel]); + if (SPG_DEBUG_SAMPLES) logerror("ADPCM stopped after %d samples\n", m_sample_count[channel]); m_sample_count[channel] = 0; stop_channel(channel); return false; } else { - //printf("ADPCM looping after %d samples\n", m_sample_count[channel]); + if (SPG_DEBUG_SAMPLES) logerror("ADPCM looping after %d samples\n", m_sample_count[channel]); m_sample_count[channel] = 0; loop_channel(channel); } @@ -1748,14 +1795,14 @@ bool spg2xx_device::fetch_sample(address_space &space, const uint32_t channel) { if (tone_mode == AUDIO_TONE_MODE_HW_ONESHOT) { - //printf("16-bit PCM stopped after %d samples\n", m_sample_count[channel]); + if (SPG_DEBUG_SAMPLES) logerror("16-bit PCM stopped after %d samples\n", m_sample_count[channel]); m_sample_count[channel] = 0; stop_channel(channel); return false; } else { - //printf("16-bit PCM looping after %d samples\n", m_sample_count[channel]); + if (SPG_DEBUG_SAMPLES) logerror("16-bit PCM looping after %d samples\n", m_sample_count[channel]); m_sample_count[channel] = 0; loop_channel(channel); } @@ -1776,14 +1823,14 @@ bool spg2xx_device::fetch_sample(address_space &space, const uint32_t channel) { if (tone_mode == AUDIO_TONE_MODE_HW_ONESHOT) { - //printf("8-bit PCM stopped after %d samples\n", m_sample_count[channel]); + if (SPG_DEBUG_SAMPLES) logerror("8-bit PCM stopped after %d samples\n", m_sample_count[channel]); m_sample_count[channel] = 0; stop_channel(channel); return false; } else { - //printf("8-bit PCM looping after %d samples\n", m_sample_count[channel]); + if (SPG_DEBUG_SAMPLES) logerror("8-bit PCM looping after %d samples\n", m_sample_count[channel]); m_sample_count[channel] = 0; loop_channel(channel); } @@ -1806,20 +1853,40 @@ void spg2xx_device::audio_frame_tick() { audio_beat_tick(); - if (!m_audio_regs[AUDIO_ENV_RAMP_DOWN]) - return; - + address_space &space = m_cpu->space(AS_PROGRAM); for (uint32_t channel = 0; channel < 6; channel++) { const uint16_t mask = (1 << channel); - if (!(m_audio_regs[AUDIO_ENV_RAMP_DOWN] & mask)) + if (!(m_audio_regs[AUDIO_CHANNEL_STATUS] & mask)) + { + if (SPG_DEBUG_ENVELOPES) printf("Skipping channel 4 due to status\n"); continue; + } - m_rampdown_frame[channel]--; - if (m_rampdown_frame[channel] == 0) + if (m_audio_regs[AUDIO_ENV_RAMP_DOWN] & mask) + { + m_rampdown_frame[channel]--; + if (m_rampdown_frame[channel] == 0) + { + //printf("Ticking rampdown for channel %d\n", channel); + audio_rampdown_tick(channel); + continue; + } + } + + if (!(m_audio_regs[AUDIO_CHANNEL_ENV_MODE] & mask)) + { + m_envclk_frame[channel]--; + if (m_envclk_frame[channel] == 0) + { + if (SPG_DEBUG_ENVELOPES) logerror("Ticking envelope for channel %d\n", channel); + audio_envelope_tick(space, channel); + m_envclk_frame[channel] = get_envclk_frame_count(channel); + } + } + else if (SPG_DEBUG_ENVELOPES) { - //printf("Ticking rampdown for channel %d\n", channel); - audio_rampdown_tick(channel); + logerror("Not ticking envelope for channel %d\n", channel); } } } @@ -1864,7 +1931,7 @@ void spg2xx_device::audio_rampdown_tick(const uint32_t channel) if (new_edd) { - //printf("Channel %d preparing for next rampdown step (%02x)\n", channel, new_edd); + if (SPG_DEBUG_ENVELOPES) logerror("Channel %d preparing for next rampdown step (%02x)\n", channel, new_edd); const uint16_t channel_mask = channel << 4; m_audio_regs[channel_mask | AUDIO_ENVELOPE_DATA] &= ~AUDIO_EDD_MASK; m_audio_regs[channel_mask | AUDIO_ENVELOPE_DATA] |= new_edd & AUDIO_EDD_MASK; @@ -1872,7 +1939,7 @@ void spg2xx_device::audio_rampdown_tick(const uint32_t channel) } else { - //printf("Stopping channel %d due to rampdown\n", channel); + if (SPG_DEBUG_ENVELOPES) logerror("Stopping channel %d due to rampdown\n", channel); const uint16_t channel_mask = 1 << channel; m_audio_regs[AUDIO_CHANNEL_ENABLE] &= ~channel_mask; m_audio_regs[AUDIO_CHANNEL_STATUS] &= ~channel_mask; @@ -1882,15 +1949,125 @@ void spg2xx_device::audio_rampdown_tick(const uint32_t channel) } } +const uint32_t spg2xx_device::s_rampdown_frame_counts[8] = +{ + 13*4, 13*16, 13*64, 13*256, 13*1024, 13*4096, 13*8192, 13*8192 +}; + uint32_t spg2xx_device::get_rampdown_frame_count(const uint32_t channel) { - const uint16_t rampdown_clock = get_rampdown_clock(channel); - if (rampdown_clock >= 6) + return s_rampdown_frame_counts[get_rampdown_clock(channel)]; +} + +const uint32_t spg2xx_device::s_envclk_frame_counts[16] = +{ + 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 8192, 8192, 8192, 8192 +}; + +uint32_t spg2xx_device::get_envclk_frame_count(const uint32_t channel) +{ + return s_envclk_frame_counts[get_envelope_clock(channel)]; +} + +uint32_t spg2xx_device::get_envelope_clock(const offs_t channel) const +{ + if (channel < 4) + return (m_audio_regs[AUDIO_ENVCLK] >> (channel << 2)) & 0x000f; + else + return (m_audio_regs[AUDIO_ENVCLK_HIGH] >> ((channel - 4) << 2)) & 0x000f; +} + +void spg2xx_device::audio_envelope_tick(address_space &space, const uint32_t channel) +{ + const uint16_t channel_mask = channel << 4; + uint16_t new_count = get_envelope_count(channel); + const uint16_t curr_edd = get_edd(channel); + if (SPG_DEBUG_ENVELOPES) logerror("envelope %d tick, count is %04x, curr edd is %04x\n", channel, new_count, curr_edd); + if (new_count == 0) { - return 13 * 8192; + const uint16_t target = get_envelope_target(channel); + uint16_t new_edd = curr_edd; + const uint16_t inc = get_envelope_inc(channel); + + if (new_edd != target) + { + if (get_envelope_sign_bit(channel)) + { + new_edd -= inc; + if (SPG_DEBUG_ENVELOPES) logerror("Envelope %d new EDD-: %04x (%04x), dec %04x\n", channel, new_edd, target, inc); + if (new_edd > curr_edd) + new_edd = 0; + else if (new_edd < target) + new_edd = target; + + if (new_edd == 0) + { + if (SPG_DEBUG_ENVELOPES) logerror("Envelope %d at 0, stopping channel\n", channel); + stop_channel(channel); + return; + } + } + else + { + new_edd += inc; + if (SPG_DEBUG_ENVELOPES) logerror("Envelope %d new EDD+: %04x\n", channel, new_edd); + if (new_edd >= target) + new_edd = target; + } + } + + if (new_edd == target) + { + if (SPG_DEBUG_ENVELOPES) logerror("Envelope %d at target %04x\n", channel, target); + new_edd = target; + + if (get_envelope_repeat_bit(channel)) + { + const uint16_t repeat_count = get_envelope_repeat_count(channel) - 1; + if (SPG_DEBUG_ENVELOPES) logerror("Repeating envelope, new repeat count %d\n", repeat_count); + if (repeat_count == 0) + { + m_audio_regs[channel_mask | AUDIO_ENVELOPE0] = space.read_word(m_envelope_addr[channel]); + m_audio_regs[channel_mask | AUDIO_ENVELOPE1] = space.read_word(m_envelope_addr[channel] + 1); + m_audio_regs[channel_mask | AUDIO_ENVELOPE_LOOP_CTRL] = space.read_word(m_envelope_addr[channel] + 2); + m_envelope_addr[channel] = get_envelope_addr(channel) + get_envelope_eaoffset(channel); + if (SPG_DEBUG_ENVELOPES) logerror("Envelope data after repeat: %04x %04x %04x (%08x)\n", m_audio_regs[channel_mask | AUDIO_ENVELOPE0], m_audio_regs[channel_mask | AUDIO_ENVELOPE1], m_audio_regs[channel_mask | AUDIO_ENVELOPE_LOOP_CTRL], m_envelope_addr[channel]); + } + else + { + set_envelope_repeat_count(channel, repeat_count); + } + } + else + { + if (SPG_DEBUG_ENVELOPES) logerror("Fetching envelope for channel %d from %08x\n", channel, m_envelope_addr[channel]); + m_audio_regs[channel_mask | AUDIO_ENVELOPE0] = space.read_word(m_envelope_addr[channel]); + m_audio_regs[channel_mask | AUDIO_ENVELOPE1] = space.read_word(m_envelope_addr[channel] + 1); + if (SPG_DEBUG_ENVELOPES) logerror("Fetched envelopes %04x %04x\n", m_audio_regs[channel_mask | AUDIO_ENVELOPE0], m_audio_regs[channel_mask | AUDIO_ENVELOPE1]); + m_envelope_addr[channel] += 2; + } + // FIXME: This makes things sound markedly worse even though the docs indicate + // the envelope count should be reloaded by the envelope load register! Why? + //set_envelope_count(channel, get_envelope_load(channel)); + } + else + { + if (SPG_DEBUG_ENVELOPES) logerror("Envelope %d not yet at target %04x (%04x)\n", channel, target, new_edd); + // FIXME: This makes things sound markedly worse even though the docs indicate + // the envelope count should be reloaded by the envelope load register! So instead, + // we just reload with zero, which at least keeps the channels going. Why? + //new_count = get_envelope_load(channel); + set_envelope_count(channel, new_count); + } + if (SPG_DEBUG_ENVELOPES) logerror("Envelope %d new count %04x\n", channel, new_count); + + set_edd(channel, new_edd); + if (SPG_DEBUG_ENVELOPES) logerror("Setting channel %d edd to %04x, register is %04x\n", channel, new_edd, m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA]); } else { - return 13 * (4 << (rampdown_clock * 2)); + new_count--; + set_envelope_count(channel, new_count); } + if (SPG_DEBUG_ENVELOPES) logerror("envelope %d post-tick, count is now %04x, register is %04x\n", channel, new_count, m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA]); }
\ No newline at end of file diff --git a/src/devices/machine/spg2xx.h b/src/devices/machine/spg2xx.h index b0044418a83..36f13acd058 100644 --- a/src/devices/machine/spg2xx.h +++ b/src/devices/machine/spg2xx.h @@ -75,12 +75,16 @@ protected: void audio_frame_tick(); void audio_beat_tick(); void audio_rampdown_tick(const uint32_t channel); - uint32_t get_rampdown_frame_count(const uint32_t channel); + void audio_envelope_tick(address_space &space, const uint32_t channel); + inline uint32_t get_rampdown_frame_count(const uint32_t channel); + inline uint32_t get_envclk_frame_count(const uint32_t channel); // Audio getters inline bool get_channel_enable(const offs_t channel) const { return m_audio_regs[AUDIO_CHANNEL_ENABLE] & (1 << channel); } inline bool get_channel_status(const offs_t channel) const { return m_audio_regs[AUDIO_CHANNEL_STATUS] & (1 << channel); } - inline bool get_envelope_enable(const offs_t channel) const { return m_audio_regs[AUDIO_CHANNEL_ENV_MODE] & (1 << channel); } + inline bool get_manual_envelope_enable(const offs_t channel) const { return m_audio_regs[AUDIO_CHANNEL_ENV_MODE] & (1 << channel); } + inline bool get_auto_envelope_enable(const offs_t channel) const { return !get_manual_envelope_enable(channel); } + uint32_t get_envelope_clock(const offs_t channel) const; // Audio Mode getters inline uint16_t get_wave_addr_high(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_MODE] & AUDIO_WADDR_HIGH_MASK; } @@ -102,11 +106,14 @@ protected: // Audio Envelope Data getters inline uint16_t get_edd(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] & AUDIO_EDD_MASK; } inline uint16_t get_envelope_count(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] & AUDIO_ENVELOPE_COUNT_MASK) >> AUDIO_ENVELOPE_COUNT_SHIFT; } + inline void set_edd(const offs_t channel, uint8_t edd) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] = (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] & ~AUDIO_EDD_MASK) | edd; } + inline void set_envelope_count(const offs_t channel, uint16_t count) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_DATA] = get_edd(channel) | (count << AUDIO_ENVELOPE_COUNT_SHIFT); } // Audio Envelope1 Data getters inline uint16_t get_envelope_load(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & AUDIO_ENVELOPE_LOAD_MASK; } inline uint16_t get_envelope_repeat_bit(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & AUDIO_ENVELOPE_RPT_MASK) ? 1 : 0; } inline uint16_t get_envelope_repeat_count(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & AUDIO_ENVELOPE_RPCNT_MASK) >> AUDIO_ENVELOPE_RPCNT_SHIFT; } + inline void set_envelope_repeat_count(const offs_t channel, const uint16_t count) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] = (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE1] & ~AUDIO_ENVELOPE_RPCNT_MASK) | ((count << AUDIO_ENVELOPE_RPCNT_SHIFT) & AUDIO_ENVELOPE_RPCNT_MASK); } // Audio Envelope Address getters inline uint16_t get_envelope_addr_high(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR_HIGH] & AUDIO_EADDR_HIGH_MASK; } @@ -116,6 +123,7 @@ protected: // Audio Envelope Loop getters inline uint16_t get_envelope_eaoffset(const offs_t channel) const { return m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] & AUDIO_EAOFFSET_MASK; } inline uint16_t get_rampdown_offset(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] & AUDIO_RAMPDOWN_OFFSET_MASK) >> AUDIO_RAMPDOWN_OFFSET_SHIFT; } + inline void set_envelope_eaoffset(const offs_t channel, uint16_t eaoffset) { m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] = (m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_LOOP_CTRL] & ~AUDIO_RAMPDOWN_OFFSET_MASK) | (eaoffset & AUDIO_EAOFFSET_MASK); } // Audio ADPCM getters inline uint16_t get_point_number(const offs_t channel) const { return (m_audio_regs[(channel << 4) | AUDIO_ADPCM_SEL] & AUDIO_POINT_NUMBER_MASK) >> AUDIO_POINT_NUMBER_SHIFT; } @@ -138,6 +146,7 @@ protected: inline uint32_t get_target_phase(const offs_t channel) const { return ((uint32_t)get_target_phase_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_TARGET_PHASE]; } inline uint32_t get_wave_addr(const offs_t channel) const { return ((uint32_t)get_wave_addr_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_WAVE_ADDR]; } inline uint32_t get_loop_addr(const offs_t channel) const { return ((uint32_t)get_loop_addr_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_LOOP_ADDR]; } + inline uint32_t get_envelope_addr(const offs_t channel) const { return ((uint32_t)get_envelope_addr_high(channel) << 16) | m_audio_regs[(channel << 4) | AUDIO_ENVELOPE_ADDR]; } enum { @@ -402,6 +411,8 @@ protected: double m_channel_rate[6]; double m_channel_rate_accum[6]; uint32_t m_rampdown_frame[6]; + uint32_t m_envclk_frame[6]; + uint32_t m_envelope_addr[6]; uint16_t m_audio_curr_beat_base_count; uint16_t m_video_regs[0x100]; @@ -434,6 +445,9 @@ protected: required_shared_ptr<uint16_t> m_scrollram; required_shared_ptr<uint16_t> m_paletteram; required_shared_ptr<uint16_t> m_spriteram; + + static const uint32_t s_rampdown_frame_counts[8]; + static const uint32_t s_envclk_frame_counts[16]; }; class spg24x_device : public spg2xx_device |