summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author mooglyguy <therealmogminer@gmail.com>2018-10-09 23:43:53 +0200
committer mooglyguy <therealmogminer@gmail.com>2018-10-09 23:44:04 +0200
commit61f191cce6c605b827e8f7eb8159708ad86a2249 (patch)
tree78630d6c0fe490063a3d7e7e46bb6206279db168
parent43a31bde96d299b83e6ea4214bf2ee298aea651d (diff)
spg2xx: Added rudimentary envelope support, needs more work. [Ryan Holtz]
-rw-r--r--src/devices/machine/spg2xx.cpp233
-rw-r--r--src/devices/machine/spg2xx.h18
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