Prepend silence to samples

Also switch most of sample loading to struct pointers
This commit is contained in:
Luke Hubmayer-Werner 2023-08-24 14:54:32 +09:30
parent a6181cb776
commit 0ef19b45a7
3 changed files with 54 additions and 44 deletions

View File

@ -3,6 +3,17 @@ character_battle_sprite_stone_palette 0x00F807 N/A N/A Palette16Of555 Also 0x199
character_battle_sprite_disabled_palette 0x00F867 /mnu/memsave.bin 0x000034 Palette16Of555
locations_bg_palettes 0x03BB00 /nar/ff5_binx.bin 0x03BF80 43 of Palette128Of555
font_glyphs_dialogue 0x03E800 256 of SNESTritile length 0x1800
sfx_brr_data 0x041E3F Use the below SPC pointers
sfx_brr_pointers 0x041F4F 8 of 2 of u16 SPC memory addresses not ROM. Start address followed by loop address.
sfx_adsrs 0x041F71 8 of u16
sfx_samplerates 0x041F83 8 of u16
sfx_data 0x041F95 Contains SPC pointers and tracks
bgm_song_pointers 0x043B97 72 of u24
bgm_instrument_brr_pointers 0x043C6F 35 of u24
bgm_instrument_loop_starts 0x043CD8 35 of u16
bgm_instrument_samplerates 0x043D1E 35 of u16
bgm_instrument_adsrs 0x043D64 35 of u16
bgm_instrument_indices 0x043DAA 72 of 16 of u16 length 0x900
enemy_battle_sprite_palettes 0x0ED000 See enemy_battle_sprite_data for pointers. Some are 8 colours instead of 16.
worldmap_blocks 0x0FF0C0 /nar/ff5_binx.bin 0x040300 3 of 4 of 192 of u8 # Top-left corners, top-right corners, bottom-left corners, bottom-right corners
worldmap_tiles.bias 0x0FF9C0 /nar/ff5_bin3.bin 0x03FB00 3 of 256 of u8 Add to each pixel of the mode7c tiles

1 Label SNES PSX_file PSX_offset format Comment
3 character_battle_sprite_disabled_palette 0x00F867 /mnu/memsave.bin 0x000034 Palette16Of555
4 locations_bg_palettes 0x03BB00 /nar/ff5_binx.bin 0x03BF80 43 of Palette128Of555
5 font_glyphs_dialogue 0x03E800 256 of SNESTritile length 0x1800
6 sfx_brr_data 0x041E3F Use the below SPC pointers
7 sfx_brr_pointers 0x041F4F 8 of 2 of u16 SPC memory addresses not ROM. Start address followed by loop address.
8 sfx_adsrs 0x041F71 8 of u16
9 sfx_samplerates 0x041F83 8 of u16
10 sfx_data 0x041F95 Contains SPC pointers and tracks
11 bgm_song_pointers 0x043B97 72 of u24
12 bgm_instrument_brr_pointers 0x043C6F 35 of u24
13 bgm_instrument_loop_starts 0x043CD8 35 of u16
14 bgm_instrument_samplerates 0x043D1E 35 of u16
15 bgm_instrument_adsrs 0x043D64 35 of u16
16 bgm_instrument_indices 0x043DAA 72 of 16 of u16 length 0x900
17 enemy_battle_sprite_palettes 0x0ED000 See enemy_battle_sprite_data for pointers. Some are 8 colours instead of 16.
18 worldmap_blocks 0x0FF0C0 /nar/ff5_binx.bin 0x040300 3 of 4 of 192 of u8 # Top-left corners, top-right corners, bottom-left corners, bottom-right corners
19 worldmap_tiles.bias 0x0FF9C0 /nar/ff5_bin3.bin 0x03FB00 3 of 256 of u8 Add to each pixel of the mode7c tiles

View File

@ -60,6 +60,9 @@ func load_snes_structs(buffer: StreamPeerBuffer) -> Dictionary:
data.job_levels.append(ability_list)
return data
func load_snes_audio_thread(data_and_buffer: Array):
SoundLoader.parse_rom(data_and_buffer[0], data_and_buffer[1])
func load_snes_rom(filename: String):
var error := rom_snes.open(filename, File.READ)
if error == OK:
@ -71,11 +74,12 @@ func load_snes_rom(filename: String):
var buffer = StreamPeerBuffer.new()
buffer.data_array = bytes
StringLoader.load_snes_rom(buffer, true)
# Give this its own buffer, avoid file pointer conflicts
var _thread_error = thread.start(SoundLoader, 'parse_rom', buffer.duplicate())
self.snes_data = load_snes_structs(buffer)
#print(snes_data.job_levels)
# Give this its own buffer, avoid file pointer conflicts
self.load_snes_audio_thread([self.snes_data, buffer.duplicate()])
# var _thread_error = thread.start(self, 'load_snes_audio_thread', [self.snes_data, buffer.duplicate()])
StringLoader.load_snes_rom(buffer, true)
SpriteLoader.load_from_structs(self.snes_data)
SpriteLoader.load_enemy_battle_sprites(self.snes_data, buffer)
SpriteLoader.load_battle_bgs(self.snes_data, buffer)

View File

@ -17,6 +17,8 @@ const SFX_BRR_SPC_TABLE := 0x041F4F + 2 # (first two bytes are the length of 0x0
const SFX_BRR_START := 0x041E3F + 2 # First two bytes are the length of the block, 0x010E = 270 bytes = 16 BRR packets = 480 samples
const SFX_ADSR := 0x041F71
const SFX_SR := 0x041F83
const PREPEND_MS := 50 # Prepend 20ms of silence to each sample for preplay purposes
const PLAY_START := PREPEND_MS / 1000.0
var bgm_tracks = []
var instrument_samples = []
var sfx_samples = []
@ -96,66 +98,59 @@ func make_sample(buffer: StreamPeerBuffer, size: int, sample_rate: int) -> Audio
break
# Convert int array to byte array
var audio_data = PoolByteArray()
for j in range(2, samples.size()):
var b = samples[j]
# Prepend silence, accounting for the two null samples
var silent_samples := ((sample_rate * PREPEND_MS) / 1000) - 2
audio_data.resize(silent_samples * 2) # 16bit samples in 8bit array
audio_data.fill(0)
# Pack 16bit samples to 8bit array
for b in samples:
audio_data.append(b & 0xFF)
audio_data.append(b >> 8)
audio.data = audio_data
return audio
func get_inst_sample_data(buffer: StreamPeerBuffer, id: int) -> AudioStreamSample:
buffer.seek(INST_SR + (id*2))
var tuning1 := buffer.get_u8()
var tuning2 := buffer.get_u8()
var sample_rate := get_reference_pitch_samplerate(tuning1)
buffer.seek(INST_LOOP + (id*2))
var loop_start_packet := buffer.get_u16()/9 # Note that Instrument $1F Steel Guitar has a length of $088B but a loop point of $088D which is 243.22... packets. Luckily it doesn't matter.
var lookup_offset := INST_BRR_LOOKUP + (id*3)
buffer.seek(lookup_offset)
var brr_offset := read_rom_address(buffer)
buffer.seek(brr_offset)
func get_inst_sample_data(snes_data: Dictionary, buffer: StreamPeerBuffer, id: int) -> AudioStreamSample:
var sample_rate := get_reference_pitch_samplerate(snes_data.bgm_instrument_samplerates[id] & 0xFF)
var silent_samples := ((sample_rate * PREPEND_MS) / 1000)
var loop_start_packet: int = snes_data.bgm_instrument_loop_starts[id]/9 # Note that Instrument $1F Steel Guitar has a length of $088B but a loop point of $088D which is 243.22... packets. Luckily it doesn't matter.
buffer.seek(snes_data.bgm_instrument_brr_pointers[id] & 0x3FFFFF)
var size := buffer.get_u16()
var num_samples := (size/9)*16
var audio := make_sample(buffer, size, sample_rate)
audio.loop_mode = AudioStreamSample.LOOP_FORWARD
audio.loop_begin = loop_start_packet * 16 # Each 9byte packet is 16 samples
audio.loop_end = num_samples-1
audio.loop_begin = (loop_start_packet * 16) + silent_samples # Each 9byte packet is 16 samples
audio.loop_end = silent_samples + num_samples - 1
# print_debug('Loaded instrument #%02X with lookup offset $%06X, BRR data offset $%06X, length $%04X (%f packets, %d samples) and loop point %d samples' % [id, lookup_offset, brr_offset, size, size/9.0, num_samples, audio.loop_begin])
return audio
func load_sfx_samples_data(buffer: StreamPeerBuffer):
var sample_rates = []
buffer.seek(SFX_SR)
for i in SFX_NUM:
var tuning1 := buffer.get_u8()
var tuning2 := buffer.get_u8()
sample_rates.append(get_reference_pitch_samplerate(tuning1))
func load_sfx_samples_data(snes_data: Dictionary, buffer: StreamPeerBuffer):
var brr_spc_addrs = []
var brr_spc_loop_addrs = []
buffer.seek(SFX_BRR_SPC_TABLE)
for two_of_u16 in snes_data.sfx_brr_pointers:
brr_spc_addrs.append(two_of_u16[0])
brr_spc_loop_addrs.append(two_of_u16[1])
var brr_spc_start = SFX_BRR_START - brr_spc_addrs[0] # Refactor this later to somehow reference sfx_brr_data address from the tsv
for i in SFX_NUM:
brr_spc_addrs.append(buffer.get_u16())
brr_spc_loop_addrs.append(buffer.get_u16())
var brr_spc_start = brr_spc_addrs[0]
for i in SFX_NUM:
brr_spc_addrs[i] += SFX_BRR_START - brr_spc_start
for i in SFX_NUM:
buffer.seek(brr_spc_addrs[i])
buffer.seek(brr_spc_addrs[i] + brr_spc_start)
# print('Loading sfx sample #%X with BRR data offset $%06X' % [i, buffer.get_position()])
sfx_samples.append(make_sample(buffer, 900, sample_rates[i])) # Use 900 as a limit, it won't be hit, parser stops after End packet anyway
var sample_rate := get_reference_pitch_samplerate(snes_data.sfx_samplerates[i] & 0xFF)
var silent_samples := ((sample_rate * PREPEND_MS) / 1000)
var audio := make_sample(buffer, 900, sample_rate)
var loop_start_packet: int = brr_spc_loop_addrs[i] - brr_spc_addrs[i]
audio.loop_mode = AudioStreamSample.LOOP_FORWARD
audio.loop_begin = (loop_start_packet * 16) + silent_samples # Each 9byte packet is 16 samples
audio.loop_end = (len(audio.data)/2) - 1
sfx_samples.append(audio) # Use 900 as a limit, it won't be hit, parser stops after End packet anyway
emit_signal('audio_sfx_sample_loaded', i)
# print('size of %d samples' % sfx_samples[i].data.size())
# Called when the node enters the scene tree for the first time.
func load_samples(buffer: StreamPeerBuffer):
load_sfx_samples_data(buffer)
func load_samples(snes_data: Dictionary, buffer: StreamPeerBuffer):
load_sfx_samples_data(snes_data, buffer)
# For some reason, this is a bit slow currently. Might optimize later.
for i in INST_NUM:
instrument_samples.append(get_inst_sample_data(buffer, i))
instrument_samples.append(get_inst_sample_data(snes_data, buffer, i))
emit_signal('audio_inst_sample_loaded', i)
@ -197,15 +192,15 @@ var player := AudioStreamPlayer.new() # Make one for each channel, later
func play_sample(id: int):
print('Playing inst sample #%02X' % id)
player.stream = instrument_samples[id]
player.play()
player.play(PLAY_START)
func play_sfx(id: int):
print('Playing sfx sample #%02X' % id)
player.stream = sfx_samples[id]
player.play()
player.play(PLAY_START)
func parse_rom(buffer: StreamPeerBuffer):
load_samples(buffer)
func parse_rom(snes_data: Dictionary, buffer: StreamPeerBuffer):
load_samples(snes_data, buffer)
#load_bgms(buffer)
has_loaded_audio_samples = true
emit_signal('audio_samples_loaded')