spg2xx: Added rudimentary envelope support, needs more work. [Ryan Holtz]

This commit is contained in:
mooglyguy 2018-10-09 23:43:53 +02:00
parent 43a31bde96
commit 61f191cce6
2 changed files with 223 additions and 32 deletions

View File

@ -36,7 +36,9 @@ inline void spg2xx_device::verboselog(int n_level, const char *s_fmt, ...)
} }
#define SPG_DEBUG_VIDEO (0) #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_ENABLE m_io_regs[0x21]
#define IO_IRQ_STATUS m_io_regs[0x22] #define IO_IRQ_STATUS m_io_regs[0x22]
@ -107,7 +109,7 @@ void spg2xx_device::device_start()
m_screenpos_timer->adjust(attotime::never); m_screenpos_timer->adjust(attotime::never);
m_audio_beat = timer_alloc(TIMER_BEAT); 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); 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, 0, sizeof(double) * 6);
memset(m_channel_rate_accum, 0, sizeof(double) * 6); memset(m_channel_rate_accum, 0, sizeof(double) * 6);
memset(m_rampdown_frame, 0, sizeof(uint32_t) * 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_video_regs, 0, 0x100 * sizeof(uint16_t));
memset(m_io_regs, 0, 0x200 * 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_REPEAT] = 0x3f;
m_audio_regs[AUDIO_CHANNEL_ENV_MODE] = 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); verboselog(5, "video_w: Video IRQ Acknowledge = %04x (%04x)\n", data, mem_mask);
const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS; const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS;
VIDEO_IRQ_STATUS &= ~data; 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); const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS);
if (changed) if (changed)
check_video_irq(); check_video_irq();
@ -581,7 +587,7 @@ WRITE_LINE_MEMBER(spg2xx_device::vblank)
const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS; const uint16_t old = VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS;
VIDEO_IRQ_STATUS |= 1; 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); const uint16_t changed = old ^ (VIDEO_IRQ_ENABLE & VIDEO_IRQ_STATUS);
if (changed) if (changed)
check_video_irq(); check_video_irq();
@ -1030,7 +1036,7 @@ READ16_MEMBER(spg2xx_device::audio_r)
break; break;
case AUDIO_CHANNEL_STATUS: case AUDIO_CHANNEL_STATUS:
verboselog(0, "audio_r: Channel Status: %04x\n", data); verboselog(5, "audio_r: Channel Status: %04x\n", data);
break; break;
case AUDIO_WAVE_IN_L: 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); //printf("Stop not set, starting playback on channel %d, mask %04x\n", channel_bit, mask);
m_audio_regs[AUDIO_CHANNEL_STATUS] |= mask; m_audio_regs[AUDIO_CHANNEL_STATUS] |= mask;
m_sample_addr[channel_bit] = get_wave_addr(channel_bit); 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_adpcm[channel_bit].reset();
m_sample_shift[channel_bit] = 0; m_sample_shift[channel_bit] = 0;
@ -1284,14 +1292,55 @@ WRITE16_MEMBER(spg2xx_device::audio_w)
} }
case AUDIO_ENVCLK: case AUDIO_ENVCLK:
{
verboselog(0, "audio_w: Envelope Interval (lo): %04x\n", data); verboselog(0, "audio_w: Envelope Interval (lo): %04x\n", data);
const uint16_t old = m_audio_regs[offset];
m_audio_regs[offset] = data; 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; 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: case AUDIO_ENVCLK_HIGH:
{
verboselog(0, "audio_w: Envelope Interval (hi): %04x\n", data); 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; 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; 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: 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++) for (uint32_t ch_index = 0; ch_index < 6; ch_index++)
{ {
// TODO: Envelopes, volume, panning
if (!get_channel_status(ch_index)) if (!get_channel_status(ch_index))
{ {
continue; continue;
@ -1597,7 +1645,6 @@ void spg2xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **
sample += prev_sample; 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++; 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) 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; m_sample_count[channel] = 0;
stop_channel(channel); stop_channel(channel);
return false; return false;
} }
else 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; m_sample_count[channel] = 0;
loop_channel(channel); 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) 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; m_sample_count[channel] = 0;
stop_channel(channel); stop_channel(channel);
return false; return false;
} }
else 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; m_sample_count[channel] = 0;
loop_channel(channel); 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) 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; m_sample_count[channel] = 0;
stop_channel(channel); stop_channel(channel);
return false; return false;
} }
else 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; m_sample_count[channel] = 0;
loop_channel(channel); loop_channel(channel);
} }
@ -1806,20 +1853,40 @@ void spg2xx_device::audio_frame_tick()
{ {
audio_beat_tick(); audio_beat_tick();
if (!m_audio_regs[AUDIO_ENV_RAMP_DOWN]) address_space &space = m_cpu->space(AS_PROGRAM);
return;
for (uint32_t channel = 0; channel < 6; channel++) for (uint32_t channel = 0; channel < 6; channel++)
{ {
const uint16_t mask = (1 << 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; continue;
}
if (m_audio_regs[AUDIO_ENV_RAMP_DOWN] & mask)
{
m_rampdown_frame[channel]--; m_rampdown_frame[channel]--;
if (m_rampdown_frame[channel] == 0) if (m_rampdown_frame[channel] == 0)
{ {
//printf("Ticking rampdown for channel %d\n", channel); //printf("Ticking rampdown for channel %d\n", channel);
audio_rampdown_tick(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)
{
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) 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; 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] &= ~AUDIO_EDD_MASK;
m_audio_regs[channel_mask | AUDIO_ENVELOPE_DATA] |= new_edd & 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 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; const uint16_t channel_mask = 1 << channel;
m_audio_regs[AUDIO_CHANNEL_ENABLE] &= ~channel_mask; m_audio_regs[AUDIO_CHANNEL_ENABLE] &= ~channel_mask;
m_audio_regs[AUDIO_CHANNEL_STATUS] &= ~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) uint32_t spg2xx_device::get_rampdown_frame_count(const uint32_t channel)
{ {
const uint16_t rampdown_clock = get_rampdown_clock(channel); return s_rampdown_frame_counts[get_rampdown_clock(channel)];
if (rampdown_clock >= 6) }
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 else
{ {
return 13 * (4 << (rampdown_clock * 2)); 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
{
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]);
} }

View File

@ -75,12 +75,16 @@ protected:
void audio_frame_tick(); void audio_frame_tick();
void audio_beat_tick(); void audio_beat_tick();
void audio_rampdown_tick(const uint32_t channel); 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 // 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_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_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 // 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; } 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 // 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_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 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 // 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_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_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 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 // 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; } 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 // 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_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 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 // 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; } 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_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_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_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 enum
{ {
@ -402,6 +411,8 @@ protected:
double m_channel_rate[6]; double m_channel_rate[6];
double m_channel_rate_accum[6]; double m_channel_rate_accum[6];
uint32_t m_rampdown_frame[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_audio_curr_beat_base_count;
uint16_t m_video_regs[0x100]; uint16_t m_video_regs[0x100];
@ -434,6 +445,9 @@ protected:
required_shared_ptr<uint16_t> m_scrollram; required_shared_ptr<uint16_t> m_scrollram;
required_shared_ptr<uint16_t> m_paletteram; required_shared_ptr<uint16_t> m_paletteram;
required_shared_ptr<uint16_t> m_spriteram; 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 class spg24x_device : public spg2xx_device