Module musx.note

Defines a base Event class for musical events and a generic Note subclass to represent time, duration, pitch, and amplitude. Notes can also represent chords` and rests according to their attribute values. A note's attribute values are automatically converted to whatever format is required by a specific backend.

Expand source code
"""
Defines a base Event class for musical events and a generic Note subclass to
represent time, duration, pitch, and amplitude. Notes can also represent chords`
and rests according to their attribute values. A note's attribute values are 
automatically converted to whatever format is required by a specific backend.
"""

from fractions import Fraction
from copy import copy, deepcopy
from .midi import midievent as me
from .midi import midimsg as mm
from .tools import quantize
from .pitch import Pitch

class Event:
    """
    A base class for defining musical events. Any subclass of Event can
    be added to a `musx.seq.Seq` object.

    Parameters
    ----------
    time : int | float
        The onset time in seconds, defaults to 0.0.  For ways to specify
        time and duration metrically, see `musx.rhythm.rhythm()` and
        `musx.rhythm.intempo()`.
    """
    def __init__(self, time):
        self.time = time

    @property
    def time(self):
        """
        The start time of the event in seconds, defaults to 0.0.  For ways
        to specify time metrically, see `musx.rhythm.rhythm()` and
        `musx.rhythm.intempo()`.
        """
        return self._time

    @time.setter
    def time(self, val):
        if isinstance(val, (int, float, Fraction)) and val >= 0:
            self._time = val
        else:
            raise ValueError(f"Invalid Note time: {val}.")

    def __str__(self):
        return f'<Event: {self.time} {hex(id(self))}>)'
    
    def __repr__(self):
        return f'Event({self.time})'


class Note (Event):
    """
    Creates a Note instance from its arguments. A Note is a generic sound
    event that can be used in different contexts. For example, if a Note
    is passed to methods in the MIDI or Csound backends the note data is
    automatically converted to the format supported by that module.

    In addition to single tones, Notes can have children, in which case 
    it is auto-tagged as a chord; if a Note contains an empty pitch 
    it is tagged as a rest. See Note.tag

    Parameters
    ----------
    time : int | float | Fraction
        The onset time in seconds, defaults to 0.0.  For ways to specify
        time and duration metrically, see `rhythm()` and `intempo()`.
    duration : int | float | Fraction
        The duration in seconds, defaults to 1.0. For ways to specify
        duration and time metrically, see `rhythm()` and `intempo()`.
    pitch : int | float | Pitch | list
        An int or float key number 0 to 127, or a `Pitch` object, or list
        of the same. Defaults to 60 (C4). If pitch is a float *kkk.cc* then
        *kkk* is the midi key number and *cc* is cents above that midi
        key's equal tempered frequency. If the pitch is an empty Pitch the
        note is tagged as a rest. If a list of pitches is provided the
        note will contain the first Pitch and the remaining pitches will
        be converted to child Notes, each child containing the same
        attribute values as the parent notw except for pitch.
    amplitude : int | float
        An amplitude 0.0 to 1.0, defaults to 0.5.
    instrument : value
        An instrument designation of some kind, defaults to 0. If you are
        generating midi then this value should be a channel integer 
        0 to 15, inclusive. 
    """
    def __init__(self, time=0.0, duration=1.0, pitch=60, amplitude=.5, instrument=0):
        # WARNING: if you add new attributes be sure to update copy() and
        # copy_at_tempo() as needed.
        super().__init__(time)
        self.duration = duration
        self.amplitude = amplitude
        self.instrument = instrument
        self._children = []
        self._mxml = {}
        self.pitch = pitch

    @property
    def time(self):
        """
        The start time of the note in seconds, defaults to 0.0.  For ways
        to specify metric time, see: `rhythm()` and `intempo()`.
        """
        return self._time

    @time.setter
    def time(self, val):
        if isinstance(val, (int, float, Fraction)) and val >= 0:
            self._time = val
        else:
            raise ValueError(f"Invalid Note time: {val}.")

    @property
    def duration(self):
        """
        The duration of the note in seconds, defaults to 1.0. For ways
        to specify metric durations, see: `rhythm()` and `intempo()`.
        """
        return self._duration

    @duration.setter
    def duration(self, val):
        if isinstance(val, (int, float, Fraction)) and val > 0:
            self._duration = val
        else:
            raise ValueError(f"Invalid Note duration: {val}.")

    @property
    def pitch(self):
        """
        A `musx.pitch.Pitch` object or an int or float key number, or list of
        the same. Defaults to 60 (Middle C). If the pitch is assigned a list 
        of pitches, the note will keep the first pitch and the other pitches
        will be assigned to child notes of this note, which will then be 
        tagged as a chord.
        """
        return self._pitch

    @pitch.setter
    def pitch(self, val):
        def checkpitch(p):
            if (isinstance(p, (int, float)) and (0 <= p <= 127)) or isinstance(p, Pitch):
                return p
            raise ValueError(f"Invalid Note pitch: {p}.")    
        if isinstance(val, list) and len(val)>0:
            self._pitch = checkpitch(val[0])
            for p in val[1:]:
                self.add_child(Note(time=self.time, duration=self.duration, pitch=p,
                    amplitude=self.amplitude, instrument=self.instrument))
        else:
            self._pitch = checkpitch(val)

    @property
    def amplitude(self):
        """
        A value between 0.0 and 1.0 inclusive, defaults to 0.5. If you output
        a note to midi, amplitude will be automatically scaled to 0-127 inclusive.
        """
        return self._amplitude

    @amplitude.setter
    def amplitude(self, val):
        if isinstance(val, (int, float)) and 0 <= 1.0:
            self._amplitude = val
        else:
            raise ValueError(f"Invalid Note amplitude: {val}.")

    @property
    def instrument(self):
        """
        A value designating the note's instrument, defalts to 0. For midi output
        the instrument must be a midi channel value 0 to 15 inclusive.
        """
        return self._instrument

    @instrument.setter
    def instrument(self, val):
        self._instrument = val

    @property
    def tag(self):
        """
        The value of tag is either 'note', 'rest' or 'chord' depending the
        note's current state: if the note has any children the tag is 'chord',
        else if the pitch of the note is empty the tag is 'rest' otherwise the
        tag is 'note'.
        """
        if self._children:
            return 'chord'
        if isinstance(self.pitch, Pitch) and self.pitch.is_empty():
            return 'rest'
        return 'note'

    def add_child(self, note):
        """
        Adds note as a child of this note and tags itself as a chord.
        """
        if isinstance(note, Note):
            # Not sure if I want to do this...
            if self._children and self._children[0].time != note.time:
                raise ValueError(f'Conflicting note onset times in chord: {self._children[0].time} and {note.time}.')
            self._children.append(note)
        else:
            raise ValueError(f'Invalid child: {note}.')

    def is_rest(self):
        """
        Returns true if the note's pitch is empty, e.g. a Pitch().
        """
        return isinstance(self._pitch, Pitch) and self._pitch.is_empty()

    def is_chord(self):
        """
        Returns true if the note contains children.
        """
        return len(self._children) > 0

    def chord(self):
        """
        Returns a list containing this note and any childen.
        """
        notes = [self]
        notes.extend(self._children)
        return notes

    def get_mxml(self, key, default=None):
        """
        Returns the mxml value of the given key, or the default value if
        the key is not in the note's mxml dictionary.
        """
        return self._mxml.get(key, default)

    def set_mxml(self, key, value):
        """
        Assigns the mxml key and value to the note.
        """
        self._mxml[key] = value

    def __iter__(self):
        """
        Iterates the children of this note.
        """
        return iter(self._children)

    def __len__(self):
        """
        Returns the number of children this note contains.
        """
        return len(self._children)

    def _tagged_pitch_str(self):
        """
        Returns a tag-specific pitch string: if the Note's tag is 'note' then the pitch name is
        returned, if the tag is 'chord' then pitch names delimited by ":" are returned and if
        the tag is 'rest' the string 'R' is returned.
        """
        return ":".join([str(c.pitch) for c in self.chord()]) if self.is_chord() else str(self.pitch)

    def __str__(self):
        name = "Note" #"Chord" if self.is_chord() else "Note"
        pstr = self._tagged_pitch_str()
        mxml = ", ".join(f"{str(k)}={v}" for k,v in self._mxml.items())
        if mxml:
            mxml = " "+mxml
        return f"<{name}: {self._time}, {self._duration}, {pstr}, {self._amplitude}, {self._instrument}{mxml}>"

    # No special repr() method for now...
    __repr__ = __str__

    def _pitchtokey(self):
        if isinstance(self._pitch, Pitch):
            return self._pitch.keynum()
        return self._pitch

    # def __deepcopy__(self, memo):
    #     cls = self.__class__
    #     result = cls.__new__(cls)
    #     memo[id(self)] = result
    #     for k, v in self.__dict__.items():
    #         setattr(result, k, deepcopy(v, memo))
    #     return result

    def copy(self):
        # ARRRG! Tried __deepcopy__ but gave up for now...
        """
        Returns a deep copy of this Note and all its children.
        """
        cpy = Note() 
        cpy._time = self._time
        cpy._duration = self._duration
        cpy._amplitude = self._amplitude
        cpy._pitch = self._pitch
        cpy._instrument = self._instrument
        cpy._children = [c.copy() for c in self._children]
        cpy._mxml = self._mxml.copy()
        return cpy

    def copy_at_tempo(self, tempo_scalar):
        """
        Returns a copy of this note with its time and duration adjusted by
        tempo_scaler, a metronome value per quarter: 60.0 / (1/4 * tempo)
        """
        cpy = Note() 
        cpy._time = self._time * tempo_scalar
        cpy._duration = self._duration * tempo_scalar
        cpy._amplitude = self._amplitude
        cpy._pitch = self._pitch
        cpy._instrument = self._instrument
        cpy._children = [c.copy_at_tempo(tempo_scalar) for c in self._children]
        cpy._mxml = self._mxml.copy()     
        return cpy
        

Classes

class Event (time)

A base class for defining musical events. Any subclass of Event can be added to a Seq object.

Parameters

time : int | float
The onset time in seconds, defaults to 0.0. For ways to specify time and duration metrically, see rhythm() and intempo().
Expand source code
class Event:
    """
    A base class for defining musical events. Any subclass of Event can
    be added to a `musx.seq.Seq` object.

    Parameters
    ----------
    time : int | float
        The onset time in seconds, defaults to 0.0.  For ways to specify
        time and duration metrically, see `musx.rhythm.rhythm()` and
        `musx.rhythm.intempo()`.
    """
    def __init__(self, time):
        self.time = time

    @property
    def time(self):
        """
        The start time of the event in seconds, defaults to 0.0.  For ways
        to specify time metrically, see `musx.rhythm.rhythm()` and
        `musx.rhythm.intempo()`.
        """
        return self._time

    @time.setter
    def time(self, val):
        if isinstance(val, (int, float, Fraction)) and val >= 0:
            self._time = val
        else:
            raise ValueError(f"Invalid Note time: {val}.")

    def __str__(self):
        return f'<Event: {self.time} {hex(id(self))}>)'
    
    def __repr__(self):
        return f'Event({self.time})'

Subclasses

Instance variables

var time

The start time of the event in seconds, defaults to 0.0. For ways to specify time metrically, see rhythm() and intempo().

Expand source code
@property
def time(self):
    """
    The start time of the event in seconds, defaults to 0.0.  For ways
    to specify time metrically, see `musx.rhythm.rhythm()` and
    `musx.rhythm.intempo()`.
    """
    return self._time
class Note (time=0.0, duration=1.0, pitch=60, amplitude=0.5, instrument=0)

Creates a Note instance from its arguments. A Note is a generic sound event that can be used in different contexts. For example, if a Note is passed to methods in the MIDI or Csound backends the note data is automatically converted to the format supported by that module.

In addition to single tones, Notes can have children, in which case it is auto-tagged as a chord; if a Note contains an empty pitch it is tagged as a rest. See Note.tag

Parameters

time : int | float | Fraction
The onset time in seconds, defaults to 0.0. For ways to specify time and duration metrically, see rhythm() and intempo().
duration : int | float | Fraction
The duration in seconds, defaults to 1.0. For ways to specify duration and time metrically, see rhythm() and intempo().
pitch : int | float | Pitch | list
An int or float key number 0 to 127, or a Pitch object, or list of the same. Defaults to 60 (C4). If pitch is a float kkk.cc then kkk is the midi key number and cc is cents above that midi key's equal tempered frequency. If the pitch is an empty Pitch the note is tagged as a rest. If a list of pitches is provided the note will contain the first Pitch and the remaining pitches will be converted to child Notes, each child containing the same attribute values as the parent notw except for pitch.
amplitude : int | float
An amplitude 0.0 to 1.0, defaults to 0.5.
instrument : value
An instrument designation of some kind, defaults to 0. If you are generating midi then this value should be a channel integer 0 to 15, inclusive.
Expand source code
class Note (Event):
    """
    Creates a Note instance from its arguments. A Note is a generic sound
    event that can be used in different contexts. For example, if a Note
    is passed to methods in the MIDI or Csound backends the note data is
    automatically converted to the format supported by that module.

    In addition to single tones, Notes can have children, in which case 
    it is auto-tagged as a chord; if a Note contains an empty pitch 
    it is tagged as a rest. See Note.tag

    Parameters
    ----------
    time : int | float | Fraction
        The onset time in seconds, defaults to 0.0.  For ways to specify
        time and duration metrically, see `rhythm()` and `intempo()`.
    duration : int | float | Fraction
        The duration in seconds, defaults to 1.0. For ways to specify
        duration and time metrically, see `rhythm()` and `intempo()`.
    pitch : int | float | Pitch | list
        An int or float key number 0 to 127, or a `Pitch` object, or list
        of the same. Defaults to 60 (C4). If pitch is a float *kkk.cc* then
        *kkk* is the midi key number and *cc* is cents above that midi
        key's equal tempered frequency. If the pitch is an empty Pitch the
        note is tagged as a rest. If a list of pitches is provided the
        note will contain the first Pitch and the remaining pitches will
        be converted to child Notes, each child containing the same
        attribute values as the parent notw except for pitch.
    amplitude : int | float
        An amplitude 0.0 to 1.0, defaults to 0.5.
    instrument : value
        An instrument designation of some kind, defaults to 0. If you are
        generating midi then this value should be a channel integer 
        0 to 15, inclusive. 
    """
    def __init__(self, time=0.0, duration=1.0, pitch=60, amplitude=.5, instrument=0):
        # WARNING: if you add new attributes be sure to update copy() and
        # copy_at_tempo() as needed.
        super().__init__(time)
        self.duration = duration
        self.amplitude = amplitude
        self.instrument = instrument
        self._children = []
        self._mxml = {}
        self.pitch = pitch

    @property
    def time(self):
        """
        The start time of the note in seconds, defaults to 0.0.  For ways
        to specify metric time, see: `rhythm()` and `intempo()`.
        """
        return self._time

    @time.setter
    def time(self, val):
        if isinstance(val, (int, float, Fraction)) and val >= 0:
            self._time = val
        else:
            raise ValueError(f"Invalid Note time: {val}.")

    @property
    def duration(self):
        """
        The duration of the note in seconds, defaults to 1.0. For ways
        to specify metric durations, see: `rhythm()` and `intempo()`.
        """
        return self._duration

    @duration.setter
    def duration(self, val):
        if isinstance(val, (int, float, Fraction)) and val > 0:
            self._duration = val
        else:
            raise ValueError(f"Invalid Note duration: {val}.")

    @property
    def pitch(self):
        """
        A `musx.pitch.Pitch` object or an int or float key number, or list of
        the same. Defaults to 60 (Middle C). If the pitch is assigned a list 
        of pitches, the note will keep the first pitch and the other pitches
        will be assigned to child notes of this note, which will then be 
        tagged as a chord.
        """
        return self._pitch

    @pitch.setter
    def pitch(self, val):
        def checkpitch(p):
            if (isinstance(p, (int, float)) and (0 <= p <= 127)) or isinstance(p, Pitch):
                return p
            raise ValueError(f"Invalid Note pitch: {p}.")    
        if isinstance(val, list) and len(val)>0:
            self._pitch = checkpitch(val[0])
            for p in val[1:]:
                self.add_child(Note(time=self.time, duration=self.duration, pitch=p,
                    amplitude=self.amplitude, instrument=self.instrument))
        else:
            self._pitch = checkpitch(val)

    @property
    def amplitude(self):
        """
        A value between 0.0 and 1.0 inclusive, defaults to 0.5. If you output
        a note to midi, amplitude will be automatically scaled to 0-127 inclusive.
        """
        return self._amplitude

    @amplitude.setter
    def amplitude(self, val):
        if isinstance(val, (int, float)) and 0 <= 1.0:
            self._amplitude = val
        else:
            raise ValueError(f"Invalid Note amplitude: {val}.")

    @property
    def instrument(self):
        """
        A value designating the note's instrument, defalts to 0. For midi output
        the instrument must be a midi channel value 0 to 15 inclusive.
        """
        return self._instrument

    @instrument.setter
    def instrument(self, val):
        self._instrument = val

    @property
    def tag(self):
        """
        The value of tag is either 'note', 'rest' or 'chord' depending the
        note's current state: if the note has any children the tag is 'chord',
        else if the pitch of the note is empty the tag is 'rest' otherwise the
        tag is 'note'.
        """
        if self._children:
            return 'chord'
        if isinstance(self.pitch, Pitch) and self.pitch.is_empty():
            return 'rest'
        return 'note'

    def add_child(self, note):
        """
        Adds note as a child of this note and tags itself as a chord.
        """
        if isinstance(note, Note):
            # Not sure if I want to do this...
            if self._children and self._children[0].time != note.time:
                raise ValueError(f'Conflicting note onset times in chord: {self._children[0].time} and {note.time}.')
            self._children.append(note)
        else:
            raise ValueError(f'Invalid child: {note}.')

    def is_rest(self):
        """
        Returns true if the note's pitch is empty, e.g. a Pitch().
        """
        return isinstance(self._pitch, Pitch) and self._pitch.is_empty()

    def is_chord(self):
        """
        Returns true if the note contains children.
        """
        return len(self._children) > 0

    def chord(self):
        """
        Returns a list containing this note and any childen.
        """
        notes = [self]
        notes.extend(self._children)
        return notes

    def get_mxml(self, key, default=None):
        """
        Returns the mxml value of the given key, or the default value if
        the key is not in the note's mxml dictionary.
        """
        return self._mxml.get(key, default)

    def set_mxml(self, key, value):
        """
        Assigns the mxml key and value to the note.
        """
        self._mxml[key] = value

    def __iter__(self):
        """
        Iterates the children of this note.
        """
        return iter(self._children)

    def __len__(self):
        """
        Returns the number of children this note contains.
        """
        return len(self._children)

    def _tagged_pitch_str(self):
        """
        Returns a tag-specific pitch string: if the Note's tag is 'note' then the pitch name is
        returned, if the tag is 'chord' then pitch names delimited by ":" are returned and if
        the tag is 'rest' the string 'R' is returned.
        """
        return ":".join([str(c.pitch) for c in self.chord()]) if self.is_chord() else str(self.pitch)

    def __str__(self):
        name = "Note" #"Chord" if self.is_chord() else "Note"
        pstr = self._tagged_pitch_str()
        mxml = ", ".join(f"{str(k)}={v}" for k,v in self._mxml.items())
        if mxml:
            mxml = " "+mxml
        return f"<{name}: {self._time}, {self._duration}, {pstr}, {self._amplitude}, {self._instrument}{mxml}>"

    # No special repr() method for now...
    __repr__ = __str__

    def _pitchtokey(self):
        if isinstance(self._pitch, Pitch):
            return self._pitch.keynum()
        return self._pitch

    # def __deepcopy__(self, memo):
    #     cls = self.__class__
    #     result = cls.__new__(cls)
    #     memo[id(self)] = result
    #     for k, v in self.__dict__.items():
    #         setattr(result, k, deepcopy(v, memo))
    #     return result

    def copy(self):
        # ARRRG! Tried __deepcopy__ but gave up for now...
        """
        Returns a deep copy of this Note and all its children.
        """
        cpy = Note() 
        cpy._time = self._time
        cpy._duration = self._duration
        cpy._amplitude = self._amplitude
        cpy._pitch = self._pitch
        cpy._instrument = self._instrument
        cpy._children = [c.copy() for c in self._children]
        cpy._mxml = self._mxml.copy()
        return cpy

    def copy_at_tempo(self, tempo_scalar):
        """
        Returns a copy of this note with its time and duration adjusted by
        tempo_scaler, a metronome value per quarter: 60.0 / (1/4 * tempo)
        """
        cpy = Note() 
        cpy._time = self._time * tempo_scalar
        cpy._duration = self._duration * tempo_scalar
        cpy._amplitude = self._amplitude
        cpy._pitch = self._pitch
        cpy._instrument = self._instrument
        cpy._children = [c.copy_at_tempo(tempo_scalar) for c in self._children]
        cpy._mxml = self._mxml.copy()     
        return cpy

Ancestors

Instance variables

var amplitude

A value between 0.0 and 1.0 inclusive, defaults to 0.5. If you output a note to midi, amplitude will be automatically scaled to 0-127 inclusive.

Expand source code
@property
def amplitude(self):
    """
    A value between 0.0 and 1.0 inclusive, defaults to 0.5. If you output
    a note to midi, amplitude will be automatically scaled to 0-127 inclusive.
    """
    return self._amplitude
var duration

The duration of the note in seconds, defaults to 1.0. For ways to specify metric durations, see: rhythm() and intempo().

Expand source code
@property
def duration(self):
    """
    The duration of the note in seconds, defaults to 1.0. For ways
    to specify metric durations, see: `rhythm()` and `intempo()`.
    """
    return self._duration
var instrument

A value designating the note's instrument, defalts to 0. For midi output the instrument must be a midi channel value 0 to 15 inclusive.

Expand source code
@property
def instrument(self):
    """
    A value designating the note's instrument, defalts to 0. For midi output
    the instrument must be a midi channel value 0 to 15 inclusive.
    """
    return self._instrument
var pitch

A Pitch object or an int or float key number, or list of the same. Defaults to 60 (Middle C). If the pitch is assigned a list of pitches, the note will keep the first pitch and the other pitches will be assigned to child notes of this note, which will then be tagged as a chord.

Expand source code
@property
def pitch(self):
    """
    A `musx.pitch.Pitch` object or an int or float key number, or list of
    the same. Defaults to 60 (Middle C). If the pitch is assigned a list 
    of pitches, the note will keep the first pitch and the other pitches
    will be assigned to child notes of this note, which will then be 
    tagged as a chord.
    """
    return self._pitch
var tag

The value of tag is either 'note', 'rest' or 'chord' depending the note's current state: if the note has any children the tag is 'chord', else if the pitch of the note is empty the tag is 'rest' otherwise the tag is 'note'.

Expand source code
@property
def tag(self):
    """
    The value of tag is either 'note', 'rest' or 'chord' depending the
    note's current state: if the note has any children the tag is 'chord',
    else if the pitch of the note is empty the tag is 'rest' otherwise the
    tag is 'note'.
    """
    if self._children:
        return 'chord'
    if isinstance(self.pitch, Pitch) and self.pitch.is_empty():
        return 'rest'
    return 'note'
var time

The start time of the note in seconds, defaults to 0.0. For ways to specify metric time, see: rhythm() and intempo().

Expand source code
@property
def time(self):
    """
    The start time of the note in seconds, defaults to 0.0.  For ways
    to specify metric time, see: `rhythm()` and `intempo()`.
    """
    return self._time

Methods

def add_child(self, note)

Adds note as a child of this note and tags itself as a chord.

Expand source code
def add_child(self, note):
    """
    Adds note as a child of this note and tags itself as a chord.
    """
    if isinstance(note, Note):
        # Not sure if I want to do this...
        if self._children and self._children[0].time != note.time:
            raise ValueError(f'Conflicting note onset times in chord: {self._children[0].time} and {note.time}.')
        self._children.append(note)
    else:
        raise ValueError(f'Invalid child: {note}.')
def chord(self)

Returns a list containing this note and any childen.

Expand source code
def chord(self):
    """
    Returns a list containing this note and any childen.
    """
    notes = [self]
    notes.extend(self._children)
    return notes
def copy(self)

Returns a deep copy of this Note and all its children.

Expand source code
def copy(self):
    # ARRRG! Tried __deepcopy__ but gave up for now...
    """
    Returns a deep copy of this Note and all its children.
    """
    cpy = Note() 
    cpy._time = self._time
    cpy._duration = self._duration
    cpy._amplitude = self._amplitude
    cpy._pitch = self._pitch
    cpy._instrument = self._instrument
    cpy._children = [c.copy() for c in self._children]
    cpy._mxml = self._mxml.copy()
    return cpy
def copy_at_tempo(self, tempo_scalar)

Returns a copy of this note with its time and duration adjusted by tempo_scaler, a metronome value per quarter: 60.0 / (1/4 * tempo)

Expand source code
def copy_at_tempo(self, tempo_scalar):
    """
    Returns a copy of this note with its time and duration adjusted by
    tempo_scaler, a metronome value per quarter: 60.0 / (1/4 * tempo)
    """
    cpy = Note() 
    cpy._time = self._time * tempo_scalar
    cpy._duration = self._duration * tempo_scalar
    cpy._amplitude = self._amplitude
    cpy._pitch = self._pitch
    cpy._instrument = self._instrument
    cpy._children = [c.copy_at_tempo(tempo_scalar) for c in self._children]
    cpy._mxml = self._mxml.copy()     
    return cpy
def get_mxml(self, key, default=None)

Returns the mxml value of the given key, or the default value if the key is not in the note's mxml dictionary.

Expand source code
def get_mxml(self, key, default=None):
    """
    Returns the mxml value of the given key, or the default value if
    the key is not in the note's mxml dictionary.
    """
    return self._mxml.get(key, default)
def is_chord(self)

Returns true if the note contains children.

Expand source code
def is_chord(self):
    """
    Returns true if the note contains children.
    """
    return len(self._children) > 0
def is_rest(self)

Returns true if the note's pitch is empty, e.g. a Pitch().

Expand source code
def is_rest(self):
    """
    Returns true if the note's pitch is empty, e.g. a Pitch().
    """
    return isinstance(self._pitch, Pitch) and self._pitch.is_empty()
def set_mxml(self, key, value)

Assigns the mxml key and value to the note.

Expand source code
def set_mxml(self, key, value):
    """
    Assigns the mxml key and value to the note.
    """
    self._mxml[key] = value