BGM: Add note ties (previously assumed they were also rests)
This commit is contained in:
parent
a50514f7ec
commit
be7874ba27
|
@ -86,7 +86,7 @@ func _init(tracks: Array, instrument_map: Dictionary):
|
||||||
|
|
||||||
func play_channel(channel: int, time_offset: float = 0.0) -> int:
|
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
|
# 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 track: Array = self.tracks[channel]
|
||||||
var l := len(track)
|
var l := len(track)
|
||||||
var player: AudioStreamPlayer = self.players[channel]
|
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.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))
|
player.play(max((SoundLoader.PLAY_START - time_offset)/player.pitch_scale, 0))
|
||||||
self.channel_current_note[channel] = note
|
self.channel_current_note[channel] = note
|
||||||
|
elif note == music.NOTE_IS_TIE:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
|
self.players[channel].stop()
|
||||||
self.channel_current_note[channel] = -1
|
self.channel_current_note[channel] = -1
|
||||||
# TODO: Confirm tempo scaling
|
# TODO: Confirm tempo scaling
|
||||||
return duration # Pulses to next instruction
|
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,
|
# 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)
|
||||||
var instrument_adsrs = RomLoader.snes_data.bgm_instrument_adsrs # TODO: UNHARDCODE THIS
|
var instrument_adsrs = RomLoader.snes_data.bgm_instrument_adsrs # TODO: UNHARDCODE THIS
|
||||||
var all_note_events = []
|
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
|
note_event.adsr_release = current_adsr_release
|
||||||
channel_note_events.append(note_event)
|
channel_note_events.append(note_event)
|
||||||
# num_notes += 1
|
# num_notes += 1
|
||||||
|
elif note == music.NOTE_IS_TIE:
|
||||||
|
channel_note_events[-1].p_end += duration
|
||||||
p += duration
|
p += duration
|
||||||
EventType.VOLUME:
|
EventType.VOLUME:
|
||||||
var new_velocity: float = event[1]/255.0
|
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_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
|
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]]
|
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))
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
const MAX_TRACKS := 8
|
const MAX_TRACKS := 8
|
||||||
const MAX_LOOP_DEPTH := 8 # Apparently 4, but eh whatever
|
const MAX_LOOP_DEPTH := 8 # Apparently 4, but eh whatever
|
||||||
|
const NOTE_IS_TIE := -1
|
||||||
|
const NOTE_IS_REST := -2
|
||||||
|
|
||||||
enum EventType {
|
enum EventType {
|
||||||
ADSR_ATTACK,
|
ADSR_ATTACK,
|
||||||
|
@ -126,6 +128,8 @@ static func get_int_array(size: int) -> PoolIntArray:
|
||||||
var EVENT_MAP: Dictionary
|
var EVENT_MAP: Dictionary
|
||||||
var NOTE_DURATIONS: PoolByteArray # This might need to be made untyped if a future addition uses PoolIntArray instead
|
var NOTE_DURATIONS: PoolByteArray # This might need to be made untyped if a future addition uses PoolIntArray instead
|
||||||
var REFERENCE_NOTE: int
|
var REFERENCE_NOTE: int
|
||||||
|
var NOTE_TIE: int
|
||||||
|
var NOTE_REST: int
|
||||||
|
|
||||||
const LOGGING_LEVEL_INFO: bool = false
|
const LOGGING_LEVEL_INFO: bool = false
|
||||||
func print_info(s: String) -> void:
|
func print_info(s: String) -> void:
|
||||||
|
@ -138,8 +142,11 @@ func translate_instruction(buffer: StreamPeer) -> Array:
|
||||||
if instruction < 0xD2:
|
if instruction < 0xD2:
|
||||||
var duration = self.NOTE_DURATIONS[instruction % 15]
|
var duration = self.NOTE_DURATIONS[instruction % 15]
|
||||||
var note = instruction / 15
|
var note = instruction / 15
|
||||||
if note >= 12: # 12 and 13 are rests
|
if note >= 12: # 12 and 13 are rests and ties
|
||||||
note = -1
|
if note == self.NOTE_REST:
|
||||||
|
note = NOTE_IS_REST
|
||||||
|
else:
|
||||||
|
note = NOTE_IS_TIE
|
||||||
return [EventType.NOTE, note, duration]
|
return [EventType.NOTE, note, duration]
|
||||||
else:
|
else:
|
||||||
# Control codes
|
# Control codes
|
||||||
|
|
|
@ -5,6 +5,8 @@ func _init() -> void:
|
||||||
# Durations are in pulses, 48 = 1 quarter note (crotchet)
|
# 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.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.REFERENCE_NOTE = 71
|
||||||
|
self.NOTE_TIE = 12
|
||||||
|
self.NOTE_REST = 13
|
||||||
|
|
||||||
self.EVENT_MAP = {
|
self.EVENT_MAP = {
|
||||||
0xD2: EventType.VOLUME,
|
0xD2: EventType.VOLUME,
|
||||||
|
|
Loading…
Reference in New Issue