Skip to content

Commit

Permalink
Control change dedup removed in dump + lint (#34)
Browse files Browse the repository at this point in the history
* control change dedup removed in dump, type hints and lint

* _include_meta_events_within_range renamed _include_meta_events_within_tick_range + fixes and docs
  • Loading branch information
Natooz authored Nov 15, 2023
1 parent c771a87 commit 4f94fbd
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 79 deletions.
177 changes: 99 additions & 78 deletions miditoolkit/midi/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ def __get_instrument(program, channel, track, create_new):
return instruments

def get_tick_to_time_mapping(self):
return _get_tick_to_time_mapping(
return _get_tick_to_second_mapping(
self.ticks_per_beat, self.max_tick, self.tempo_changes
)

Expand Down Expand Up @@ -435,7 +435,7 @@ def event_compare(event1, event2):
add_ts = True
ts_list = []
if self.time_signature_changes:
add_ts = min([ts.time for ts in self.time_signature_changes]) > 0.0
add_ts = min([ts.time for ts in self.time_signature_changes]) > 0
if add_ts:
ts_list.append(
mido.MetaMessage("time_signature", time=0, numerator=4, denominator=4)
Expand Down Expand Up @@ -473,8 +473,8 @@ def event_compare(event1, event2):

# 3. Lyrics
lyrics_list = []
for l in self.lyrics:
lyrics_list.append(mido.MetaMessage("lyrics", time=l.time, text=l.text))
for lyr in self.lyrics:
lyrics_list.append(mido.MetaMessage("lyrics", time=lyr.time, text=lyr.text))

# 4. Markers
markers_list = []
Expand All @@ -489,21 +489,22 @@ def event_compare(event1, event2):
)

# crop segment
start_tick, end_tick = 0, 0
if segment:
start_tick, end_tick = segment
ts_list = _include_meta_events_within_range(
ts_list = _include_meta_events_within_tick_range(
ts_list, start_tick, end_tick, shift=shift, front=True
)
tempo_list = _include_meta_events_within_range(
tempo_list = _include_meta_events_within_tick_range(
tempo_list, start_tick, end_tick, shift=shift, front=True
)
lyrics_list = _include_meta_events_within_range(
lyrics_list = _include_meta_events_within_tick_range(
lyrics_list, start_tick, end_tick, shift=shift, front=False
)
markers_list = _include_meta_events_within_range(
markers_list = _include_meta_events_within_tick_range(
markers_list, start_tick, end_tick, shift=shift, front=False
)
key_list = _include_meta_events_within_range(
key_list = _include_meta_events_within_tick_range(
key_list, start_tick, end_tick, shift=shift, front=True
)
meta_track = ts_list + tempo_list + lyrics_list + markers_list + key_list
Expand Down Expand Up @@ -586,7 +587,6 @@ def event_compare(event1, event2):
value=127,
)
)

# append for pedal-off (0)
cc_list.append(
mido.Message(
Expand All @@ -597,44 +597,45 @@ def event_compare(event1, event2):
value=0,
)
)
# print(cc_list[-2:])

if segment:
bend_list = _include_meta_events_within_range(
cc_list = _include_meta_events_within_tick_range(
cc_list, start_tick, end_tick, shift=shift, front=False
)
bend_list = _include_meta_events_within_tick_range(
bend_list, start_tick, end_tick, shift=shift, front=True
)
track += bend_list + cc_list #
track += bend_list + cc_list

# Add all note events
for note in instrument.notes:
if segment:
note = _check_note_within_range(
note, start_tick, end_tick, shift=True
)
if note:
track.append(
mido.Message(
"note_on",
time=note.start,
channel=channel,
note=note.pitch,
velocity=note.velocity,
end=note.end,
)
if segment and not _is_note_within_tick_range(
note, start_tick, end_tick, shift, True
):
continue
track.append(
mido.Message(
"note_on",
time=note.start,
channel=channel,
note=note.pitch,
velocity=note.velocity,
end=note.end,
)
# Also need a note-off event (note on with velocity 0)
track.append(
mido.Message(
"note_off",
time=note.end,
channel=channel,
note=note.pitch,
velocity=note.velocity,
)
)
# Also need a note-off event
track.append(
mido.Message(
"note_off",
time=note.end,
channel=channel,
note=note.pitch,
velocity=note.velocity,
)
)
track = sorted(track, key=functools.cmp_to_key(event_compare))

memo = 0
"""memo = 0
i = 0
while i < len(track):
# print(i)
Expand All @@ -647,7 +648,7 @@ def event_compare(event1, event2):
memo = track[i].value
i += 1
else:
i += 1
i += 1"""

# i = 0
# while i <= len(cc_list)-1:
Expand Down Expand Up @@ -683,23 +684,55 @@ def event_compare(event1, event2):
midi_parsed.save(file=file)


def _check_note_within_range(note, st, ed, shift=True):
tmp_st = max(st, note.start)
tmp_ed = max(st, min(note.end, ed))
def _is_note_within_tick_range(
note: Note,
start_tick: int,
end_tick: int,
shift: bool = False,
adapt_note_times: bool = False,
) -> bool:
r"""
Args:
note: note to check.
start_tick: starting tick.
end_tick: ending tick.
shift: if True, will shift the note's start and end times by `start_tick`.
adapt_note_times: if True, will cut the start and end note times to fit within the range.
Returns: whether the note is within the time range.
"""
# | |
# **** | *** **|* *****
tmp_st = max(start_tick, note.start)
tmp_ed = max(start_tick, min(note.end, end_tick))
if (tmp_ed - tmp_st) <= 0:
return None
return False

if shift:
tmp_st -= st
tmp_ed -= st
note.start = int(tmp_st)
note.end = int(tmp_ed)
return note
tmp_st -= start_tick
tmp_ed -= start_tick
if adapt_note_times:
note.start = tmp_st
note.end = tmp_ed
return True


def _include_meta_events_within_range(events, st, ed, shift=True, front=True):
"""
For time, key signature
def _include_meta_events_within_tick_range(
events, start_tick: int, end_tick: int, shift: bool = False, front: bool = True
):
r"""
Args:
events: meta messages to check.
start_tick: starting tick.
end_tick: ending tick.
shift: if True, will shift the note's start and end times by `start_tick`.
front: will make sure the message coming last before the `start_tick` is kept and its time set at `start_tick`.
Returns: list of meta messages within the given tick range
"""
proc_events = []
num = len(events)
Expand All @@ -710,53 +743,41 @@ def _include_meta_events_within_range(events, st, ed, shift=True, front=True):
i = num - 1
while i >= 0:
event = events[i]
if event.time < st:
if event.time < start_tick:
break
if event.time < ed:
if event.time < end_tick:
proc_events.append(event)
i -= 1

# if the first tick has no event, add the previous one
if front and (i >= 0):
if not proc_events:
proc_events = [events[i]]
elif proc_events[-1].time != st:
elif proc_events[-1].time != start_tick:
proc_events.append(events[i])
else:
pass
proc_events[-1].time = start_tick

# reverse
proc_events = proc_events[::-1]

# shift
result = []
# shift = st if shift else 0
for event in proc_events:
event.time -= st
event.time = int(max(event.time, 0))
result.append(event)
return proc_events


def _find_nearest_np(array, value):
return (np.abs(array - value)).argmin()
if shift:
for event in proc_events:
event.time -= start_tick
event.time = int(max(event.time, 0))

return proc_events

def _get_tick_index_by_seconds(sec, tick_to_time):
if not isinstance(sec, float):
raise ValueError("Seconds should be float")

if isinstance(sec, list) or isinstance(sec, tuple):
return [_find_nearest_np(tick_to_time, s) for s in sec]
else:
return _find_nearest_np(tick_to_time, sec)
def _get_tick_eq_of_second(sec: Union[float, int], tick_to_time: np.ndarray) -> int:
return int((np.abs(tick_to_time - sec)).argmin())


def _get_tick_to_time_mapping(ticks_per_beat, max_tick, tempo_changes):
def _get_tick_to_second_mapping(
ticks_per_beat: int, max_tick: int, tempo_changes: Sequence[TempoChange]
) -> np.ndarray:
tick_to_time = np.zeros(max_tick + 1)
num_tempi = len(tempo_changes)

fianl_tick = max_tick
acc_time = 0

for idx in range(num_tempi):
Expand All @@ -768,9 +789,9 @@ def _get_tick_to_time_mapping(ticks_per_beat, max_tick, tempo_changes):
seconds_per_tick = seconds_per_beat / float(ticks_per_beat)

# set end tick of interval
end_tick = tempo_changes[idx + 1].time if (idx + 1) < num_tempi else fianl_tick
end_tick = tempo_changes[idx + 1].time if (idx + 1) < num_tempi else max_tick

# wrtie interval
# write interval
ticks = np.arange(end_tick - start_tick + 1)
tick_to_time[start_tick : end_tick + 1] = acc_time + seconds_per_tick * ticks
acc_time = tick_to_time[end_tick]
Expand Down
1 change: 0 additions & 1 deletion miditoolkit/pianoroll/vis.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import numpy as np
from matplotlib import pyplot as plt

Expand Down

0 comments on commit 4f94fbd

Please sign in to comment.