Source code for reapy.core.item.midi_event

import reapy
import reapy.reascript_api as RPR
from reapy.core import ReapyObject, ReapyObjectList


class MIDIEvent(ReapyObject):

    """Abstract class for MIDI events."""

    def __init__(self, parent, index):
        """
        Create event.

        Parameters
        ----------
        parent : Take
            Take to which the event belongs.
        index : int
            Event index. It is specific to the event type, which means
            a Note and a CC can have the same index.
        """
        self.index = index
        self.parent = parent

    @property
    def _args(self):
        return self.parent, self.index

    @property
    def _del_name(self):
        return 'MIDI_DeleteEvt'

    def delete(self):
        """Delete event from the take."""
        f = getattr(RPR, self._del_name)
        f(self.parent.id, self.index)

    @reapy.inside_reaper()
    def set(self, message=None, position=None, selected=None,
            muted=None, unit="seconds", sort=True):
        """
        Set properties of event if needed.

        Parameters
        ----------
        message : Iterable[int], optional
            Can be any message buffer, for example: (0xb0, 64, 127)
            which is CC64 val127 on channel 1
        position : float, optional
            position at take
        selected : bool, optional
            Whether to select new note (default=False).
        muted : bool, optional
            Whether to mute new note (default=False).
        unit : str ("seconds as default")
            "beats"|"ppq"|"seconds" (default are seconds)
        sort : bool (True as default)
            Whether to resort notes after creating new note
            (default=True). If False, then the new note will be
            ``take.notes[-1]``. Otherwise it will be at its place in
            the time-sorted list ``take.notes``. Set to False for
            improved efficiency when adding several notes, then call
            ``Take.sort_events`` at the end.
        """
        take = self.parent
        if position:
            position = take._resolve_midi_unit((position,), unit)[0]
        if message:
            message = take._midi_to_bytestr(message)
        RPR.MIDI_SetEvt(
            take.id, self.index, selected, muted, position, message,
            len(message), not sort
        )


class MIDIEventList(ReapyObjectList):

    def __init__(self, parent):
        """
        Create event list.

        Parameters
        ----------
        parent : Take
            Take to which the event list belongs.
        """
        self.parent = parent

    def __getitem__(self, key):
        with reapy.inside_reaper():
            if key >= len(self):
                raise IndexError
            return self._elements_class(self.parent, key)

    def __len__(self):
        return getattr(self.parent, self._n_elements)

    @property
    def _args(self):
        return self.parent,

    @property
    def _elements_class(self):
        return MIDIEvent

    @property
    def _n_elements(self):
        return 'n_midi_events'


[docs]class CC(MIDIEvent): """MIDI CC event.""" @property def channel(self): """ CC channel between 0 and 15. :type: int See also -------- CC.infos For maximum efficiency when querying several properties of a CC. """ return RPR.MIDI_GetCC( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[7] @property def channel_message(self): """ CC channel message. :type: int See also -------- CC.infos For maximum efficiency when querying several properties of a CC. """ return RPR.MIDI_GetCC( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[6] @property def _del_name(self): return 'MIDI_DeleteCC' @reapy.inside_reaper() @property def infos(self): """ Return infos about CC. Keys are {"selected", "muted", "position", "channel", "channel_message", "messages"}. :type: dict """ res = list(RPR.MIDI_GetCC( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 ))[3:] res[0] = bool(res[0]) res[1] = bool(res[1]) res[2] = self.parent.ppq_to_time(res[2]) res[-2] = res[-2], res[-1] res.pop() keys = ( "selected", "muted", "position", "channel_message", "channel", "messages" ) return {k: r for k, r in zip(keys, res)} @property def messages(self): """ CC messages. :type: 2-list of int See also -------- CC.infos For maximum efficiency when querying several properties of a CC. """ return RPR.MIDI_GetCC( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[-2:] @property def muted(self): """ Whether CC is muted. :type: bool See also -------- CC.infos For maximum efficiency when querying several properties of a CC. """ return bool(RPR.MIDI_GetCC( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[4]) @property def position(self): """ CC position in seconds. :type: float See also -------- CC.infos For maximum efficiency when querying several properties of a CC. """ return self.infos["position"] @property def selected(self): """ Whether CC is selected. :type: bool See also -------- CC.infos For maximum efficiency when querying several properties of a CC. """ return bool(RPR.MIDI_GetCC( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[3])
[docs]class CCList(MIDIEventList): _elements_class = CC _n_elements = "n_cc"
[docs]class Note(MIDIEvent): """MIDI note.""" @property def channel(self): """ Note channel between 0 and 15. :type: int See also -------- Note.infos For maximum efficiency when querying several properties of a Note. """ return RPR.MIDI_GetNote( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[7] @property def _del_name(self): return 'MIDI_DeleteNote' @property def end(self): """ Note end in seconds. :type: float See also -------- Note.infos For maximum efficiency when querying several properties of a Note. """ return self.infos["end"] @property def infos(self): """ Return infos about note. Keys are {"selected", "muted", "start", "end", "channel", "pitch", "velocity"}. :type: dict """ res = list(RPR.MIDI_GetNote( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 ))[3:] res[0] = bool(res[0]) res[1] = bool(res[1]) res[2] = self.parent.ppq_to_time(res[2]) res[3] = self.parent.ppq_to_time(res[3]) keys = ( "selected", "muted", "start", "end", "channel", "pitch", "velocity" ) return {k: r for k, r in zip(keys, res)} @property def muted(self): """ Whether note is muted. :type: bool See also -------- Note.infos For maximum efficiency when querying several properties of a Note. """ return bool(RPR.MIDI_GetNote( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[4]) @property def pitch(self): """ Note pitch between 0 and 127. :type: int See also -------- Note.infos For maximum efficiency when querying several properties of a Note. """ return RPR.MIDI_GetNote( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[8] @property def selected(self): """ Whether note is selected. :type: bool See also -------- Note.infos For maximum efficiency when querying several properties of a Note. """ return bool(RPR.MIDI_GetNote( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[3]) @property def start(self): """ Note start in seconds. :type: float See also -------- Note.infos For maximum efficiency when querying several properties of a Note. """ return self.infos["start"] @property def velocity(self): """ Note velocity between 0 and 127. :type: int See also -------- Note.infos For maximum efficiency when querying several properties of a Note. """ return RPR.MIDI_GetNote( self.parent.id, self.index, 0, 0, 0, 0, 0, 0, 0 )[9]
[docs]class NoteList(MIDIEventList): _elements_class = Note _n_elements = "n_notes"