[BGM] Fix incorrect SFX data, change tie handling to accomodate weird edge cases

This commit is contained in:
Luke Hubmayer-Werner 2024-07-17 22:03:27 +09:30
parent 38a822362a
commit 59de8aa820
6 changed files with 94 additions and 62 deletions

View File

@ -11,12 +11,16 @@ locations_bg_palettes 0x03BB00 /nar/ff5_binx.bin 0x03BF80 43 of 128 of ColorBGR5
font_glyphs_dialogue 0x03E800 256 of SNESTritile length 0x1800 font_glyphs_dialogue 0x03E800 256 of SNESTritile length 0x1800
spc_note_durations 0x041D7E 14 of u8 spc_note_durations 0x041D7E 14 of u8
bytelength_sfx_brr_data 0x041E3F u16 Used by the memcpy routine that copies the below data to the SPC (0x010E = 270 bytes = 16 BRR packets = 480 samples) bytelength_sfx_brr_data 0x041E3F u16 Used by the memcpy routine that copies the below data to the SPC (0x010E = 270 bytes = 16 BRR packets = 480 samples)
sfx_brr_data 0x041E41 Use the below SPC pointers sfx_brr_data 0x041E41 270 of u8 Use the below SPC pointers
bytelength_sfx_brr_pointers 0x041F4F u16 Used by the memcpy routine that copies the below data to the SPC (0x0020 = 32 bytes) bytelength_sfx_brr_pointers 0x041F4F u16 Used by the memcpy routine that copies the below data to the SPC (0x0020 = 32 bytes)
sfx_brr_pointers 0x041F51 8 of 2 of u16 SPC memory addresses not ROM. Start address followed by loop address. sfx_brr_pointers 0x041F51 8 of 2 of u16 SPC memory addresses not ROM. Start address followed by loop address.
sfx_adsrs 0x041F71 8 of 4 of u4 bytelength_sfx_adsrs 0x041F71 u16 0x0010 = 16 bytes
sfx_samplerates 0x041F83 8 of u16 sfx_adsrs 0x041F73 8 of 4 of u4
sfx_data 0x041F95 Contains SPC pointers and tracks bytelength_sfx_samplerates 0x041F83 u16 0x0010 = 16 bytes
sfx_samplerates 0x041F85 8 of u16
bytelength_sfx_data 0x041F95 u16 0x1C00 = 7168 bytes
sfx_sequence_pointers 0x041F97 256 of 2 of u16 Contains SPC pointers. Subtract 0x3000 to get position within next block. Each SFX sequence has two channels.
sfx_sequences 0x042397 6144 of u8 0x1800 = 6144 bytes
bgm_song_pointers 0x043B97 72 of u24 bgm_song_pointers 0x043B97 72 of u24
bgm_instrument_brr_pointers 0x043C6F 35 of u24 bgm_instrument_brr_pointers 0x043C6F 35 of u24
bgm_instrument_loop_starts 0x043CD8 35 of u16 bgm_instrument_loop_starts 0x043CD8 35 of u16
@ -27,16 +31,19 @@ bgm_instrument_indices 0x043DAA 72 of 16 of u16 length 0x900
worldmap_compressed_tilesets 0x070000 tilesets 0 up to 0x434 worldmap_compressed_tilesets 0x070000 tilesets 0 up to 0x434
worldmap_compressed_tilesets2 0x080000 tilesets 0x434 up to 0x500 worldmap_compressed_tilesets2 0x080000 tilesets 0x434 up to 0x500
ptrs_jp_speech 0x082220 2160 of u16 ptrs_jp_speech 0x082220 2160 of u16
ptrs_extended_event_data 0x083320 1940 of u24 ptrs_event_scripts 0x083320 1940 of u24
extended_event_data 0x0849DC See above for addresses event_scripts 0x0849DC See above for addresses
jp_speech 0x0A0000 See 0x082220 for offsets jp_speech 0x0A0000 See 0x082220 for offsets
ptrs_tilemaps 0x0B0000 328 of u16 ptrs_tilemaps 0x0B0000 328 of u16
tilemaps 0x0B0290 See above for offsets tilemaps 0x0B0290 See above for offsets
ptrs_npc_actions 0x0E0000 928 of u16 map_palette_animation 0x0DFA40 15 of 24 of u8 Need new struct
npc_actions 0x0E0740 See above for offsets map_palette_animation_colors 0x0DFBA8 44 of ColorBGR555
ptrs_event_places 0x0E2400 512 of u16
event_places 0x0E2800 920 of EventPlace See above for offsets ptrs_npc_scripts 0x0E0000 928 of u16
npc_scripts 0x0E0740 See above for offsets
ptrs_event_triggers 0x0E2400 512 of u16
event_triggers 0x0E2800 920 of EventPlace See above for offsets
ptrs_zone_exits 0x0E36C0 512 of u16 ptrs_zone_exits 0x0E36C0 512 of u16
zone_exits 0x0E3AC0 See above for offsets zone_exits 0x0E3AC0 See above for offsets
ptrs_npc_data 0x0E59C0 512 of u16 ptrs_npc_data 0x0E59C0 512 of u16
@ -50,7 +57,7 @@ ptrs_tile_properties 0x0FC540 23 of u16
tile_properties 0x0FC56E See above for offsets tile_properties 0x0FC56E See above for offsets
worldmap_minimap_border_tiles 0x0FD800 32 of TileSNES4bpp length 0x400 worldmap_minimap_border_tiles 0x0FD800 32 of TileSNES4bpp length 0x400
ptrs_worldmap_tilesets 0x0FE000 5 of 256 of u16 Every offset points to a horizontal line of 256 tiles stored in banks C7 and C8 ptrs_worldmap_tilesets 0x0FE000 5 of 256 of u16 Every offset points to a horizontal line of 256 tiles stored in banks C7 and C8
worldmap_block_properties 0x0FEA00 3 of 192 of WorldMapBlockProperties worldmap_block_properties 0x0FEA00 3 of 192 of WorldMapBlockProperties
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_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 worldmap_tiles.bias 0x0FF9C0 /nar/ff5_bin3.bin 0x03FB00 3 of 256 of u8 Add to each pixel of the mode7c tiles
worldmap_palettes 0x0FFCC0 /nar/ff5_binx.bin 0x040000 3 of 128 of ColorBGR555 worldmap_palettes 0x0FFCC0 /nar/ff5_binx.bin 0x040000 3 of 128 of ColorBGR555
@ -125,8 +132,9 @@ ptrs_battle_background_tileset_skips 0x184157 21 of u24 RAM addresses, subtrac
ptrs_battle_background_tilesets 0x184196 21 of u24 ROM addresses, subtract 0xC00000 ptrs_battle_background_tilesets 0x184196 21 of u24 ROM addresses, subtract 0xC00000
lzss_battle_background_tilesets 0x1841D5 see pointers above, 4bpp lzss_battle_background_tilesets 0x1841D5 see pointers above, 4bpp
? 0x18DE36 ? 0x18DE36
ptrs_event_data 0x18E080 687 of u16 initial_npc_flags 0x18E000 128 of u8
event_data 0x18E5E0 see above, links to extended event data ptrs_trigger_scripts 0x18E080 704 of u16 offset from this same address
trigger_scripts 0x18E600 see above, links to event scripts too
tiles_attack_anims 0x190000 tiles_attack_anims 0x190000
ptrs_anim_unk1 0x19A486 405 of u16 bank offsets to below ptrs_anim_unk1 0x19A486 405 of u16 bank offsets to below
0x19A7B0 padding 0x19A7B0 padding
@ -139,4 +147,11 @@ worldmap_tiles.1 0x1BA000 /nar/ff5_bin3.bin 0x039B00 256 of TileSNESMode7c Add t
worldmap_tiles.2 0x1BC000 /nar/ff5_bin3.bin 0x039B00 128 of TileSNESMode7c Add the biases worldmap_tiles.2 0x1BC000 /nar/ff5_bin3.bin 0x039B00 128 of TileSNESMode7c Add the biases
font_glyphs_kanji 0x1BD000 426 of SNESTritile length of 0x27F0 font_glyphs_kanji 0x1BD000 426 of SNESTritile length of 0x27F0
? 0x1BF800 ? 0x1BF800
ptrs_map_bg3_graphics 0x1C0000 18 of u16 From start of region (0x1C0024)
map_bg3_graphics 0x1C0024 2bpp
ptrs_map_graphics 0x1C2D84 40 of u32 From start of region (0x1C2E24)
map_graphics 0x1C2E24 4bpp
map_animation_graphics 0x1F9B00
map_palettes 0x1FFC00 32 of 16 of ColorBGR555
RPGe_font_character_widths 0x203225 512 of u8 RPGe only, Includes the 1px spacing RPGe_font_character_widths 0x203225 512 of u8 RPGe only, Includes the 1px spacing

Can't render this file because it has a wrong number of fields in line 53.

View File

@ -6,7 +6,8 @@ var MUSIC := music.new()
const NUM_TRACKS := 8 # TODO const NUM_TRACKS := 8 # TODO
const MAX_NOTE_EVENTS := 2048 const MAX_NOTE_EVENTS := 2048
class NoteEvent: class NoteEvent:
var p_start: int # In pulse space var p_event_start: int # In pulse space
var p_note_start: int # For tied notes, this will be earlier than p_event_start and is used for envelope calculations
var p_end: int var p_end: int
var instrument: int var instrument: int
var pitch: int var pitch: int
@ -94,13 +95,13 @@ class TrackCurve: # built-in Curve class is too restrictive for this
return 0.0 return 0.0
static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none') -> Array: # [data: PoolByteArray, target_time_length: float in seconds] static func render_channels(tracks: Array, inst_map: Array, _debug_name := 'none') -> Array: # [data: PoolByteArray, target_time_length: float in seconds]
# Since some channels contain global events (tempo and global volume for now), # Since some channels contain global events (tempo and global volume for now),
# the strategy will be to preprocess each channel in a global-state-agnostic way, # the strategy will be to preprocess each channel in a global-state-agnostic way,
# then once all the global tracks are known, as well as the longest unlooped length, # then once all the global tracks are known, as well as the longest unlooped length,
# do a second pass to generate the final events # do a second pass to generate the final events
# self.print_channel_events(inst_map) # self.print_channel_events(inst_map)
var instrument_adsrs = RomLoader.snes_data.bgm_instrument_adsrs # TODO: UNHARDCODE THIS var sample_default_adsrs = RomLoader.snes_data.sfx_adsrs + RomLoader.snes_data.bgm_instrument_adsrs # TODO: UNHARDCODE THIS
var all_note_events = [] var all_note_events = []
var curve_master_volume := TrackCurve.new(100.0/255.0) # [0.0, 1.0] for now var curve_master_volume := TrackCurve.new(100.0/255.0) # [0.0, 1.0] for now
@ -157,6 +158,8 @@ static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none'
infinite_loop_target_program_counter = track[-1][1] infinite_loop_target_program_counter = track[-1][1]
var program_counter := 0 var program_counter := 0
var last_note_pretransform_pitch := -2
var last_untied_note_p_start := 0
while true: #num_notes < MAX_NOTE_EVENTS: while true: #num_notes < MAX_NOTE_EVENTS:
if program_counter >= l: if program_counter >= l:
break break
@ -167,8 +170,8 @@ static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none'
match event[0]: # Control codes match event[0]: # Control codes
EventType.GOTO: # This is a preprocessed event list, so GOTO is a final infinite loop marker EventType.GOTO: # This is a preprocessed event list, so GOTO is a final infinite loop marker
var note_event = NoteEvent.new() var note_event = NoteEvent.new()
note_event.p_start = p note_event.p_event_start = p
note_event.p_end = infinite_loop_target_pulse # Fake final note event using p_start > p_end to encode the infinite jump back loop. note_event.p_end = infinite_loop_target_pulse # Fake final note event using p_event_start > p_end to encode the infinite jump back loop.
# Note that event[1] points to an Event, not a NoteEvent, not a Pulse, so we looked it up earlier # Note that event[1] points to an Event, not a NoteEvent, not a Pulse, so we looked it up earlier
channel_note_events.append(note_event) channel_note_events.append(note_event)
break break
@ -187,9 +190,12 @@ static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none'
var note = event[1] var note = event[1]
var duration = event[2] var duration = event[2]
if note >= 0: # Don't shift or play rests if note >= 0: # Don't shift or play rests
last_note_pretransform_pitch = note # Ties reuse this
last_untied_note_p_start = p
note += (12 * current_octave) + current_transpose note += (12 * current_octave) + current_transpose
var note_event = NoteEvent.new() var note_event = NoteEvent.new()
note_event.p_start = p note_event.p_event_start = p
note_event.p_note_start = p
note_event.p_end = p + duration note_event.p_end = p + duration
note_event.instrument = current_instrument note_event.instrument = current_instrument
note_event.pitch = note # pitch_idx #* curve_fine_tuning note_event.pitch = note # pitch_idx #* curve_fine_tuning
@ -201,12 +207,20 @@ static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none'
channel_note_events.append(note_event) channel_note_events.append(note_event)
# num_notes += 1 # num_notes += 1
elif note == music.NOTE_IS_TIE: elif note == music.NOTE_IS_TIE:
if not channel_note_events: if last_note_pretransform_pitch >= 0:
print('Encountered a tie with no preceeding note! %s channel %d pulse %d (loop return is %d)' % [debug_name, channel, p, infinite_loop_target_pulse]) note = last_note_pretransform_pitch + (12 * current_octave) + current_transpose
else: var note_event = NoteEvent.new()
if channel_note_events[-1].p_end != p: note_event.p_event_start = p
print('Encountered a tie with preceeding rest! %s channel %d pulse %d (loop return is %d)' % [debug_name, channel, p, infinite_loop_target_pulse]) note_event.p_note_start = last_untied_note_p_start
channel_note_events[-1].p_end += duration note_event.p_end = p + duration
note_event.instrument = current_instrument
note_event.pitch = note # pitch_idx #* curve_fine_tuning
note_event.velocity = curve_velocity.get_pulse(p) # current_velocity
note_event.adsr_attack_rate = current_adsr_attack_rate
note_event.adsr_decay_rate = current_adsr_decay_rate
note_event.adsr_sustain_level = current_adsr_sustain_level
note_event.adsr_sustain_rate = current_adsr_sustain_rate
channel_note_events.append(note_event)
p += duration p += duration
EventType.VOLUME: EventType.VOLUME:
var new_velocity: float = event[1]/255.0 var new_velocity: float = event[1]/255.0
@ -248,18 +262,18 @@ static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none'
scale = fine_tune/255.0 scale = fine_tune/255.0
curve_fine_tuning.add_point(p, scale) curve_fine_tuning.add_point(p, scale)
EventType.PROGCHANGE: EventType.PROGCHANGE:
var event_idx = event[1]-0x20 current_instrument = event[1]
if event_idx >= 0: if current_instrument >= 0x20:
current_instrument = inst_map[event_idx] - 1 current_instrument = inst_map[current_instrument-0x20] - 1 + SoundLoader.SFX_NUM
if current_instrument < len(instrument_adsrs) and current_instrument > 0: if current_instrument < len(sample_default_adsrs) and current_instrument > 0:
var adsr = instrument_adsrs[current_instrument] var adsr = sample_default_adsrs[current_instrument]
current_adsr_attack_rate = adsr[0] current_adsr_attack_rate = adsr[0]
current_adsr_decay_rate = adsr[1] current_adsr_decay_rate = adsr[1]
current_adsr_sustain_level = adsr[2] current_adsr_sustain_level = adsr[2]
current_adsr_sustain_rate = adsr[3] current_adsr_sustain_rate = adsr[3]
EventType.ADSR_DEFAULT: # TODO - Investigate actual scaling and order EventType.ADSR_DEFAULT: # TODO - Investigate actual scaling and order
if current_instrument < len(instrument_adsrs) and current_instrument > 0: if current_instrument < len(sample_default_adsrs) and current_instrument > 0:
var adsr = instrument_adsrs[current_instrument] var adsr = sample_default_adsrs[current_instrument]
current_adsr_attack_rate = adsr[0] current_adsr_attack_rate = adsr[0]
current_adsr_decay_rate = adsr[1] current_adsr_decay_rate = adsr[1]
current_adsr_sustain_level = adsr[2] current_adsr_sustain_level = adsr[2]
@ -339,13 +353,13 @@ static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none'
continue continue
var note_event: NoteEvent = all_note_events[channel][-1] var note_event: NoteEvent = all_note_events[channel][-1]
var p_end = note_event.p_end var p_end = note_event.p_end
if p_end < note_event.p_start: if p_end < note_event.p_event_start:
# Ends on infinite loop # Ends on infinite loop
channel_loop_p_returns.append(p_end) channel_loop_p_returns.append(p_end)
channel_loop_p_lengths.append(note_event.p_start - p_end) channel_loop_p_lengths.append(note_event.p_event_start - p_end)
if p_end > highest_channel_p_return: if p_end > highest_channel_p_return:
highest_channel_p_return = p_end highest_channel_p_return = p_end
p_end = note_event.p_start p_end = note_event.p_event_start
else: else:
channel_loop_p_returns.append(-1) channel_loop_p_returns.append(-1)
channel_loop_p_lengths.append(0) channel_loop_p_lengths.append(0)
@ -365,7 +379,8 @@ static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none'
var loop_return_p = channel_loop_p_returns[channel] var loop_return_p = channel_loop_p_returns[channel]
var curve_pan: TrackCurve = curve_channel_pans[channel] var curve_pan: TrackCurve = curve_channel_pans[channel]
var midi_events_bytes_t_start := StreamPeerBuffer.new() var midi_events_bytes_t_event_start := StreamPeerBuffer.new()
var midi_events_bytes_t_note_start := StreamPeerBuffer.new()
var midi_events_bytes_t_end := StreamPeerBuffer.new() var midi_events_bytes_t_end := StreamPeerBuffer.new()
var midi_events_bytes3 := StreamPeerBuffer.new() var midi_events_bytes3 := StreamPeerBuffer.new()
var midi_events_bytes_adsr := StreamPeerBuffer.new() var midi_events_bytes_adsr := StreamPeerBuffer.new()
@ -381,10 +396,11 @@ static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none'
event_ptr = loop_return_note_event_idx event_ptr = loop_return_note_event_idx
loop_p_offset += channel_loop_p_lengths[channel] loop_p_offset += channel_loop_p_lengths[channel]
var event: NoteEvent = events[event_ptr] var event: NoteEvent = events[event_ptr]
var p = event.p_start var p = event.p_event_start
if loop_return_note_event_idx < 0 and p >= loop_return_p: if loop_return_note_event_idx < 0 and p >= loop_return_p:
loop_return_note_event_idx = event_ptr loop_return_note_event_idx = event_ptr
midi_events_bytes_t_start.put_32(int(curve_master_tempo.get_integral(p + loop_p_offset) * 32000)) midi_events_bytes_t_event_start.put_32(int(curve_master_tempo.get_integral(p + loop_p_offset) * 32000))
midi_events_bytes_t_note_start.put_32(int(curve_master_tempo.get_integral(event.p_note_start + loop_p_offset) * 32000))
midi_events_bytes_t_end.put_32(int(curve_master_tempo.get_integral(event.p_end + loop_p_offset) * 32000)) # t_end midi_events_bytes_t_end.put_32(int(curve_master_tempo.get_integral(event.p_end + loop_p_offset) * 32000)) # t_end
midi_events_bytes3.put_u8(event.instrument) midi_events_bytes3.put_u8(event.instrument)
midi_events_bytes3.put_u8(event.pitch) midi_events_bytes3.put_u8(event.pitch)
@ -399,11 +415,12 @@ static func render_channels(tracks: Array, inst_map: Array, debug_name := 'none'
num_notes += 1 num_notes += 1
# Fill up end of notes array with dummies # Fill up end of notes array with dummies
for i in range(num_notes, MAX_NOTE_EVENTS): for i in range(num_notes, MAX_NOTE_EVENTS):
midi_events_bytes_t_start.put_32(0x0FFFFFFF) midi_events_bytes_t_event_start.put_32(0x0FFFFFFF)
midi_events_bytes_t_note_start.put_32(0x0FFFFFFF)
midi_events_bytes_t_end.put_32(0x0FFFFFFF) midi_events_bytes_t_end.put_32(0x0FFFFFFF)
midi_events_bytes3.put_32(0) midi_events_bytes3.put_32(0)
midi_events_bytes_adsr.put_32(0) midi_events_bytes_adsr.put_32(0)
data += midi_events_bytes_t_start.data_array + midi_events_bytes_t_end.data_array + midi_events_bytes3.data_array + midi_events_bytes_adsr.data_array data += midi_events_bytes_t_event_start.data_array + midi_events_bytes_t_end.data_array + midi_events_bytes3.data_array + midi_events_bytes_adsr.data_array + midi_events_bytes_t_note_start.data_array
var smp_loop_start = -1 var smp_loop_start = -1
var smp_loop_end = -1 var smp_loop_end = -1
if highest_channel_p_return > 0: if highest_channel_p_return > 0:
@ -431,11 +448,11 @@ static func disassemble_channel_events(channel_events: Array, inst_map: Array) -
output.append(print_str + print_str2) output.append(print_str + print_str2)
p += duration p += duration
EventType.PROGCHANGE: EventType.PROGCHANGE:
var event_idx = event[1]-0x20 var event_idx = event[1]
if event_idx >= 0: if event_idx >= 0x20:
output.append(print_str + 'instrument %02d'%(inst_map[event_idx] - 1)) output.append(print_str + '($%02x) = instrument %02d'%[event_idx, inst_map[event_idx-0x20] - 1])
else: else:
output.append(print_str + print_str2) output.append(print_str + 'sfx %d'%event_idx)
_: _:
output.append(print_str + print_str2) output.append(print_str + print_str2)
return output return output

View File

@ -148,7 +148,7 @@ func load_sfx_samples_data(snes_data: Dictionary, buffer: StreamPeerBuffer):
for two_of_u16 in snes_data.sfx_brr_pointers: for two_of_u16 in snes_data.sfx_brr_pointers:
brr_spc_addrs.append(two_of_u16[0]) brr_spc_addrs.append(two_of_u16[0])
brr_spc_loop_addrs.append(two_of_u16[1]) brr_spc_loop_addrs.append(two_of_u16[1])
var brr_spc_start = Common.SNES_PSX_addresses.sfx_brr_data.SNES - brr_spc_addrs[0] # Refactor this later var brr_spc_start = Common.SNES_PSX_addresses.sfx_brr_data.SNES - brr_spc_addrs[0] # Refactor this later - SFX samples start at $4800 in ARAM, right after the SFX tracks
for i in SFX_NUM: for i in SFX_NUM:
buffer.seek(brr_spc_addrs[i] + brr_spc_start) buffer.seek(brr_spc_addrs[i] + brr_spc_start)
# print('Loading sfx sample #%X with BRR data offset $%06X' % [i, buffer.get_position()]) # print('Loading sfx sample #%X with BRR data offset $%06X' % [i, buffer.get_position()])
@ -156,7 +156,7 @@ func load_sfx_samples_data(snes_data: Dictionary, buffer: StreamPeerBuffer):
var audio := make_sample(buffer, 900, sample_rate) var audio := make_sample(buffer, 900, sample_rate)
var loop_start_packet: int = brr_spc_loop_addrs[i] - brr_spc_addrs[i] var loop_start_packet: int = brr_spc_loop_addrs[i] - brr_spc_addrs[i]
audio.loop_mode = AudioStreamSample.LOOP_FORWARD audio.loop_mode = AudioStreamSample.LOOP_FORWARD
audio.loop_begin = loop_start_packet * 16 # Each 9byte packet is 16 samples audio.loop_begin = (loop_start_packet/9) * 16 # Each 9byte packet is 16 samples
audio.loop_end = (len(audio.data)/2) audio.loop_end = (len(audio.data)/2)
sfx_samples.append(audio) # Use 900 as a limit, it won't be hit, parser stops after End packet anyway 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) emit_signal('audio_sfx_sample_loaded', i)
@ -186,14 +186,14 @@ var samples_tex: ImageTexture
const TEX_WIDTH := 2048 const TEX_WIDTH := 2048
const FILTER_PAD := 32 const FILTER_PAD := 32
func samples_to_texture(): func samples_to_texture():
var num_samples := INST_NUM + SFX_NUM var num_samples := SFX_NUM + INST_NUM
var header_length := num_samples * 5 var header_length := num_samples * 5
# Create header and unwrapped payload separately first # Create header and unwrapped payload separately first
var header_buffer := StreamPeerBuffer.new() var header_buffer := StreamPeerBuffer.new()
var payload_buffer := StreamPeerBuffer.new() var payload_buffer := StreamPeerBuffer.new()
for sample in instrument_samples + sfx_samples: for sample in sfx_samples + instrument_samples:
var sample_data_start: int = header_length + (payload_buffer.get_position()/2) + FILTER_PAD # After the prepended silence, in texels (2bytes) var sample_data_start: int = header_length + (payload_buffer.get_position()/2) + FILTER_PAD # After the prepended silence, in texels (2bytes)
var loop_begin: int = sample.loop_begin var loop_begin: int = sample.loop_begin
var loop_length: int = sample.loop_end - loop_begin var loop_length: int = sample.loop_end - loop_begin

View File

@ -118,11 +118,10 @@ class StructArrayType extends StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array): func get_value(buffer: StreamPeer, leftover_bits: Array):
# Might be a bit too much branching but oh well # Might be a bit too much branching but oh well
if self.contained_struct_type is U8: if self.contained_struct_type is U8:
var result = PoolByteArray()
# Slight optimization over calling the method # Slight optimization over calling the method
for i in self.count: var result = buffer.get_data(self.count)
result.append(buffer.get_u8()) # result[0] is an error code
return result return result[1]
var result = [] var result = []
for i in self.count: for i in self.count:

View File

@ -172,7 +172,7 @@ highp float get_instrument_sample(highp float instrument_index, highp float note
} }
// const int ATTACK_TIME_MS[16] = {4100, 2600, 1500, 1000, 640, 380, 260, 160, 96, 64, 40, 24, 16, 10, 6, 0}; // const int ATTACK_TIME_MS[16] = {4100, 2600, 1500, 1000, 640, 380, 260, 160, 96, 64, 40, 24, 16, 10, 6, 0};
const int ATTACK_TIME_SMPS[16] = {131200, 83200, 48000, 32000, 20480, 12160, 8320, 5120, 3072, 2048, 1280, 768, 512, 320, 192, 1}; const int ATTACK_TIME_SMPS[16] = {131200, 83200, 48000, 32000, 20480, 12160, 8320, 5120, 3072, 2048, 1280, 768, 512, 320, 192, 0};
// const int DECAY_TIME_MS[8] = {1200, 740, 440, 290, 180, 110, 74, 37}; // const int DECAY_TIME_MS[8] = {1200, 740, 440, 290, 180, 110, 74, 37};
const int DECAY_TIME_SMPS[8] = {38400, 23680, 14080, 9280, 5760, 3520, 2368, 1184}; const int DECAY_TIME_SMPS[8] = {38400, 23680, 14080, 9280, 5760, 3520, 2368, 1184};
// const int SUSTAIN_DECAY_TIME_MS[32] = {Infinite, 38000, 28000, 24000, 19000, 14000, 12000, 9400, 7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500, 1200, 880, 740, 590, 440, 370, 290, 220, 180, 150, 110, 92, 74, 55, 37, 18}; // const int SUSTAIN_DECAY_TIME_MS[32] = {Infinite, 38000, 28000, 24000, 19000, 14000, 12000, 9400, 7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500, 1200, 880, 740, 590, 440, 370, 290, 220, 180, 150, 110, 92, 74, 55, 37, 18};
@ -202,7 +202,7 @@ highp vec4 render_song(highp sampler2D tex, highp int smp) {
// Binary search the channels // Binary search the channels
for (int channel = 0; channel < NUM_CHANNELS; channel++) { for (int channel = 0; channel < NUM_CHANNELS; channel++) {
highp float row = float(channel * 4); highp float row = float(channel * 5);
highp float event_idx = 0.0; highp float event_idx = 0.0;
highp int smp_start; highp int smp_start;
for (int i = 0; i < NUM_CHANNEL_NOTE_PROBES; i++) { for (int i = 0; i < NUM_CHANNEL_NOTE_PROBES; i++) {
@ -212,6 +212,7 @@ highp vec4 render_song(highp sampler2D tex, highp int smp) {
} }
smp_start = retime_smp(int(unpack_int32(get_midi_texel(tex, event_idx, row)))); smp_start = retime_smp(int(unpack_int32(get_midi_texel(tex, event_idx, row))));
highp int smp_end = retime_smp(int(unpack_int32(get_midi_texel(tex, event_idx, row+1.0)))); highp int smp_end = retime_smp(int(unpack_int32(get_midi_texel(tex, event_idx, row+1.0))));
highp int smp_note_start = retime_smp(int(unpack_int32(get_midi_texel(tex, event_idx, row+4.0))));
highp vec4 note_event_supplement = get_midi_texel(tex, event_idx, row+2.0); // left as [0.0, 1.0] highp vec4 note_event_supplement = get_midi_texel(tex, event_idx, row+2.0); // left as [0.0, 1.0]
highp float instrument_idx = trunc(note_event_supplement.x * 255.0); highp float instrument_idx = trunc(note_event_supplement.x * 255.0);
@ -228,12 +229,12 @@ highp vec4 render_song(highp sampler2D tex, highp int smp) {
highp int smp_decay = DECAY_TIME_SMPS[adsr.y]; highp int smp_decay = DECAY_TIME_SMPS[adsr.y];
// For now, just branch this // For now, just branch this
if (smp_start < smp) { // First sample may not start at zero! if (smp_note_start < smp) { // First sample may not start at zero!
highp int smp_overrun = smp - smp_end; // 256 samples of linear decay to 0 after note_off highp int smp_overrun = smp - smp_end; // 256 samples of linear decay to 0 after note_off
smp_overrun = (smp_overrun < 0) ? 0 : smp_overrun; smp_overrun = (smp_overrun < 0) ? 0 : smp_overrun;
if (smp_overrun < 256) { if (smp_overrun < 256) {
highp int smp_progress = smp - smp_start; highp int smp_progress = smp - smp_note_start;
highp float t_start = float(smp_start)/output_mixrate; highp float t_start = float(smp_note_start)/output_mixrate;
highp float attack_factor = clamp(float(smp_progress)/float(smp_attack), 0.0, 1.0); highp float attack_factor = clamp(float(smp_progress)/float(smp_attack), 0.0, 1.0);
highp float decay_factor = mix(1.0, sustain_level, clamp(float(smp_progress - smp_attack)/float(smp_decay), 0.0, 1.0)); highp float decay_factor = mix(1.0, sustain_level, clamp(float(smp_progress - smp_attack)/float(smp_decay), 0.0, 1.0));
highp float sustain_decay_factor = 1.0; highp float sustain_decay_factor = 1.0;

View File

@ -161,7 +161,7 @@ func push_image(image: Image, target_samples: int, key: String, enqueue: bool =
func push_bytes(data: PoolByteArray, target_samples: int, key: String, enqueue: bool = true) -> void: func push_bytes(data: PoolByteArray, target_samples: int, key: String, enqueue: bool = true) -> void:
var rows = int(pow(2, ceil(log((len(data)/INPUT_BYTES_PER_TEXEL) / INPUT_TEX_WIDTH)/log(2)))) var rows = int(pow(2, ceil(log((len(data)/INPUT_BYTES_PER_TEXEL) / INPUT_TEX_WIDTH)/log(2))))
var target_length = rows * INPUT_BYTES_PER_TEXEL * INPUT_FORMAT var target_length = rows * INPUT_BYTES_PER_TEXEL * INPUT_TEX_WIDTH
while len(data) < target_length: # This is inefficient, but this function should be called with pre-padded data anyway while len(data) < target_length: # This is inefficient, but this function should be called with pre-padded data anyway
data.append(0) data.append(0)
var image := Image.new() var image := Image.new()