Module musx.seq
The seq module provide support for reading and writing sequences of events that are sorted by time.
Expand source code
"""
The seq module provide support for reading and writing sequences of events that
are sorted by time.
"""
import sys
import time
import threading
from .note import Note
from .midi import midievent as me
from .midi import gm
from .tools import rescale
class Seq:
def __init__(self, events=[]):
"""
A time ordered sequence of Event objects, e.g. instances of
Note, MidiEvent, or some other user defined Event subclass.
A Seq is an iterable so its events can be iterated, sliced and
mapped.
Parameters
----------
events : list
The initial list of events for the sequence, defaults to an
empty list. An initial list will not be sorted so its events
should already be in proper time order.
"""
# copy user's event list because addevent alters it!
if isinstance(events, list):
self.events = events.copy()
else:
raise ValueError(f"events is not a list ({events})")
def __str__(self):
return f"<Seq: len={len(self)}, endtime={self.endtime()} {hex(id(self))}>"
__repr__ = __str__
def __iter__(self):
return iter(self.events)
def __getitem__(self, index):
return self.events[index] # index can be slice
def __len__(self):
return len(self.events)
def endtime(self):
"""Returns the time of the last event or 0 if there are none."""
return self.events[-1].time if len(self.events) > 0 else 0
def clear(self):
"""Removes the current contents of the sequence."""
self.events = []
def map(self, func):
"""
Maps a function of one argument over all the events in the sequence
and returns a list of the results returned by the function.
Parameters
----------
func : Function | lambda
A function or lambda of one argument, which will receive the
current event being mapped. The results of calling the function
will be returned as a list of values.
"""
return [func(x) for x in self]
def print(self, start=0, end=None):
"""
Prints the contents of the sequence to the standard output.
Parameters
----------
start : int
The index of the first event to print.
end : int
The index (exclusive) at which to stop printing.
hints : bool
If true events are printed with message names.
"""
if end is None:
end = len(self.events)
_printer = self._midiprinter if isinstance(self.events[0], me.MidiEvent) else self._defaultprinter
for i in range(start, end):
e = self.events[i]
_printer(i, e)
@staticmethod
def _defaultprinter(index, event):
print(index, f'{event.time:7.3f}', event, sep='\t')
@staticmethod
def _midiprinter(index, event):
time = event.time
str1 = f'{index:4}' # index position of event in seq
str2 = f'{time:7.3f}' # seconds rounded to 3 places in a 7 character pad
str3 = event.tostring(hint=True) # hint
print(str1 + " " + str2 + " " + str3)
def append(self, ev):
"""
Adds an event to the end of the sequence without checking time.
"""
self.events.append(ev)
def add(self, ev):
"""
Adds an event to the sequence in time sorted order, with the event
postioned after any other events with the same time stamp.
"""
if self.endtime() <= ev.time:
self.events.append(ev)
else:
i = 0; l = len(self.events)
while i < l and self.events[i].time <= ev.time:
i += 1
self.events.insert(i, ev)
def serialize(self, skiprests=True):
"""
Iterator that yields consecutive notes, chord members, and optionally, rests.
"""
for x in self.events:
try:
tag = x.tag
if tag == 'rest' and skiprests:
continue
yield x
for c in x:
yield c
except AttributeError:
yield x
Classes
class Seq (events=[])
-
A time ordered sequence of Event objects, e.g. instances of Note, MidiEvent, or some other user defined Event subclass.
A Seq is an iterable so its events can be iterated, sliced and mapped.
Parameters
events
:list
- The initial list of events for the sequence, defaults to an empty list. An initial list will not be sorted so its events should already be in proper time order.
Expand source code
class Seq: def __init__(self, events=[]): """ A time ordered sequence of Event objects, e.g. instances of Note, MidiEvent, or some other user defined Event subclass. A Seq is an iterable so its events can be iterated, sliced and mapped. Parameters ---------- events : list The initial list of events for the sequence, defaults to an empty list. An initial list will not be sorted so its events should already be in proper time order. """ # copy user's event list because addevent alters it! if isinstance(events, list): self.events = events.copy() else: raise ValueError(f"events is not a list ({events})") def __str__(self): return f"<Seq: len={len(self)}, endtime={self.endtime()} {hex(id(self))}>" __repr__ = __str__ def __iter__(self): return iter(self.events) def __getitem__(self, index): return self.events[index] # index can be slice def __len__(self): return len(self.events) def endtime(self): """Returns the time of the last event or 0 if there are none.""" return self.events[-1].time if len(self.events) > 0 else 0 def clear(self): """Removes the current contents of the sequence.""" self.events = [] def map(self, func): """ Maps a function of one argument over all the events in the sequence and returns a list of the results returned by the function. Parameters ---------- func : Function | lambda A function or lambda of one argument, which will receive the current event being mapped. The results of calling the function will be returned as a list of values. """ return [func(x) for x in self] def print(self, start=0, end=None): """ Prints the contents of the sequence to the standard output. Parameters ---------- start : int The index of the first event to print. end : int The index (exclusive) at which to stop printing. hints : bool If true events are printed with message names. """ if end is None: end = len(self.events) _printer = self._midiprinter if isinstance(self.events[0], me.MidiEvent) else self._defaultprinter for i in range(start, end): e = self.events[i] _printer(i, e) @staticmethod def _defaultprinter(index, event): print(index, f'{event.time:7.3f}', event, sep='\t') @staticmethod def _midiprinter(index, event): time = event.time str1 = f'{index:4}' # index position of event in seq str2 = f'{time:7.3f}' # seconds rounded to 3 places in a 7 character pad str3 = event.tostring(hint=True) # hint print(str1 + " " + str2 + " " + str3) def append(self, ev): """ Adds an event to the end of the sequence without checking time. """ self.events.append(ev) def add(self, ev): """ Adds an event to the sequence in time sorted order, with the event postioned after any other events with the same time stamp. """ if self.endtime() <= ev.time: self.events.append(ev) else: i = 0; l = len(self.events) while i < l and self.events[i].time <= ev.time: i += 1 self.events.insert(i, ev) def serialize(self, skiprests=True): """ Iterator that yields consecutive notes, chord members, and optionally, rests. """ for x in self.events: try: tag = x.tag if tag == 'rest' and skiprests: continue yield x for c in x: yield c except AttributeError: yield x
Methods
def add(self, ev)
-
Adds an event to the sequence in time sorted order, with the event postioned after any other events with the same time stamp.
Expand source code
def add(self, ev): """ Adds an event to the sequence in time sorted order, with the event postioned after any other events with the same time stamp. """ if self.endtime() <= ev.time: self.events.append(ev) else: i = 0; l = len(self.events) while i < l and self.events[i].time <= ev.time: i += 1 self.events.insert(i, ev)
def append(self, ev)
-
Adds an event to the end of the sequence without checking time.
Expand source code
def append(self, ev): """ Adds an event to the end of the sequence without checking time. """ self.events.append(ev)
def clear(self)
-
Removes the current contents of the sequence.
Expand source code
def clear(self): """Removes the current contents of the sequence.""" self.events = []
def endtime(self)
-
Returns the time of the last event or 0 if there are none.
Expand source code
def endtime(self): """Returns the time of the last event or 0 if there are none.""" return self.events[-1].time if len(self.events) > 0 else 0
def map(self, func)
-
Maps a function of one argument over all the events in the sequence and returns a list of the results returned by the function.
Parameters
func
:Function | lambda
- A function or lambda of one argument, which will receive the current event being mapped. The results of calling the function will be returned as a list of values.
Expand source code
def map(self, func): """ Maps a function of one argument over all the events in the sequence and returns a list of the results returned by the function. Parameters ---------- func : Function | lambda A function or lambda of one argument, which will receive the current event being mapped. The results of calling the function will be returned as a list of values. """ return [func(x) for x in self]
def print(self, start=0, end=None)
-
Prints the contents of the sequence to the standard output.
Parameters
start
:int
- The index of the first event to print.
end
:int
- The index (exclusive) at which to stop printing.
hints
:bool
- If true events are printed with message names.
Expand source code
def print(self, start=0, end=None): """ Prints the contents of the sequence to the standard output. Parameters ---------- start : int The index of the first event to print. end : int The index (exclusive) at which to stop printing. hints : bool If true events are printed with message names. """ if end is None: end = len(self.events) _printer = self._midiprinter if isinstance(self.events[0], me.MidiEvent) else self._defaultprinter for i in range(start, end): e = self.events[i] _printer(i, e)
def serialize(self, skiprests=True)
-
Iterator that yields consecutive notes, chord members, and optionally, rests.
Expand source code
def serialize(self, skiprests=True): """ Iterator that yields consecutive notes, chord members, and optionally, rests. """ for x in self.events: try: tag = x.tag if tag == 'rest' and skiprests: continue yield x for c in x: yield c except AttributeError: yield x