diff --git a/scripts/MusicPlayer.gd b/scripts/MusicPlayer.gd index c1c3270..c6359a0 100644 --- a/scripts/MusicPlayer.gd +++ b/scripts/MusicPlayer.gd @@ -86,7 +86,7 @@ func _init(tracks: Array, instrument_map: Dictionary): func play_channel(channel: int, time_offset: float = 0.0) -> int: # Executes the track events until it hits a note/rest, in which case it returns the pulse count to the next action, or the end of the events, in which case it returns -1 - self.players[channel].stop() + # self.players[channel].stop() var track: Array = self.tracks[channel] var l := len(track) var player: AudioStreamPlayer = self.players[channel] @@ -106,7 +106,10 @@ func play_channel(channel: int, time_offset: float = 0.0) -> int: player.volume_db = linear2db((self.channel_velocity[channel]/255.0) * (self.master_volume/255.0)) player.play(max((SoundLoader.PLAY_START - time_offset)/player.pitch_scale, 0)) self.channel_current_note[channel] = note + elif note == music.NOTE_IS_TIE: + pass else: + self.players[channel].stop() self.channel_current_note[channel] = -1 # TODO: Confirm tempo scaling return duration # Pulses to next instruction @@ -331,6 +334,7 @@ func render_channels(_t_start: float, _t_end: float, inst_map: Array) -> Array: # 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, # do a second pass to generate the final events + # self.print_channel_events(inst_map) var instrument_adsrs = RomLoader.snes_data.bgm_instrument_adsrs # TODO: UNHARDCODE THIS var all_note_events = [] @@ -412,6 +416,8 @@ func render_channels(_t_start: float, _t_end: float, inst_map: Array) -> Array: note_event.adsr_release = current_adsr_release channel_note_events.append(note_event) # num_notes += 1 + elif note == music.NOTE_IS_TIE: + channel_note_events[-1].p_end += duration p += duration EventType.VOLUME: var new_velocity: float = event[1]/255.0 @@ -612,3 +618,32 @@ func render_channels(_t_start: float, _t_end: float, inst_map: Array) -> Array: smp_loop_start = curve_master_tempo.get_integral(highest_channel_p_return + 100) * 32000 smp_loop_end = curve_master_tempo.get_integral(longest_channel_p_end + 100) * 32000 return [data, target_time_length, [smp_loop_start, smp_loop_end]] + +func print_channel_events(inst_map: Array) -> void: + for channel in self.num_tracks: + print('================Channel %d================'%channel) + var track: Array = self.tracks[channel] + var l := len(track) + var p := 0 # current pulse + for event in track: #num_notes < MAX_NOTE_EVENTS: + var print_str := 'p=%6d : %s '%[p, EventType.keys()[event[0]]] + match event[0]: + EventType.NOTE: + var note = event[1] + var duration = event[2] + match note: + music.NOTE_IS_REST: + print('p=%6d : NOTE_REST %d pulses'%[p, duration]) + music.NOTE_IS_TIE: + print('p=%6d : NOTE_TIE %d pulses'%[p, duration]) + _: + print(print_str, event.slice(1, -1)) + p += duration + EventType.PROGCHANGE: + var event_idx = event[1]-0x20 + if event_idx >= 0: + print(print_str, ' instrument %02d'%(inst_map[event_idx] - 1)) + else: + print(print_str, event.slice(1, -1)) + _: + print(print_str, event.slice(1, -1)) diff --git a/scripts/loaders/snes/music.gd b/scripts/loaders/snes/music.gd index 6fca066..a07ee87 100644 --- a/scripts/loaders/snes/music.gd +++ b/scripts/loaders/snes/music.gd @@ -1,5 +1,7 @@ const MAX_TRACKS := 8 const MAX_LOOP_DEPTH := 8 # Apparently 4, but eh whatever +const NOTE_IS_TIE := -1 +const NOTE_IS_REST := -2 enum EventType { ADSR_ATTACK, @@ -126,6 +128,8 @@ static func get_int_array(size: int) -> PoolIntArray: var EVENT_MAP: Dictionary var NOTE_DURATIONS: PoolByteArray # This might need to be made untyped if a future addition uses PoolIntArray instead var REFERENCE_NOTE: int +var NOTE_TIE: int +var NOTE_REST: int const LOGGING_LEVEL_INFO: bool = false func print_info(s: String) -> void: @@ -138,8 +142,11 @@ func translate_instruction(buffer: StreamPeer) -> Array: if instruction < 0xD2: var duration = self.NOTE_DURATIONS[instruction % 15] var note = instruction / 15 - if note >= 12: # 12 and 13 are rests - note = -1 + if note >= 12: # 12 and 13 are rests and ties + if note == self.NOTE_REST: + note = NOTE_IS_REST + else: + note = NOTE_IS_TIE return [EventType.NOTE, note, duration] else: # Control codes diff --git a/scripts/loaders/snes/music_ff5.gd b/scripts/loaders/snes/music_ff5.gd index 5140131..f54969e 100644 --- a/scripts/loaders/snes/music_ff5.gd +++ b/scripts/loaders/snes/music_ff5.gd @@ -5,6 +5,8 @@ func _init() -> void: # Durations are in pulses, 48 = 1 quarter note (crotchet) self.NOTE_DURATIONS = PoolByteArray([192, 144, 96, 64, 72, 48, 32, 36, 24, 16, 12, 8, 6, 4, 3]) # See ROM 0x041D7E to 0x041D8C self.REFERENCE_NOTE = 71 + self.NOTE_TIE = 12 + self.NOTE_REST = 13 self.EVENT_MAP = { 0xD2: EventType.VOLUME,