summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/devices/sound/gb.cpp685
-rw-r--r--src/devices/sound/gb.h36
2 files changed, 353 insertions, 368 deletions
diff --git a/src/devices/sound/gb.cpp b/src/devices/sound/gb.cpp
index 6a683a21313..81541884162 100644
--- a/src/devices/sound/gb.cpp
+++ b/src/devices/sound/gb.cpp
@@ -63,12 +63,12 @@ TODO:
/* Represents wave duties of 12.5%, 25%, 50% and 75% */
-const int gameboy_sound_device::wave_duty_table[4][8] =
+const int gameboy_sound_device::wave_duty_table[4] =
{
- { -1, -1, -1, -1, -1, -1, -1, 1},
- { 1, -1, -1, -1, -1, -1, -1, 1},
- { 1, -1, -1, -1, -1, 1, 1, 1},
- { -1, 1, 1, 1, 1, 1, 1, -1}
+ 0b10000000,
+ 0b10000001,
+ 0b11100001,
+ 0b01111110
};
// device type definitions
@@ -117,41 +117,6 @@ agb_apu_device::agb_apu_device(const machine_config &mconfig, const char *tag, d
// device_start - device-specific startup
//-------------------------------------------------
-#define SAVE_CHANNEL(snd) \
- save_item(NAME(snd.reg)); \
- save_item(NAME(snd.on)); \
- save_item(NAME(snd.channel)); \
- save_item(NAME(snd.length)); \
- save_item(NAME(snd.length_mask)); \
- save_item(NAME(snd.length_counting)); \
- save_item(NAME(snd.length_enabled)); \
- save_item(NAME(snd.cycles_left)); \
- save_item(NAME(snd.duty)); \
- save_item(NAME(snd.envelope_enabled)); \
- save_item(NAME(snd.envelope_value)); \
- save_item(NAME(snd.envelope_direction)); \
- save_item(NAME(snd.envelope_time)); \
- save_item(NAME(snd.envelope_count)); \
- save_item(NAME(snd.signal)); \
- save_item(NAME(snd.frequency)); \
- save_item(NAME(snd.frequency_counter)); \
- save_item(NAME(snd.sweep_enabled)); \
- save_item(NAME(snd.sweep_neg_mode_used)); \
- save_item(NAME(snd.sweep_shift)); \
- save_item(NAME(snd.sweep_direction)); \
- save_item(NAME(snd.sweep_time)); \
- save_item(NAME(snd.sweep_count)); \
- save_item(NAME(snd.size)); \
- save_item(NAME(snd.bank)); \
- save_item(NAME(snd.level)); \
- save_item(NAME(snd.offset)); \
- save_item(NAME(snd.duty_count)); \
- save_item(NAME(snd.current_sample)); \
- save_item(NAME(snd.sample_reading)); \
- save_item(NAME(snd.noise_short)); \
- save_item(NAME(snd.noise_lfsr));
-
-
void gameboy_sound_device::device_start()
{
m_channel = stream_alloc(0, 2, SAMPLE_RATE_OUTPUT_ADAPTIVE);
@@ -165,20 +130,43 @@ void gameboy_sound_device::device_start()
save_item(NAME(m_snd_control.on));
save_item(NAME(m_snd_control.vol_left));
save_item(NAME(m_snd_control.vol_right));
- save_item(NAME(m_snd_control.mode1_left));
- save_item(NAME(m_snd_control.mode1_right));
- save_item(NAME(m_snd_control.mode2_left));
- save_item(NAME(m_snd_control.mode2_right));
- save_item(NAME(m_snd_control.mode3_left));
- save_item(NAME(m_snd_control.mode3_right));
- save_item(NAME(m_snd_control.mode4_left));
- save_item(NAME(m_snd_control.mode4_right));
+ save_item(NAME(m_snd_control.chan_left));
+ save_item(NAME(m_snd_control.chan_right));
save_item(NAME(m_snd_control.cycles));
- SAVE_CHANNEL(m_snd_1);
- SAVE_CHANNEL(m_snd_2);
- SAVE_CHANNEL(m_snd_3);
- SAVE_CHANNEL(m_snd_4);
+ save_item(STRUCT_MEMBER(m_snd, reg));
+ save_item(STRUCT_MEMBER(m_snd, on));
+ save_item(STRUCT_MEMBER(m_snd, channel));
+ save_item(STRUCT_MEMBER(m_snd, length));
+ save_item(STRUCT_MEMBER(m_snd, length_mask));
+ save_item(STRUCT_MEMBER(m_snd, length_counting));
+ save_item(STRUCT_MEMBER(m_snd, length_enabled));
+ save_item(STRUCT_MEMBER(m_snd, frequency));
+ save_item(STRUCT_MEMBER(m_snd, frequency_counter));
+ save_item(STRUCT_MEMBER(m_snd, cycles_left));
+ save_item(STRUCT_MEMBER(m_snd, duty));
+ save_item(STRUCT_MEMBER(m_snd, envelope_enabled));
+ save_item(STRUCT_MEMBER(m_snd, envelope_value));
+ save_item(STRUCT_MEMBER(m_snd, envelope_direction));
+ save_item(STRUCT_MEMBER(m_snd, envelope_time));
+ save_item(STRUCT_MEMBER(m_snd, envelope_count));
+ save_item(STRUCT_MEMBER(m_snd, signal));
+ save_item(STRUCT_MEMBER(m_snd, frequency_shadow));
+ save_item(STRUCT_MEMBER(m_snd, sweep_enabled));
+ save_item(STRUCT_MEMBER(m_snd, sweep_neg_mode_used));
+ save_item(STRUCT_MEMBER(m_snd, sweep_shift));
+ save_item(STRUCT_MEMBER(m_snd, sweep_direction));
+ save_item(STRUCT_MEMBER(m_snd, sweep_time));
+ save_item(STRUCT_MEMBER(m_snd, sweep_count));
+ save_item(STRUCT_MEMBER(m_snd, size));
+ save_item(STRUCT_MEMBER(m_snd, bank));
+ save_item(STRUCT_MEMBER(m_snd, level));
+ save_item(STRUCT_MEMBER(m_snd, offset));
+ save_item(STRUCT_MEMBER(m_snd, duty_count));
+ save_item(STRUCT_MEMBER(m_snd, current_sample));
+ save_item(STRUCT_MEMBER(m_snd, sample_reading));
+ save_item(STRUCT_MEMBER(m_snd, noise_short));
+ save_item(STRUCT_MEMBER(m_snd, noise_lfsr));
}
@@ -198,19 +186,19 @@ void gameboy_sound_device::device_clock_changed()
void gameboy_sound_device::device_reset()
{
- memset(&m_snd_1, 0, sizeof(m_snd_1));
- memset(&m_snd_2, 0, sizeof(m_snd_2));
- memset(&m_snd_3, 0, sizeof(m_snd_3));
- memset(&m_snd_4, 0, sizeof(m_snd_4));
-
- m_snd_1.channel = 1;
- m_snd_1.length_mask = 0x3f;
- m_snd_2.channel = 2;
- m_snd_2.length_mask = 0x3f;
- m_snd_3.channel = 3;
- m_snd_3.length_mask = 0xff;
- m_snd_4.channel = 4;
- m_snd_4.length_mask = 0x3f;
+ memset(&m_snd[0], 0, sizeof(m_snd[0]));
+ memset(&m_snd[1], 0, sizeof(m_snd[1]));
+ memset(&m_snd[2], 0, sizeof(m_snd[2]));
+ memset(&m_snd[3], 0, sizeof(m_snd[3]));
+
+ m_snd[0].channel = 1;
+ m_snd[0].length_mask = 0x3f;
+ m_snd[1].channel = 2;
+ m_snd[1].length_mask = 0x3f;
+ m_snd[2].channel = 3;
+ m_snd[2].length_mask = 0xff;
+ m_snd[3].channel = 4;
+ m_snd[3].length_mask = 0x3f;
sound_w_internal(NR52, 0x00);
m_wave_ram[0][0x0] = 0xac;
@@ -322,7 +310,7 @@ void gameboy_sound_device::tick_length(SOUND &snd)
int32_t gameboy_sound_device::calculate_next_sweep(SOUND &snd)
{
snd.sweep_neg_mode_used = (snd.sweep_direction < 0);
- int32_t new_frequency = snd.frequency + snd.sweep_direction * (snd.frequency >> snd.sweep_shift);
+ const int32_t new_frequency = snd.frequency_shadow + snd.sweep_direction * (snd.frequency_shadow >> snd.sweep_shift);
if (new_frequency > 0x7ff)
{
@@ -335,12 +323,14 @@ int32_t gameboy_sound_device::calculate_next_sweep(SOUND &snd)
void gameboy_sound_device::apply_next_sweep(SOUND &snd)
{
- int32_t new_frequency = calculate_next_sweep(snd);
+ const int32_t new_frequency = calculate_next_sweep(snd);
if (snd.on && snd.sweep_shift > 0)
{
snd.frequency = new_frequency;
+ snd.frequency_shadow = snd.frequency;
snd.reg[3] = snd.frequency & 0xff;
+ snd.reg[4] = (snd.reg[4] & ~0x7) | ((snd.frequency >> 8) & 0x7);
}
}
@@ -373,7 +363,7 @@ void gameboy_sound_device::tick_envelope(SOUND &snd)
if (snd.envelope_count)
{
- int8_t new_envelope_value = snd.envelope_value + snd.envelope_direction;
+ const int8_t new_envelope_value = snd.envelope_value + snd.envelope_direction;
if (new_envelope_value >= 0 && new_envelope_value <= 15)
{
@@ -411,10 +401,10 @@ void gameboy_sound_device::update_square_channel(SOUND &snd, uint64_t cycles)
{
cycles -= distance;
distance = 0x800 - snd.frequency;
- uint64_t counter = 1 + cycles / distance;
+ const uint64_t counter = 1 + cycles / distance;
snd.duty_count = (snd.duty_count + counter) & 0x07;
- snd.signal = wave_duty_table[snd.duty][snd.duty_count];
+ snd.signal = BIT(wave_duty_table[snd.duty], snd.duty_count);
snd.frequency_counter = snd.frequency + cycles % distance;
}
@@ -454,14 +444,13 @@ void dmg_apu_device::update_wave_channel(SOUND &snd, uint64_t cycles)
{
snd.current_sample >>= 4;
}
- snd.current_sample = (snd.current_sample & 0x0f) - 8;
-
- snd.signal = level ? (snd.current_sample >> (level - 1)) : 0;
+ snd.current_sample &= 0x0f;
// Reload frequency counter
snd.frequency_counter = snd.frequency;
}
}
+ snd.signal = level ? (snd.current_sample >> (level - 1)) : 0;
}
}
@@ -484,7 +473,7 @@ void cgb04_apu_device::update_wave_channel(SOUND &snd, uint64_t cycles)
cycles -= distance;
distance = 0x800 - snd.frequency;
// How many times the condition snd.frequency_counter == 0 is true
- uint64_t counter = 1 + cycles / distance;
+ const uint64_t counter = 1 + cycles / distance;
snd.offset = (snd.offset + counter) & 0x1f;
snd.current_sample = m_wave_ram[0][snd.offset / 2];
@@ -492,8 +481,7 @@ void cgb04_apu_device::update_wave_channel(SOUND &snd, uint64_t cycles)
{
snd.current_sample >>= 4;
}
- snd.current_sample = (snd.current_sample & 0x0f) - 8;
- snd.signal = level ? (snd.current_sample >> (level - 1)) : 0;
+ snd.current_sample &= 0x0f;
cycles %= distance;
snd.sample_reading = !cycles;
@@ -504,6 +492,7 @@ void cgb04_apu_device::update_wave_channel(SOUND &snd, uint64_t cycles)
{
snd.frequency_counter += cycles;
}
+ snd.signal = level ? (snd.current_sample >> (level - 1)) : 0;
}
}
@@ -527,7 +516,7 @@ void agb_apu_device::update_wave_channel(SOUND &snd, uint64_t cycles)
cycles -= distance;
distance = 0x800 - snd.frequency;
// How many times the condition snd.frequency_counter == 0 is true
- uint64_t counter = 1 + cycles / distance;
+ const uint64_t counter = 1 + cycles / distance;
snd.offset = (snd.offset + counter) & 0x3f;
const uint8_t bank = snd.size ? BIT(snd.offset, 5) : snd.bank;
@@ -536,8 +525,7 @@ void agb_apu_device::update_wave_channel(SOUND &snd, uint64_t cycles)
{
snd.current_sample >>= 4;
}
- snd.current_sample = (snd.current_sample & 0x0f) - 8;
- snd.signal = level ? ((snd.current_sample * level) / 4) : 0;
+ snd.current_sample &= 0x0f;
cycles %= distance;
snd.sample_reading = !cycles;
@@ -548,26 +536,27 @@ void agb_apu_device::update_wave_channel(SOUND &snd, uint64_t cycles)
{
snd.frequency_counter += cycles;
}
+ snd.signal = level ? ((snd.current_sample * level) / 4) : 0;
}
}
void gameboy_sound_device::update_noise_channel(SOUND &snd, uint64_t cycles)
{
snd.cycles_left += cycles;
- uint64_t period = noise_period_cycles();
+ const uint64_t period = noise_period_cycles();
while (snd.cycles_left >= period)
{
snd.cycles_left -= period;
// Using a Polynomial Counter (aka Linear Feedback Shift Register)
- // Mode 4 has a 15 bit counter so we need to shift the bits around accordingly.
- uint16_t feedback = ((snd.noise_lfsr >> 1) ^ snd.noise_lfsr) & 1;
+ // Channel 4 has a 15 bit counter so we need to shift the bits around accordingly.
+ const uint16_t feedback = ((snd.noise_lfsr >> 1) ^ snd.noise_lfsr) & 1;
snd.noise_lfsr = (snd.noise_lfsr >> 1) | (feedback << 14);
if (snd.noise_short)
{
snd.noise_lfsr = (snd.noise_lfsr & ~(1 << 6)) | (feedback << 6);
}
- snd.signal = (snd.noise_lfsr & 1) ? -1 : 1;
+ snd.signal = BIT(~snd.noise_lfsr, 0);
}
}
@@ -586,7 +575,7 @@ void gameboy_sound_device::update_state()
{
uint64_t cycles = attotime_to_clocks(now - m_last_updated);
- uint64_t old_cycles = m_snd_control.cycles;
+ const uint64_t old_cycles = m_snd_control.cycles;
m_snd_control.cycles += cycles;
if ((old_cycles / FRAME_CYCLES) != (m_snd_control.cycles / FRAME_CYCLES))
@@ -594,10 +583,10 @@ void gameboy_sound_device::update_state()
// Left over cycles in current frame
uint64_t cycles_current_frame = FRAME_CYCLES - (old_cycles & (FRAME_CYCLES - 1));
- update_square_channel(m_snd_1, cycles_current_frame);
- update_square_channel(m_snd_2, cycles_current_frame);
- update_wave_channel(m_snd_3, cycles_current_frame);
- update_noise_channel(m_snd_4, cycles_current_frame);
+ update_square_channel(m_snd[0], cycles_current_frame);
+ update_square_channel(m_snd[1], cycles_current_frame);
+ update_wave_channel(m_snd[2], cycles_current_frame);
+ update_noise_channel(m_snd[3], cycles_current_frame);
cycles -= cycles_current_frame;
@@ -606,49 +595,49 @@ void gameboy_sound_device::update_state()
{
case 0:
// length
- tick_length(m_snd_1);
- tick_length(m_snd_2);
- tick_length(m_snd_3);
- tick_length(m_snd_4);
+ tick_length(m_snd[0]);
+ tick_length(m_snd[1]);
+ tick_length(m_snd[2]);
+ tick_length(m_snd[3]);
break;
case 2:
// sweep
- tick_sweep(m_snd_1);
+ tick_sweep(m_snd[0]);
// length
- tick_length(m_snd_1);
- tick_length(m_snd_2);
- tick_length(m_snd_3);
- tick_length(m_snd_4);
+ tick_length(m_snd[0]);
+ tick_length(m_snd[1]);
+ tick_length(m_snd[2]);
+ tick_length(m_snd[3]);
break;
case 4:
// length
- tick_length(m_snd_1);
- tick_length(m_snd_2);
- tick_length(m_snd_3);
- tick_length(m_snd_4);
+ tick_length(m_snd[0]);
+ tick_length(m_snd[1]);
+ tick_length(m_snd[2]);
+ tick_length(m_snd[3]);
break;
case 6:
// sweep
- tick_sweep(m_snd_1);
+ tick_sweep(m_snd[0]);
// length
- tick_length(m_snd_1);
- tick_length(m_snd_2);
- tick_length(m_snd_3);
- tick_length(m_snd_4);
+ tick_length(m_snd[0]);
+ tick_length(m_snd[1]);
+ tick_length(m_snd[2]);
+ tick_length(m_snd[3]);
break;
case 7:
// update envelope
- tick_envelope(m_snd_1);
- tick_envelope(m_snd_2);
- tick_envelope(m_snd_4);
+ tick_envelope(m_snd[0]);
+ tick_envelope(m_snd[1]);
+ tick_envelope(m_snd[3]);
break;
}
}
- update_square_channel(m_snd_1, cycles);
- update_square_channel(m_snd_2, cycles);
- update_wave_channel(m_snd_3, cycles);
- update_noise_channel(m_snd_4, cycles);
+ update_square_channel(m_snd[0], cycles);
+ update_square_channel(m_snd[1], cycles);
+ update_wave_channel(m_snd[2], cycles);
+ update_noise_channel(m_snd[3], cycles);
}
m_last_updated = now;
@@ -658,7 +647,7 @@ void gameboy_sound_device::update_state()
uint64_t gameboy_sound_device::noise_period_cycles()
{
static const int divisor[8] = { 8, 16,32, 48, 64, 80, 96, 112 };
- return divisor[m_snd_4.reg[3] & 7] << (m_snd_4.reg[3] >> 4);
+ return divisor[m_snd[3].reg[3] & 7] << (m_snd[3].reg[3] >> 4);
}
@@ -667,9 +656,9 @@ u8 dmg_apu_device::wave_r(offs_t offset)
m_channel->update();
update_state();
- if (m_snd_3.on)
+ if (m_snd[2].on)
{
- return m_snd_3.sample_reading ? m_wave_ram[0][(m_snd_3.offset / 2)] : 0xff;
+ return m_snd[2].sample_reading ? m_wave_ram[0][(m_snd[2].offset / 2)] : 0xff;
}
return m_wave_ram[0][offset];
@@ -680,9 +669,9 @@ u8 cgb04_apu_device::wave_r(offs_t offset)
m_channel->update();
update_state();
- if (m_snd_3.on)
+ if (m_snd[2].on)
{
- return m_wave_ram[0][(m_snd_3.offset / 2)];
+ return m_wave_ram[0][(m_snd[2].offset / 2)];
}
return m_wave_ram[0][offset];
@@ -693,12 +682,12 @@ u8 agb_apu_device::wave_r(offs_t offset)
m_channel->update();
update_state();
- if (m_snd_3.on)
+ if (m_snd[2].on)
{
- return m_wave_ram[m_snd_3.bank ^ 1][(m_snd_3.offset / 2) & 0xf];
+ return 0xff;
}
- return m_wave_ram[m_snd_3.bank ^ 1][offset & 0xf];
+ return m_wave_ram[m_snd[2].bank ^ 1][offset & 0xf];
}
u8 gameboy_sound_device::sound_r(offs_t offset)
@@ -722,7 +711,7 @@ u8 gameboy_sound_device::sound_r(offs_t offset)
{
if (offset == NR52)
{
- return (m_snd_regs[NR52] & 0xf0) | (m_snd_1.on ? 1 : 0) | (m_snd_2.on ? 2 : 0) | (m_snd_3.on ? 4 : 0) | (m_snd_4.on ? 8 : 0) | 0x70;
+ return (m_snd_regs[NR52] & 0xf0) | (m_snd[0].on ? 1 : 0) | (m_snd[1].on ? 2 : 0) | (m_snd[2].on ? 4 : 0) | (m_snd[3].on ? 8 : 0) | 0x70;
}
return m_snd_regs[offset] | read_mask[offset & 0x3f];
}
@@ -751,7 +740,7 @@ u8 agb_apu_device::sound_r(offs_t offset)
{
if (offset == NR52)
{
- return (m_snd_regs[NR52] & 0xf0) | (m_snd_1.on ? 1 : 0) | (m_snd_2.on ? 2 : 0) | (m_snd_3.on ? 4 : 0) | (m_snd_4.on ? 8 : 0) | 0x70;
+ return (m_snd_regs[NR52] & 0xf0) | (m_snd[0].on ? 1 : 0) | (m_snd[1].on ? 2 : 0) | (m_snd[2].on ? 4 : 0) | (m_snd[3].on ? 8 : 0) | 0x70;
}
return m_snd_regs[offset] | read_mask[offset & 0x3f];
}
@@ -766,11 +755,11 @@ void dmg_apu_device::wave_w(offs_t offset, u8 data)
m_channel->update();
update_state();
- if (m_snd_3.on)
+ if (m_snd[2].on)
{
- if (m_snd_3.sample_reading)
+ if (m_snd[2].sample_reading)
{
- m_wave_ram[0][(m_snd_3.offset / 2)] = data;
+ m_wave_ram[0][(m_snd[2].offset / 2)] = data;
}
}
else
@@ -785,9 +774,9 @@ void cgb04_apu_device::wave_w(offs_t offset, u8 data)
m_channel->update();
update_state();
- if (m_snd_3.on)
+ if (m_snd[2].on)
{
- m_wave_ram[0][(m_snd_3.offset / 2)] = data;
+ m_wave_ram[0][(m_snd[2].offset / 2)] = data;
}
else
{
@@ -800,13 +789,9 @@ void agb_apu_device::wave_w(offs_t offset, u8 data)
m_channel->update();
update_state();
- if (m_snd_3.on)
- {
- m_wave_ram[m_snd_3.bank ^ 1][(m_snd_3.offset / 2) & 0xf] = data;
- }
- else
+ if (!m_snd[2].on)
{
- m_wave_ram[m_snd_3.bank ^ 1][offset & 0xf] = data;
+ m_wave_ram[m_snd[2].bank ^ 1][offset & 0xf] = data;
}
}
@@ -840,15 +825,15 @@ void cgb04_apu_device::sound_w(offs_t offset, u8 data)
void dmg_apu_device::corrupt_wave_ram()
{
- if (m_snd_3.offset < 8)
+ if (m_snd[2].offset < 4)
{
- m_wave_ram[0][0x0] = m_wave_ram[0][(m_snd_3.offset / 2)];
+ m_wave_ram[0][0x0] = m_wave_ram[0][(m_snd[2].offset / 2)];
}
else
{
for (int i = 0; i < 4; i++)
{
- m_wave_ram[0][i] = m_wave_ram[0][((m_snd_3.offset / 2) & ~0x03) + i];
+ m_wave_ram[0][i] = m_wave_ram[0][((m_snd[2].offset / 2) & ~0x03) + i];
}
}
}
@@ -857,7 +842,7 @@ void dmg_apu_device::corrupt_wave_ram()
void gameboy_sound_device::sound_w_internal( int offset, uint8_t data )
{
/* Store the value */
- uint8_t old_data = m_snd_regs[offset];
+ const uint8_t old_data = m_snd_regs[offset];
if (m_snd_control.on)
{
@@ -868,94 +853,95 @@ void gameboy_sound_device::sound_w_internal( int offset, uint8_t data )
{
/*MODE 1 */
case NR10: /* Sweep (R/W) */
- m_snd_1.reg[0] = data;
- m_snd_1.sweep_shift = data & 0x7;
- m_snd_1.sweep_direction = (data & 0x8) ? -1 : 1;
- m_snd_1.sweep_time = (data & 0x70) >> 4;
- if ((old_data & 0x08) && !(data & 0x08) && m_snd_1.sweep_neg_mode_used)
+ m_snd[0].reg[0] = data;
+ m_snd[0].sweep_shift = data & 0x7;
+ m_snd[0].sweep_direction = BIT(data, 3) ? -1 : 1;
+ m_snd[0].sweep_time = (data & 0x70) >> 4;
+ if (BIT(old_data, 3) && BIT(~data, 3) && m_snd[0].sweep_neg_mode_used)
{
- m_snd_1.on = false;
+ m_snd[0].on = false;
}
break;
case NR11: /* Sound length/Wave pattern duty (R/W) */
- m_snd_1.reg[1] = data;
+ m_snd[0].reg[1] = data;
if (m_snd_control.on)
{
- m_snd_1.duty = (data & 0xc0) >> 6;
+ m_snd[0].duty = (data & 0xc0) >> 6;
}
- m_snd_1.length = data & 0x3f;
- m_snd_1.length_counting = true;
+ m_snd[0].length = data & 0x3f;
+ m_snd[0].length_counting = true;
break;
case NR12: /* Envelope (R/W) */
- m_snd_1.reg[2] = data;
- m_snd_1.envelope_value = data >> 4;
- m_snd_1.envelope_direction = (data & 0x8) ? 1 : -1;
- m_snd_1.envelope_time = data & 0x07;
- if (!dac_enabled(m_snd_1))
+ m_snd[0].reg[2] = data;
+ m_snd[0].envelope_value = data >> 4;
+ m_snd[0].envelope_direction = BIT(data, 3) ? 1 : -1;
+ m_snd[0].envelope_time = data & 0x07;
+ if (!dac_enabled(m_snd[0]))
{
- m_snd_1.on = false;
+ m_snd[0].on = false;
}
break;
case NR13: /* Frequency lo (R/W) */
- m_snd_1.reg[3] = data;
+ m_snd[0].reg[3] = data;
// Only enabling the frequency line breaks blarggs's sound test #5
// This condition may not be correct
- if (!m_snd_1.sweep_enabled)
+ if (!m_snd[0].sweep_enabled)
{
- m_snd_1.frequency = ((m_snd_1.reg[4] & 0x7) << 8) | m_snd_1.reg[3];
+ m_snd[0].frequency = ((m_snd[0].reg[4] & 0x7) << 8) | m_snd[0].reg[3];
}
break;
case NR14: /* Frequency hi / Initialize (R/W) */
- m_snd_1.reg[4] = data;
+ m_snd[0].reg[4] = data;
{
- bool length_was_enabled = m_snd_1.length_enabled;
+ const bool length_was_enabled = m_snd[0].length_enabled;
- m_snd_1.length_enabled = (data & 0x40) ? true : false;
- m_snd_1.frequency = ((m_snd_regs[NR14] & 0x7) << 8) | m_snd_1.reg[3];
+ m_snd[0].length_enabled = BIT(data, 6);
+ m_snd[0].frequency = ((m_snd_regs[NR14] & 0x7) << 8) | m_snd[0].reg[3];
- if (!length_was_enabled && !(m_snd_control.cycles & FRAME_CYCLES) && m_snd_1.length_counting)
+ if (!length_was_enabled && !(m_snd_control.cycles & FRAME_CYCLES) && m_snd[0].length_counting)
{
- if (m_snd_1.length_enabled)
+ if (m_snd[0].length_enabled)
{
- tick_length(m_snd_1);
+ tick_length(m_snd[0]);
}
}
- if (data & 0x80)
+ if (BIT(data, 7))
{
- m_snd_1.on = true;
- m_snd_1.envelope_enabled = true;
- m_snd_1.envelope_value = m_snd_1.reg[2] >> 4;
- m_snd_1.envelope_count = m_snd_1.envelope_time;
- m_snd_1.sweep_count = m_snd_1.sweep_time;
- m_snd_1.sweep_neg_mode_used = false;
- m_snd_1.signal = 0;
- m_snd_1.length_counting = true;
- m_snd_1.frequency = ((m_snd_1.reg[4] & 0x7) << 8) | m_snd_1.reg[3];
- m_snd_1.frequency_counter = m_snd_1.frequency;
- m_snd_1.cycles_left = 0;
- m_snd_1.duty_count = 0;
- m_snd_1.sweep_enabled = (m_snd_1.sweep_shift != 0) || (m_snd_1.sweep_time != 0);
- if (!dac_enabled(m_snd_1))
+ m_snd[0].on = true;
+ m_snd[0].envelope_enabled = true;
+ m_snd[0].envelope_value = m_snd[0].reg[2] >> 4;
+ m_snd[0].envelope_count = m_snd[0].envelope_time;
+ m_snd[0].sweep_count = m_snd[0].sweep_time;
+ m_snd[0].sweep_neg_mode_used = false;
+ m_snd[0].signal = 0;
+ m_snd[0].length_counting = true;
+ m_snd[0].frequency = ((m_snd[0].reg[4] & 0x7) << 8) | m_snd[0].reg[3];
+ m_snd[0].frequency_counter = m_snd[0].frequency;
+ m_snd[0].frequency_shadow = m_snd[0].frequency;
+ m_snd[0].cycles_left = 0;
+ m_snd[0].duty_count = 0;
+ m_snd[0].sweep_enabled = (m_snd[0].sweep_shift != 0) || (m_snd[0].sweep_time != 0);
+ if (!dac_enabled(m_snd[0]))
{
- m_snd_1.on = false;
+ m_snd[0].on = false;
}
- if (m_snd_1.sweep_shift > 0)
+ if (m_snd[0].sweep_shift > 0)
{
- calculate_next_sweep(m_snd_1);
+ calculate_next_sweep(m_snd[0]);
}
- if (m_snd_1.length == 0 && m_snd_1.length_enabled && !(m_snd_control.cycles & FRAME_CYCLES))
+ if (m_snd[0].length == 0 && m_snd[0].length_enabled && !(m_snd_control.cycles & FRAME_CYCLES))
{
- tick_length(m_snd_1);
+ tick_length(m_snd[0]);
}
}
else
{
// This condition may not be correct
- if (!m_snd_1.sweep_enabled)
+ if (!m_snd[0].sweep_enabled)
{
- m_snd_1.frequency = ((m_snd_1.reg[4] & 0x7) << 8) | m_snd_1.reg[3];
+ m_snd[0].frequency = ((m_snd[0].reg[4] & 0x7) << 8) | m_snd[0].reg[3];
}
}
}
@@ -963,200 +949,201 @@ void gameboy_sound_device::sound_w_internal( int offset, uint8_t data )
/*MODE 2 */
case NR21: /* Sound length/Wave pattern duty (R/W) */
- m_snd_2.reg[1] = data;
+ m_snd[1].reg[1] = data;
if (m_snd_control.on)
{
- m_snd_2.duty = (data & 0xc0) >> 6;
+ m_snd[1].duty = (data & 0xc0) >> 6;
}
- m_snd_2.length = data & 0x3f;
- m_snd_2.length_counting = true;
+ m_snd[1].length = data & 0x3f;
+ m_snd[1].length_counting = true;
break;
case NR22: /* Envelope (R/W) */
- m_snd_2.reg[2] = data;
- m_snd_2.envelope_value = data >> 4;
- m_snd_2.envelope_direction = (data & 0x8) ? 1 : -1;
- m_snd_2.envelope_time = data & 0x07;
- if (!dac_enabled(m_snd_2))
+ m_snd[1].reg[2] = data;
+ m_snd[1].envelope_value = data >> 4;
+ m_snd[1].envelope_direction = BIT(data, 3) ? 1 : -1;
+ m_snd[1].envelope_time = data & 0x07;
+ if (!dac_enabled(m_snd[1]))
{
- m_snd_2.on = false;
+ m_snd[1].on = false;
}
break;
case NR23: /* Frequency lo (R/W) */
- m_snd_2.reg[3] = data;
- m_snd_2.frequency = ((m_snd_2.reg[4] & 0x7) << 8) | m_snd_2.reg[3];
+ m_snd[1].reg[3] = data;
+ m_snd[1].frequency = ((m_snd[1].reg[4] & 0x7) << 8) | m_snd[1].reg[3];
break;
case NR24: /* Frequency hi / Initialize (R/W) */
- m_snd_2.reg[4] = data;
+ m_snd[1].reg[4] = data;
{
- bool length_was_enabled = m_snd_2.length_enabled;
+ const bool length_was_enabled = m_snd[1].length_enabled;
- m_snd_2.length_enabled = (data & 0x40) ? true : false;
+ m_snd[1].length_enabled = BIT(data, 6);
- if (!length_was_enabled && !(m_snd_control.cycles & FRAME_CYCLES) && m_snd_2.length_counting)
+ if (!length_was_enabled && !(m_snd_control.cycles & FRAME_CYCLES) && m_snd[1].length_counting)
{
- if (m_snd_2.length_enabled)
+ if (m_snd[1].length_enabled)
{
- tick_length(m_snd_2);
+ tick_length(m_snd[1]);
}
}
- if (data & 0x80)
+ if (BIT(data, 7))
{
- m_snd_2.on = true;
- m_snd_2.envelope_enabled = true;
- m_snd_2.envelope_value = m_snd_2.reg[2] >> 4;
- m_snd_2.envelope_count = m_snd_2.envelope_time;
- m_snd_2.frequency = ((m_snd_2.reg[4] & 0x7) << 8) | m_snd_2.reg[3];
- m_snd_2.frequency_counter = m_snd_2.frequency;
- m_snd_2.cycles_left = 0;
- m_snd_2.duty_count = 0;
- m_snd_2.signal = 0;
- m_snd_2.length_counting = true;
-
- if (!dac_enabled(m_snd_2))
+ m_snd[1].on = true;
+ m_snd[1].envelope_enabled = true;
+ m_snd[1].envelope_value = m_snd[1].reg[2] >> 4;
+ m_snd[1].envelope_count = m_snd[1].envelope_time;
+ m_snd[1].frequency = ((m_snd[1].reg[4] & 0x7) << 8) | m_snd[1].reg[3];
+ m_snd[1].frequency_counter = m_snd[1].frequency;
+ m_snd[1].cycles_left = 0;
+ m_snd[1].duty_count = 0;
+ m_snd[1].signal = 0;
+ m_snd[1].length_counting = true;
+
+ if (!dac_enabled(m_snd[1]))
{
- m_snd_2.on = false;
+ m_snd[1].on = false;
}
- if (m_snd_2.length == 0 && m_snd_2.length_enabled && !(m_snd_control.cycles & FRAME_CYCLES))
+ if (m_snd[1].length == 0 && m_snd[1].length_enabled && !(m_snd_control.cycles & FRAME_CYCLES))
{
- tick_length(m_snd_2);
+ tick_length(m_snd[1]);
}
}
else
{
- m_snd_2.frequency = ((m_snd_2.reg[4] & 0x7) << 8) | m_snd_2.reg[3];
+ m_snd[1].frequency = ((m_snd[1].reg[4] & 0x7) << 8) | m_snd[1].reg[3];
}
}
break;
/*MODE 3 */
case NR30: /* Sound On/Off (R/W) */
- m_snd_3.reg[0] = data;
- m_snd_3.size = BIT(data, 5);
- m_snd_3.bank = BIT(data, 6);
- if (!dac_enabled(m_snd_3))
+ m_snd[2].reg[0] = data;
+ m_snd[2].size = BIT(data, 5);
+ m_snd[2].bank = BIT(data, 6);
+ if (!dac_enabled(m_snd[2]))
{
- m_snd_3.on = false;
+ m_snd[2].on = false;
}
break;
case NR31: /* Sound Length (R/W) */
- m_snd_3.reg[1] = data;
- m_snd_3.length = data;
- m_snd_3.length_counting = true;
+ m_snd[2].reg[1] = data;
+ m_snd[2].length = data;
+ m_snd[2].length_counting = true;
break;
case NR32: /* Select Output Level */
- m_snd_3.reg[2] = data;
- m_snd_3.level = (data & 0xe0) >> 5;
+ m_snd[2].reg[2] = data;
+ m_snd[2].level = (data & 0xe0) >> 5;
break;
case NR33: /* Frequency lo (W) */
- m_snd_3.reg[3] = data;
- m_snd_3.frequency = ((m_snd_3.reg[4] & 0x7) << 8) | m_snd_3.reg[3];
+ m_snd[2].reg[3] = data;
+ m_snd[2].frequency = ((m_snd[2].reg[4] & 0x7) << 8) | m_snd[2].reg[3];
break;
case NR34: /* Frequency hi / Initialize (W) */
- m_snd_3.reg[4] = data;
+ m_snd[2].reg[4] = data;
{
- bool length_was_enabled = m_snd_3.length_enabled;
+ const bool length_was_enabled = m_snd[2].length_enabled;
- m_snd_3.length_enabled = (data & 0x40) ? true : false;
+ m_snd[2].length_enabled = BIT(data, 6);
- if (!length_was_enabled && !(m_snd_control.cycles & FRAME_CYCLES) && m_snd_3.length_counting)
+ if (!length_was_enabled && !(m_snd_control.cycles & FRAME_CYCLES) && m_snd[2].length_counting)
{
- if (m_snd_3.length_enabled)
+ if (m_snd[2].length_enabled)
{
- tick_length(m_snd_3);
+ tick_length(m_snd[2]);
}
}
- if (data & 0x80)
+ if (BIT(data, 7))
{
- if (m_snd_3.on && m_snd_3.frequency_counter == 0x7ff)
+ if (m_snd[2].on && m_snd[2].frequency_counter == 0x7ff)
{
corrupt_wave_ram();
}
- m_snd_3.on = true;
- m_snd_3.offset = 0;
- m_snd_3.duty = 1;
- m_snd_3.duty_count = 0;
- m_snd_3.length_counting = true;
- m_snd_3.frequency = ((m_snd_3.reg[4] & 0x7) << 8) | m_snd_3.reg[3];
- m_snd_3.frequency_counter = m_snd_3.frequency;
+ m_snd[2].on = true;
+ m_snd[2].offset = 0;
+ m_snd[2].duty = 1;
+ m_snd[2].duty_count = 0;
+ m_snd[2].length_counting = true;
+ m_snd[2].frequency = ((m_snd[2].reg[4] & 0x7) << 8) | m_snd[2].reg[3];
+ m_snd[2].frequency_counter = m_snd[2].frequency;
// There is a tiny bit of delay in starting up the wave channel
- m_snd_3.cycles_left = -6;
- m_snd_3.sample_reading = false;
+ m_snd[2].cycles_left = -6;
+ m_snd[2].current_sample = 0;
+ m_snd[2].sample_reading = false;
- if (!dac_enabled(m_snd_3))
+ if (!dac_enabled(m_snd[2]))
{
- m_snd_3.on = false;
+ m_snd[2].on = false;
}
- if (m_snd_3.length == 0 && m_snd_3.length_enabled && !(m_snd_control.cycles & FRAME_CYCLES))
+ if (m_snd[2].length == 0 && m_snd[2].length_enabled && !(m_snd_control.cycles & FRAME_CYCLES))
{
- tick_length(m_snd_3);
+ tick_length(m_snd[2]);
}
}
else
{
- m_snd_3.frequency = ((m_snd_3.reg[4] & 0x7) << 8) | m_snd_3.reg[3];
+ m_snd[2].frequency = ((m_snd[2].reg[4] & 0x7) << 8) | m_snd[2].reg[3];
}
}
break;
/*MODE 4 */
case NR41: /* Sound Length (R/W) */
- m_snd_4.reg[1] = data;
- m_snd_4.length = data & 0x3f;
- m_snd_4.length_counting = true;
+ m_snd[3].reg[1] = data;
+ m_snd[3].length = data & 0x3f;
+ m_snd[3].length_counting = true;
break;
case NR42: /* Envelope (R/W) */
- m_snd_4.reg[2] = data;
- m_snd_4.envelope_value = data >> 4;
- m_snd_4.envelope_direction = (data & 0x8) ? 1 : -1;
- m_snd_4.envelope_time = data & 0x07;
- if (!dac_enabled(m_snd_4))
+ m_snd[3].reg[2] = data;
+ m_snd[3].envelope_value = data >> 4;
+ m_snd[3].envelope_direction = BIT(data, 3) ? 1 : -1;
+ m_snd[3].envelope_time = data & 0x07;
+ if (!dac_enabled(m_snd[3]))
{
- m_snd_4.on = false;
+ m_snd[3].on = false;
}
break;
case NR43: /* Polynomial Counter/Frequency */
- m_snd_4.reg[3] = data;
- m_snd_4.noise_short = (data & 0x8);
+ m_snd[3].reg[3] = data;
+ m_snd[3].noise_short = BIT(data, 3);
break;
case NR44: /* Counter/Consecutive / Initialize (R/W) */
- m_snd_4.reg[4] = data;
+ m_snd[3].reg[4] = data;
{
- bool length_was_enabled = m_snd_4.length_enabled;
+ const bool length_was_enabled = m_snd[3].length_enabled;
- m_snd_4.length_enabled = (data & 0x40) ? true : false;
+ m_snd[3].length_enabled = BIT(data, 6);
- if (!length_was_enabled && !(m_snd_control.cycles & FRAME_CYCLES) && m_snd_4.length_counting)
+ if (!length_was_enabled && !(m_snd_control.cycles & FRAME_CYCLES) && m_snd[3].length_counting)
{
- if (m_snd_4.length_enabled)
+ if (m_snd[3].length_enabled)
{
- tick_length(m_snd_4);
+ tick_length(m_snd[3]);
}
}
- if (data & 0x80)
+ if (BIT(data, 7))
{
- m_snd_4.on = true;
- m_snd_4.envelope_enabled = true;
- m_snd_4.envelope_value = m_snd_4.reg[2] >> 4;
- m_snd_4.envelope_count = m_snd_4.envelope_time;
- m_snd_4.frequency_counter = 0;
- m_snd_4.cycles_left = noise_period_cycles();
- m_snd_4.signal = -1;
- m_snd_4.noise_lfsr = 0x7fff;
- m_snd_4.length_counting = true;
-
- if (!dac_enabled(m_snd_4))
+ m_snd[3].on = true;
+ m_snd[3].envelope_enabled = true;
+ m_snd[3].envelope_value = m_snd[3].reg[2] >> 4;
+ m_snd[3].envelope_count = m_snd[3].envelope_time;
+ m_snd[3].frequency_counter = 0;
+ m_snd[3].cycles_left = noise_period_cycles();
+ m_snd[3].signal = 0;
+ m_snd[3].noise_lfsr = 0x7fff;
+ m_snd[3].length_counting = true;
+
+ if (!dac_enabled(m_snd[3]))
{
- m_snd_4.on = false;
+ m_snd[3].on = false;
}
- if (m_snd_4.length == 0 && m_snd_4.length_enabled && !(m_snd_control.cycles & FRAME_CYCLES))
+ if (m_snd[3].length == 0 && m_snd[3].length_enabled && !(m_snd_control.cycles & FRAME_CYCLES))
{
- tick_length(m_snd_4);
+ tick_length(m_snd[3]);
}
}
}
@@ -1168,18 +1155,18 @@ void gameboy_sound_device::sound_w_internal( int offset, uint8_t data )
m_snd_control.vol_right = (data & 0x70) >> 4;
break;
case NR51: /* Selection of Sound Output Terminal */
- m_snd_control.mode1_right = data & 0x1;
- m_snd_control.mode1_left = (data & 0x10) >> 4;
- m_snd_control.mode2_right = (data & 0x2) >> 1;
- m_snd_control.mode2_left = (data & 0x20) >> 5;
- m_snd_control.mode3_right = (data & 0x4) >> 2;
- m_snd_control.mode3_left = (data & 0x40) >> 6;
- m_snd_control.mode4_right = (data & 0x8) >> 3;
- m_snd_control.mode4_left = (data & 0x80) >> 7;
+ m_snd_control.chan_right[0] = BIT(data, 0);
+ m_snd_control.chan_left[0] = BIT(data, 4);
+ m_snd_control.chan_right[1] = BIT(data, 1);
+ m_snd_control.chan_left[1] = BIT(data, 5);
+ m_snd_control.chan_right[2] = BIT(data, 2);
+ m_snd_control.chan_left[2] = BIT(data, 6);
+ m_snd_control.chan_right[3] = BIT(data, 3);
+ m_snd_control.chan_left[3] = BIT(data, 7);
break;
case NR52: // Sound On/Off (R/W)
// Only bit 7 is writable, writing to bits 0-3 does NOT enable or disable sound. They are read-only.
- if (!(data & 0x80))
+ if (BIT(~data, 7))
{
// On DMG the length counters are not affected and not clocked
// powering off should actually clear all registers
@@ -1193,7 +1180,7 @@ void gameboy_sound_device::sound_w_internal( int offset, uint8_t data )
m_snd_control.cycles |= 7 * FRAME_CYCLES;
}
}
- m_snd_control.on = (data & 0x80) ? true : false;
+ m_snd_control.on = BIT(data, 7);
m_snd_regs[NR52] = data & 0x80;
break;
case AUD3W0: // Wavetable (R/W)
@@ -1221,38 +1208,39 @@ void gameboy_sound_device::sound_w_internal( int offset, uint8_t data )
void dmg_apu_device::apu_power_off()
{
sound_w_internal(NR10, 0x00);
- m_snd_1.duty = 0;
+ m_snd[0].duty = 0;
m_snd_regs[NR11] = 0;
sound_w_internal(NR12, 0x00);
sound_w_internal(NR13, 0x00);
sound_w_internal(NR14, 0x00);
- m_snd_1.length_counting = false;
- m_snd_1.sweep_neg_mode_used = false;
+ m_snd[0].frequency_shadow = 0;
+ m_snd[0].length_counting = false;
+ m_snd[0].sweep_neg_mode_used = false;
m_snd_regs[NR21] = 0;
sound_w_internal(NR22, 0x00);
sound_w_internal(NR23, 0x00);
sound_w_internal(NR24, 0x00);
- m_snd_2.length_counting = false;
+ m_snd[1].length_counting = false;
sound_w_internal(NR30, 0x00);
sound_w_internal(NR32, 0x00);
sound_w_internal(NR33, 0x00);
sound_w_internal(NR34, 0x00);
- m_snd_3.length_counting = false;
- m_snd_3.current_sample = 0;
+ m_snd[2].length_counting = false;
+ m_snd[2].current_sample = 0;
m_snd_regs[NR41] = 0;
sound_w_internal(NR42, 0x00);
sound_w_internal(NR43, 0x00);
sound_w_internal(NR44, 0x00);
- m_snd_4.length_counting = false;
- m_snd_4.cycles_left = noise_period_cycles();
+ m_snd[3].length_counting = false;
+ m_snd[3].cycles_left = noise_period_cycles();
- m_snd_1.on = false;
- m_snd_2.on = false;
- m_snd_3.on = false;
- m_snd_4.on = false;
+ m_snd[0].on = false;
+ m_snd[1].on = false;
+ m_snd[2].on = false;
+ m_snd[3].on = false;
m_snd_control.wave_ram_locked = false;
@@ -1266,39 +1254,39 @@ void dmg_apu_device::apu_power_off()
void cgb04_apu_device::apu_power_off()
{
sound_w_internal(NR10, 0x00);
- m_snd_1.duty = 0;
+ m_snd[0].duty = 0;
sound_w_internal(NR11, 0x00);
sound_w_internal(NR12, 0x00);
sound_w_internal(NR13, 0x00);
sound_w_internal(NR14, 0x00);
- m_snd_1.length_counting = false;
- m_snd_1.sweep_neg_mode_used = false;
+ m_snd[0].length_counting = false;
+ m_snd[0].sweep_neg_mode_used = false;
sound_w_internal(NR21, 0x00);
sound_w_internal(NR22, 0x00);
sound_w_internal(NR23, 0x00);
sound_w_internal(NR24, 0x00);
- m_snd_2.length_counting = false;
+ m_snd[1].length_counting = false;
sound_w_internal(NR30, 0x00);
sound_w_internal(NR31, 0x00);
sound_w_internal(NR32, 0x00);
sound_w_internal(NR33, 0x00);
sound_w_internal(NR34, 0x00);
- m_snd_3.length_counting = false;
- m_snd_3.current_sample = 0;
+ m_snd[2].length_counting = false;
+ m_snd[2].current_sample = 0;
sound_w_internal(NR41, 0x00);
sound_w_internal(NR42, 0x00);
sound_w_internal(NR43, 0x00);
sound_w_internal(NR44, 0x00);
- m_snd_4.length_counting = false;
- m_snd_4.cycles_left = noise_period_cycles();
+ m_snd[3].length_counting = false;
+ m_snd[3].cycles_left = noise_period_cycles();
- m_snd_1.on = false;
- m_snd_2.on = false;
- m_snd_3.on = false;
- m_snd_4.on = false;
+ m_snd[0].on = false;
+ m_snd[1].on = false;
+ m_snd[2].on = false;
+ m_snd[3].on = false;
m_snd_control.wave_ram_locked = false;
@@ -1309,6 +1297,12 @@ void cgb04_apu_device::apu_power_off()
}
+// convert output: 1 (0) to -1 (15)
+constexpr s32 convert_output(s32 sample)
+{
+ return 0xf - (sample * 2);
+}
+
//-------------------------------------------------
// sound_stream_update - handle a stream update
//-------------------------------------------------
@@ -1323,53 +1317,52 @@ void gameboy_sound_device::sound_stream_update(sound_stream &stream, std::vector
s32 left = 0;
s32 right = 0;
- /* Mode 1 - Wave with Envelope and Sweep */
- if (m_snd_1.on)
+ /* Channel 1 - Wave with Envelope and Sweep */
+ if (m_snd[0].on)
{
- sample = m_snd_1.signal * m_snd_1.envelope_value;
-
- if (m_snd_control.mode1_left)
+ sample = convert_output(m_snd[0].signal * m_snd[0].envelope_value);
+ if (m_snd_control.chan_left[0])
left += sample;
- if (m_snd_control.mode1_right)
+ if (m_snd_control.chan_right[0])
right += sample;
}
- /* Mode 2 - Wave with Envelope */
- if (m_snd_2.on)
+ /* Channel 2 - Wave with Envelope */
+ if (m_snd[1].on)
{
- sample = m_snd_2.signal * m_snd_2.envelope_value;
- if (m_snd_control.mode2_left)
+ sample = convert_output(m_snd[1].signal * m_snd[1].envelope_value);
+ if (m_snd_control.chan_left[1])
left += sample;
- if (m_snd_control.mode2_right)
+ if (m_snd_control.chan_right[1])
right += sample;
}
- /* Mode 3 - Wave patterns from WaveRAM */
- if (m_snd_3.on)
+ /* Channel 3 - Wave patterns from WaveRAM */
+ if (m_snd[2].on)
{
- sample = m_snd_3.signal;
- if (m_snd_control.mode3_left)
+ sample = convert_output(m_snd[2].signal);
+ if (m_snd_control.chan_left[2])
left += sample;
- if (m_snd_control.mode3_right)
+ if (m_snd_control.chan_right[2])
right += sample;
}
- /* Mode 4 - Noise with Envelope */
- if (m_snd_4.on)
+ /* Channel 4 - Noise with Envelope */
+ if (m_snd[3].on)
{
- sample = m_snd_4.signal * m_snd_4.envelope_value;
- if (m_snd_control.mode4_left)
+ sample = convert_output(m_snd[3].signal * m_snd[3].envelope_value);
+ if (m_snd_control.chan_left[3])
left += sample;
- if (m_snd_control.mode4_right)
+ if (m_snd_control.chan_right[3])
right += sample;
}
/* Adjust for master volume */
- left *= m_snd_control.vol_left;
- right *= m_snd_control.vol_right;
+ left *= 1 + m_snd_control.vol_left;
+ right *= 1 + m_snd_control.vol_right;
/* Update the buffers */
- outputl.put_int(sampindex, left, 32768 / 64);
- outputr.put_int(sampindex, right, 32768 / 64);
+ outputl.put_int(sampindex, left, 15 * 4 * (1 + 7));
+ outputr.put_int(sampindex, right, 15 * 4 * (1 + 7));
}
}
diff --git a/src/devices/sound/gb.h b/src/devices/sound/gb.h
index be5f12fb324..a4211e28133 100644
--- a/src/devices/sound/gb.h
+++ b/src/devices/sound/gb.h
@@ -9,7 +9,7 @@ class gameboy_sound_device : public device_t,
public device_sound_interface
{
public:
- static constexpr feature_type imperfect_features() { return feature::SOUND; } // incorrect sound pitch
+ static constexpr feature_type imperfect_features() { return feature::SOUND; }
gameboy_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -75,7 +75,7 @@ protected:
};
static const unsigned int FRAME_CYCLES = 8192;
- static const int wave_duty_table[4][8];
+ static const int wave_duty_table[4];
sound_stream *m_channel;
@@ -89,26 +89,27 @@ protected:
uint8_t length_mask;
bool length_counting;
bool length_enabled;
- /* Mode 1, 2, 3 */
+ uint16_t frequency;
+ uint16_t frequency_counter;
+ /* Channel 1, 2, 3 */
int64_t cycles_left;
int8_t duty;
- /* Mode 1, 2, 4 */
+ /* Channel 1, 2, 4 */
bool envelope_enabled;
int8_t envelope_value;
int8_t envelope_direction;
uint8_t envelope_time;
uint8_t envelope_count;
int8_t signal;
- /* Mode 1 */
- uint16_t frequency;
- uint16_t frequency_counter;
+ /* Channel 1 */
+ uint16_t frequency_shadow;
bool sweep_enabled;
bool sweep_neg_mode_used;
uint8_t sweep_shift;
int32_t sweep_direction;
uint8_t sweep_time;
uint8_t sweep_count;
- /* Mode 3 */
+ /* Channel 3 */
uint8_t size; // AGB specific
uint8_t bank; // AGB specific
uint8_t level;
@@ -116,29 +117,20 @@ protected:
uint32_t duty_count;
int8_t current_sample;
bool sample_reading;
- /* Mode 4 */
+ /* Channel 4 */
bool noise_short;
uint16_t noise_lfsr;
};
- SOUND m_snd_1;
- SOUND m_snd_2;
- SOUND m_snd_3;
- SOUND m_snd_4;
+ SOUND m_snd[4];
struct
{
- uint8_t on;
+ bool on;
uint8_t vol_left;
uint8_t vol_right;
- uint8_t mode1_left;
- uint8_t mode1_right;
- uint8_t mode2_left;
- uint8_t mode2_right;
- uint8_t mode3_left;
- uint8_t mode3_right;
- uint8_t mode4_left;
- uint8_t mode4_right;
+ bool chan_left[4];
+ bool chan_right[4];
uint64_t cycles;
bool wave_ram_locked;
} m_snd_control;