mirror of
https://github.com/mattrberry/crab.git
synced 2025-01-30 20:34:45 +01:00
proper DMA/PSG balance, use soundbias, remove offset for silence
This commit is contained in:
parent
f21091d375
commit
79ed746d6c
6 changed files with 26 additions and 30 deletions
|
@ -20,7 +20,7 @@ class APU
|
|||
@soundcnt_l = Reg::SOUNDCNT_L.new 0
|
||||
getter soundcnt_h = Reg::SOUNDCNT_H.new 0
|
||||
@sound_enabled : Bool = false
|
||||
@soundbias = Reg::SOUNDBIAS.new 0
|
||||
@soundbias = Reg::SOUNDBIAS.new 0x3FE
|
||||
|
||||
@buffer = Slice(Int16).new BUFFER_SIZE
|
||||
@buffer_pos = 0
|
||||
|
@ -101,29 +101,25 @@ class APU
|
|||
|
||||
def get_sample : Nil
|
||||
abort "Prohibited sound 1-4 volume #{@soundcnt_h.sound_volume}" if @soundcnt_h.sound_volume >= 3
|
||||
# Puts PSGs on scale of 0...0x40
|
||||
# Gets PSGs on scale of -0x80..0x80 each
|
||||
psg_sound = ((@channel1.get_amplitude * @soundcnt_l.channel_1_left) +
|
||||
(@channel2.get_amplitude * @soundcnt_l.channel_2_left) +
|
||||
(@channel3.get_amplitude * @soundcnt_l.channel_3_left) +
|
||||
(@channel4.get_amplitude * @soundcnt_l.channel_4_left))# * 2 - 0x80
|
||||
# Puts PSGs on scale of 0...0x200
|
||||
psg_left = (psg_sound * @soundcnt_l.left_volume) >> (2 - @soundcnt_h.sound_volume)
|
||||
psg_right = (psg_sound * @soundcnt_l.right_volume) >> (2 - @soundcnt_h.sound_volume)
|
||||
(@channel4.get_amplitude * @soundcnt_l.channel_4_left))
|
||||
# Keep PSGs on scale of -0x200...0x200 (shift by `5 - vol` to account for `*8` from left/right vol)
|
||||
psg_left = (psg_sound * @soundcnt_l.left_volume) >> (5 - @soundcnt_h.sound_volume)
|
||||
psg_right = (psg_sound * @soundcnt_l.right_volume) >> (5 - @soundcnt_h.sound_volume)
|
||||
|
||||
# Gets DMAs on scale of -0x100...0x100
|
||||
dma_a, dma_b = @dma_channels.get_amplitude
|
||||
dma_a <<= 1
|
||||
dma_b <<= 1
|
||||
# Puts DMAs on scale of -0x200...0x200
|
||||
dma_a <<= @soundcnt_h.dma_sound_a_volume
|
||||
dma_b <<= @soundcnt_h.dma_sound_b_volume
|
||||
dma_left = dma_a * @soundcnt_h.dma_sound_a_left + dma_b * @soundcnt_h.dma_sound_b_left
|
||||
dma_right = dma_a * @soundcnt_h.dma_sound_a_right + dma_b * @soundcnt_h.dma_sound_b_right
|
||||
|
||||
bias = 0x200
|
||||
|
||||
total_left = (psg_left + dma_left + bias).clamp(0_i16..0x3FF_i16)
|
||||
total_right = (psg_right + dma_right + bias).clamp(0_i16..0x3FF_i16)
|
||||
total_left = (psg_left + dma_left + @soundbias.bias_level).clamp(0_i16..0x3FF_i16) - @soundbias.bias_level
|
||||
total_right = (psg_right + dma_right + @soundbias.bias_level).clamp(0_i16..0x3FF_i16) - @soundbias.bias_level
|
||||
|
||||
@buffer[@buffer_pos] = total_left * 32
|
||||
@buffer[@buffer_pos + 1] = total_right * 32
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
class Channel1 < VolumeEnvelopeChannel
|
||||
WAVE_DUTY = [
|
||||
[0, 0, 0, 0, 0, 0, 0, 1], # 12.5%
|
||||
[1, 0, 0, 0, 0, 0, 0, 1], # 25%
|
||||
[1, 0, 0, 0, 0, 1, 1, 1], # 50%
|
||||
[0, 1, 1, 1, 1, 1, 1, 0], # 75%
|
||||
[-8, -8, -8, -8, -8, -8, -8, +8], # 12.5%
|
||||
[+8, -8, -8, -8, -8, -8, -8, +8], # 25%
|
||||
[+8, -8, -8, -8, -8, +8, +8, +8], # 50%
|
||||
[-8, +8, +8, +8, +8, +8, +8, -8], # 75%
|
||||
]
|
||||
|
||||
RANGE = 0x60..0x67
|
||||
|
@ -57,7 +57,7 @@ class Channel1 < VolumeEnvelopeChannel
|
|||
end
|
||||
end
|
||||
|
||||
# Outputs a value 0..0xF
|
||||
# Outputs a value -0x80..0x80
|
||||
def get_amplitude : Int16
|
||||
if @enabled && @dac_enabled
|
||||
WAVE_DUTY[@duty][@wave_duty_position].to_i16 * @current_volume
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
class Channel2 < VolumeEnvelopeChannel
|
||||
WAVE_DUTY = [
|
||||
[0, 0, 0, 0, 0, 0, 0, 1], # 12.5%
|
||||
[1, 0, 0, 0, 0, 0, 0, 1], # 25%
|
||||
[1, 0, 0, 0, 0, 1, 1, 1], # 50%
|
||||
[0, 1, 1, 1, 1, 1, 1, 0], # 75%
|
||||
[-8, -8, -8, -8, -8, -8, -8, +8], # 12.5%
|
||||
[+8, -8, -8, -8, -8, -8, -8, +8], # 25%
|
||||
[+8, -8, -8, -8, -8, +8, +8, +8], # 50%
|
||||
[-8, +8, +8, +8, +8, +8, +8, -8], # 75%
|
||||
]
|
||||
|
||||
RANGE = 0x68..0x6F
|
||||
|
@ -33,7 +33,7 @@ class Channel2 < VolumeEnvelopeChannel
|
|||
@gba.scheduler.schedule frequency_timer, ->step, Scheduler::EventType::APUChannel2
|
||||
end
|
||||
|
||||
# Outputs a value 0..0xF
|
||||
# Outputs a value -0x80..0x80
|
||||
def get_amplitude : Int16
|
||||
if @enabled && @dac_enabled
|
||||
WAVE_DUTY[@duty][@wave_duty_position].to_i16 * @current_volume
|
||||
|
|
|
@ -8,7 +8,7 @@ class Channel3 < SoundChannel
|
|||
|
||||
@wave_ram = Array(Bytes).new 2, Bytes.new(WAVE_RAM_RANGE.size) { |idx| idx & 1 == 0 ? 0x00_u8 : 0xFF_u8 }
|
||||
@wave_ram_position : UInt8 = 0
|
||||
@wave_ram_sample_buffer : Int16 = 0x00
|
||||
@wave_ram_sample_buffer : UInt8 = 0x00
|
||||
|
||||
# NR30
|
||||
@wave_ram_dimension : Bool = false
|
||||
|
@ -27,7 +27,8 @@ class Channel3 < SoundChannel
|
|||
def step_wave_generation : Nil
|
||||
@wave_ram_position = (@wave_ram_position + 1) % (WAVE_RAM_RANGE.size * 2)
|
||||
@wave_ram_bank ^= 1 if @wave_ram_position == 0 && @wave_ram_dimension
|
||||
@wave_ram_sample_buffer = @wave_ram[@wave_ram_bank][@wave_ram_position // 2].to_i16
|
||||
full_sample = @wave_ram[@wave_ram_bank][@wave_ram_position // 2]
|
||||
@wave_ram_sample_buffer = (full_sample >> (@wave_ram_position & 1 == 0 ? 4 : 0)) & 0xF
|
||||
end
|
||||
|
||||
def frequency_timer : UInt32
|
||||
|
@ -38,11 +39,10 @@ class Channel3 < SoundChannel
|
|||
@gba.scheduler.schedule frequency_timer, ->step, Scheduler::EventType::APUChannel3
|
||||
end
|
||||
|
||||
# Outputs a value 0..0xF
|
||||
# Outputs a value -0x80..0x80
|
||||
def get_amplitude : Int16
|
||||
if @enabled && @dac_enabled
|
||||
volume_shift = (-1 + @volume_code) % 4
|
||||
(((@wave_ram_sample_buffer >> (@wave_ram_position & 1 == 0 ? 4 : 0)) & 0x0F) >> volume_shift)
|
||||
(@wave_ram_sample_buffer.to_i16 - 8) * 4 * (@volume_force ? 3 : {0, 4, 2, 1}[@volume_code])
|
||||
else
|
||||
0_i16
|
||||
end
|
||||
|
|
|
@ -33,10 +33,10 @@ class Channel4 < VolumeEnvelopeChannel
|
|||
@gba.scheduler.schedule frequency_timer, ->step, Scheduler::EventType::APUChannel4
|
||||
end
|
||||
|
||||
# Outputs a value 0..0xF
|
||||
# Outputs a value -0x80..0x80
|
||||
def get_amplitude : Int16
|
||||
if @enabled && @dac_enabled
|
||||
((~@lfsr & 1) * @current_volume).to_i16
|
||||
((~@lfsr & 1).to_i16 * 16 - 8) * @current_volume
|
||||
else
|
||||
0_i16
|
||||
end
|
||||
|
|
|
@ -37,7 +37,7 @@ class DMAChannels
|
|||
if timer == @timers[channel].call
|
||||
if @sizes[channel] > 0
|
||||
log "Timer overflow good; channel:#{channel}, timer:#{timer}".colorize.fore(:yellow)
|
||||
@latches[channel] = @fifos[channel][@positions[channel]].to_i16
|
||||
@latches[channel] = @fifos[channel][@positions[channel]].to_i16 << 1 # put on scale of -0x100..0x100
|
||||
@positions[channel] = (@positions[channel] + 1) % 32
|
||||
@sizes[channel] -= 1
|
||||
else
|
||||
|
|
Loading…
Add table
Reference in a new issue