Skip to content

Commit

Permalink
better unique_notesets, generate SpecificNoteSetEvent
Browse files Browse the repository at this point in the history
  • Loading branch information
tandav committed Dec 16, 2023
1 parent fc87149 commit cd2cdbf
Showing 1 changed file with 31 additions and 3 deletions.
34 changes: 31 additions & 3 deletions src/musiclib/midi/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ def __lt__(self, other: object) -> bool:
raise TypeError
return self.on < other.on

def __len__(self) -> int:
return self.off - self.on

def __hash__(self) -> int:
return hash((self.note, self.on, self.off))

Expand All @@ -46,6 +49,9 @@ class Midi:
pitchbend: list[MidiPitch] = dataclasses.field(default_factory=list)
ticks_per_beat: int = 96

def __len__(self) -> int:
return max(note.off for note in self.notes)


@dataclasses.dataclass
class IndexedMessage:
Expand Down Expand Up @@ -183,16 +189,38 @@ def append_bar(noteset: SpecificNoteSet | None) -> None:
return mid


def unique_notesets(midi: mido.MidiFile) -> Generator[tuple[int, SpecificNoteSet], None, None]:
class SpecificNoteSetEvent:
def __init__(
self,
sns: SpecificNoteSet,
on: int,
off: int,
) -> None:
self.sns = sns
self.on = on
self.off = off

def __len__(self) -> int:
return self.off - self.on

def __repr__(self) -> str:
return f'{self.__class__.__name__}(sns={self.sns}, on={self.on}, off={self.off})'


def unique_notesets(midi: mido.MidiFile) -> Generator[SpecificNoteSetEvent, None, None]:
if midi.type != 0:
raise ValueError('only type 0 midi files are supported')
track, = midi.tracks
playing_notes = collections.defaultdict(dict) # type: ignore[var-annotated]
t = 0
t_sns = 0
for message in track:
if message.time > 0:
yield t, SpecificNoteSet(frozenset(n['note'] for n in playing_notes.values()))
t += message.time
if message.type not in {'note_on', 'note_off'}:
continue
sns = SpecificNoteSet(frozenset(n['note'] for n in playing_notes.values()))
yield SpecificNoteSetEvent(sns=sns, on=t_sns, off=t)
t_sns = t
if is_note('on', message):
playing_notes[message.note].update({'note': SpecificNote.from_i(message.note), 'on': t})
elif is_note('off', message):
Expand Down

0 comments on commit cd2cdbf

Please sign in to comment.