
    rh                    f   % S r SSKJr  / SQrSSKJr  SSKrSSKJr  SSKr	SSK
Jr  SSKJr  SS	K
Jr  SS
K
Jr  SSK
Jr  SSK
Jr  \R$                  " S5      r " S S\R(                  5      r\R,                  " SSS5      S4S j5       r\R,                  " SSS5      S5S j5       r\S6S j5       r\S7S j5       r\S8S j5       rS9S jrS:S jr\R,                  " SSS5      S;S j5       rS<S jrS=S jrS>S jr " S  S!\5      r " S" S#\5      r  " S$ S%\5      r! " S& S'\5      r"S(r#\\ -  \!-  \"-  \	RH                  S)   -  r% " S* S+\RL                  5      r' " S, S)\'5      r( " S- S.\RL                  5      r) " S/ S0\RL                  5      r*\'\(\)\*/r+S1\,S2'   \-S3:X  a  SSK
r
\
R\                  " 5         gg)?a  
Objects and tools for processing MIDI data.  Converts from MIDI files to
:class:`~music21.midi.MidiEvent`, :class:`~music21.midi.MidiTrack`, and
:class:`~music21.midi.MidiFile` objects, and vice-versa.

This module originally used routines from Will Ware's public domain midi.py
library from 2001 which was once posted at (http link)
groups.google.com/g/alt.sources/msg/0c5fc523e050c35e
    )annotations)	MidiEventMidiFile	MidiTrackMidiException	DeltaTime
MetaEventsChannelVoiceMessagesChannelModeMessagesSysExEventscharToBinary	getNumbergetVariableLengthNumber	putNumberputVariableLengthNumbergetNumbersAsListputNumbersAsListintsToHexBytesr
   r   r   METAEVENT_MARKER)IterableN)overload)common)ContainsEnum)defaults)environment)exceptions21)prebasez	midi.basec                      \ rS rSrSrg)r   8    N)__name__
__module____qualname____firstlineno____static_attributes__r        K/home/james-whalen/.local/lib/python3.13/site-packages/music21/midi/base.pyr   r   8   s    r&   r   zv9.7v10zuse bin(ord(char)) instead.c                Z    [        [        U 5      5      SS nS[        U5      -
  S-  nX!-   $ )a  
DEPRECATED: just use bin(ord(char)) instead.

Or for the exact prior output (with left-padding)
use `f'{int(bin(ord(char))[2:]):08d}'`


Convert a char into its binary representation. Useful for debugging.

>>> #_DOCS_SHOW midi.charToBinary('a')
>>> f'{int(bin(ord("a"))[2:]):08d}'  #_DOCS_HIDE
'01100001'

Note: This function is deprecated and will be removed in v10.  Music21 actually
predates the bin() function in Python (added in Python 2.6).
   N   0)binordlen)charbinaryzeroFixs      r'   r   r   <   s3    $ T^ABF3v;#%Gr&   zJust use bytes(...) insteadc                    [        U 5      $ )a  
(Deprecated: just use bytes(...) instead)

Convert a list of integers into hex bytes, suitable for testing MIDI encoding.

Here we take NOTE_ON message, Middle C, 120 velocity and translate it to bytes

>>> #_DOCS_SHOW midi.intsToHexBytes([0x90, 60, 120])
>>> bytes([0x90, 60, 120])  #_DOCS_HIDE
b'\x90<x'

Note: This function is deprecated and will be removed in v10.  This
function has not been needed since music21 became Python 3-only in v.5.
)bytes)intLists    r'   r   r   R   s      >r&   c                    g Nr    midiStrlengths     r'   r   r   e       r&   c                    g r7   r    r8   s     r'   r   r   i   r;   r&   c                    g r7   r    r8   s     r'   r   r   m   r;   r&   c                R   Sn[        U [        5      (       dx  [        U5       Hc  nX   n[        U[        5      (       a
  US-  U-   nM&  [        R                  (       a  [        U[
        5      (       d   eUS-  [        U5      -   nMe     X US 4$ U nXUSU-  -	  SU-  -  -
  nXR-
  nX&4$ )a=  
Return the value of a string byte or bytes if length > 1
from an 8-bit string or bytes object

Then, return the remaining string or bytes object

The `length` is the number of chars to read.
This will sum a length greater than 1 if desired.

Note that MIDI uses big-endian for everything.
This is the inverse of Python's chr() function.

Read first two bytes

>>> midi.getNumber(b'test', 2)
(29797, b'st')

That number comes from:

>>> ord('t') * 256 + ord('e')
29797

Demonstration of reading the whole length in:

>>> midi.getNumber(b'test', 4)
(1952805748, b'')

Reading in zero bytes leaves the midiStr unchanged:

>>> midi.getNumber(b'test', 0)
(0, b'test')


The method can also take in an integer and return an integer and the remainder part.
This usage might be deprecated in the future and has already been replaced within
music21 internal code.

>>> midi.getNumber(516, 1)   # = 2*256 + 4
(4, 512)

As of v9.7, this method can also take a string as input and return a string.
This usage is deprecated and will be removed in v10.

>>> midi.getNumber('test', 2)
(29797, 'st')
r   r+   N)
isinstanceintrangetTYPE_CHECKINGstrr.   )r9   r:   	summationimidiStrOrNummidNumbigBytess          r'   r   r   q   s    ^ Igs##vA":L,,,&!^|;	??%lC8888&!^s</@@	  &'***!f*51v:FG	%""r&   c                    SnSnUS:  a,  X   nUS-  US-  -   nUS-  nUS-  (       d  XUS 4$ US:  a  M,  [        S5      e)	u
  
Given a string or bytes of data, strip off the first character, or all high-byte characters
terminating with one whose ord() function is < 0x80.  Thus, a variable number of bytes
might be read.

After finding the appropriate termination,
return the remaining string.

This is necessary as DeltaTime times are given with variable size,
and thus may be of different numbers if characters are used.

>>> midi.getVariableLengthNumber(b'A-u')
(65, b'-u')
>>> midi.getVariableLengthNumber(b'-u')
(45, b'u')
>>> midi.getVariableLengthNumber(b'u')
(117, b'')

>>> midi.getVariableLengthNumber(b'test')
(116, b'est')
>>> midi.getVariableLengthNumber(b'E@-E')
(69, b'@-E')
>>> midi.getVariableLengthNumber(b'@-E')
(64, b'-E')
>>> midi.getVariableLengthNumber(b'-E')
(45, b'E')
>>> midi.getVariableLengthNumber(b'E')
(69, b'')

Test that variable length characters work:

>>> midi.getVariableLengthNumber(b'\xff\x7f')
(16383, b'')
>>> midi.getVariableLengthNumber('中xy'.encode('utf-8'))
(210638584, b'y')

If no low-byte character is encoded, raises an IndexError

>>> midi.getVariableLengthNumber('中国'.encode('utf-8'))
Traceback (most recent call last):
IndexError: index out of range

Up to v9.7, this method could also take a string as input and return a string.  This usage is
now removed.
r   i              Nz#did not find the end of the number!)r   )	midiBytesrE   rF   xs       r'   r   r      sg    b I	A
c'L !^D1		QDm++ c' =
>>r&   zuse list(midiBytes) insteadc                    / nU  HE  n[        U[        5      (       a  UR                  [        U5      5        M4  UR                  U5        MG     U$ )a  
**Deprecated**: this method existed in Python 2.6 and for Python 2 (no bytes)
compatibility.  Now use `list(midiBytes)` instead.

Translate each char into a number, return in a list.
Used for reading data messages where each byte encodes
a different discrete value.

>>> #_DOCS_SHOW midi.getNumbersAsList(b'\x00\x00\x00\x03')
>>> list(b'\x00\x00\x00\x03') #_DOCS_HIDE
[0, 0, 0, 3]

Now just do:

>>> list(b'\x00\x00\x00\x03')
[0, 0, 0, 3]
)r?   rD   appendr.   )rO   postmidiBytes      r'   r   r      sC    & Dh$$KKH&KK!	 
 Kr&   c                    [        5       n[        U5       H&  nSUS-
  U-
  -  nX-	  S-  nUR                  U5        M(     [        U5      $ )a  
Put a single number as a hex number at the end of a bytes object `length` bytes long.

>>> midi.putNumber(3, 4)
b'\x00\x00\x00\x03'
>>> midi.putNumber(0, 1)
b'\x00'

>>> midi.putNumber(258, 2)
b'\x01\x02'

If the number is larger than the length currently only the least significant
bytes are returned. This behavior may change in the near future to raise an
exception instead.

>>> midi.putNumber(258, 1)
b'\x02'
r+   rM      )	bytearrayrA   rR   r4   )numr:   lstrF   nthisNums         r'   r   r     sO    & +C6]!a 8t#

7 
 :r&   c                    U S:  a  [        SU  35      e[        5       n U S-  U S-	  pUR                  US-   5        U S:X  a  OM&  UR                  5         US   S-  US'   [	        U5      $ )a  
Turn an integer number into the smallest bytes object that can hold it for MIDI

Numbers < 128 are encoded as single bytes and are the same as bytes([x])

>>> midi.putVariableLengthNumber(4)
b'\x04'
>>> midi.putVariableLengthNumber(127)
b'\x7f'
>>> bytes([127])
b'\x7f'
>>> midi.putVariableLengthNumber(0)
b'\x00'

Numbers > 7bit but < 16384 need two characters,
with the first character set as 0x80 + n // 128
and the second character set as n % 128:

>>> midi.putVariableLengthNumber(128)
b'\x81\x00'
>>> midi.putVariableLengthNumber(129)
b'\x81\x01'
>>> midi.putVariableLengthNumber(255)
b'\x81\x7f'

This differs from the 8-bit representation of
`bytes([x])`:

>>> bytes([128])
b'\x80'
>>> bytes([255])
b'\xff'


This method can also deal with numbers > 255, which `bytes` cannot.

>>> midi.putVariableLengthNumber(256)
b'\x82\x00'
>>> bytes([256])
Traceback (most recent call last):
ValueError: bytes must be in range(0, 256)

It also differs from the normal way of representing 256 in Python bytes:

>>> bytes([1, 0])
b'\x01\x00'

Here are MIDI representation of other numbers that are too large to fit in 8 bits
but stored in two bytes in MIDI.

>>> midi.putVariableLengthNumber(1024)
b'\x88\x00'

Notice that the least significant byte is second.

>>> midi.putVariableLengthNumber(8192)
b'\xc0\x00'
>>> midi.putVariableLengthNumber(8193)
b'\xc0\x01'

This is the maximum normal MIDI number that can be stored in 2 bytes.

>>> midi.putVariableLengthNumber(16383)
b'\xff\x7f'

Numbers >= 16384 are not used in 2-byte classic MIDI,
but this routine continues the basic principle from above:

>>> midi.putVariableLengthNumber(16384)
b'\x81\x80\x00'
>>> midi.putVariableLengthNumber(16384 + 128)
b'\x81\x81\x00'
>>> midi.putVariableLengthNumber(16384 * 2)
b'\x82\x80\x00'
>>> midi.putVariableLengthNumber(16384 ** 2)
b'\x81\x80\x80\x80\x00'

Negative numbers raise MidiException

>>> midi.putVariableLengthNumber(-1)
Traceback (most recent call last):
music21.midi.base.MidiException: cannot putVariableLengthNumber() when number is negative: -1
r   z:cannot putVariableLengthNumber() when number is negative: rL   rK   rN   )r   rW   rR   reverser4   )rP   rY   ys      r'   r   r   *  s    l 	1uXYZX[\]]
+C
4xa1

1t86	 
 KKM"gnCG:r&   c                    [        5       nU  H3  nUS:  a  US-  nUS:  a  [        SU 35      eUR                  U5        M5     [        U5      $ )a  
Translate a list of numbers (0-255) into bytes.
Used for encoding data messages where each byte encodes a different discrete value.

>>> midi.putNumbersAsList([0, 0, 0, 3])
b'\x00\x00\x00\x03'

For positive numbers this method behaves the same as `bytes(numList)` and that
method should be used if you are sure all numbers are positive.

>>> bytes([0, 0, 0, 3])
b'\x00\x00\x00\x03'


If a number is < 0 then it wraps around from the top.  This is used in places
like MIDI key signatures where flats are represented by `256 - flats`.

>>> midi.putNumbersAsList([0, 0, 0, -3])
b'\x00\x00\x00\xfd'
>>> midi.putNumbersAsList([0, 0, 0, -1])
b'\x00\x00\x00\xff'

The behavior with negative numbers is different from `bytes(numList)`

List can be of any length

>>> midi.putNumbersAsList([1, 16, 255])
b'\x01\x10\xff'

Any number > 255 (or less than -255) raises an exception:

>>> midi.putNumbersAsList([256])
Traceback (most recent call last):
music21.midi.base.MidiException: Cannot place a number > 255 in a list: 256
r      z'Cannot place a number > 255 in a list: )rW   r   rR   r4   )numListrS   rZ   s      r'   r   r     sW    H ;Dq5CA8"I! MNNA  ;r&   c                  4    \ rS rSrSrSrSrSrSrSr	Sr
S	rS
rg)r
   i  zc
ChannelVoiceMessages are the main MIDI messages for channel 1-16, such as
NOTE_ON, NOTE_OFF, etc.
rN                     r    N)r!   r"   r#   r$   __doc__NOTE_OFFNOTE_ONPOLYPHONIC_KEY_PRESSURECONTROLLER_CHANGEPROGRAM_CHANGECHANNEL_KEY_PRESSURE
PITCH_BENDr%   r    r&   r'   r
   r
     s/     HG"NJr&   r
   c                  4    \ rS rSrSrSrSrSrSrSr	Sr
S	rS
rg)r   i  x   y   z   {   |   }   ~   rL   r    N)r!   r"   r#   r$   ALL_SOUND_OFFRESET_ALL_CONTROLLERSLOCAL_CONTROLALL_NOTES_OFFOMNI_MODE_OFFOMNI_MODE_ONMONO_MODE_ONPOLY_MODE_ONr%   r    r&   r'   r   r     s+    M MMMLLLr&   r   c                  `    \ rS rSrSrSrSrSrSrSr	Sr
S	rS
rSrSrSrSrSrSrSrSrSrSrSrg)r	   i  r   rM   r*               rK   r+   	       !   /   Q   T   X   Y   rL   rV   r    N)r!   r"   r#   r$   SEQUENCE_NUMBER
TEXT_EVENTCOPYRIGHT_NOTICESEQUENCE_TRACK_NAMEINSTRUMENT_NAMELYRICMARKER	CUE_POINTPROGRAM_NAMESOUND_SET_UNSUPPORTEDMIDI_CHANNEL_PREFIX	MIDI_PORTEND_OF_TRACK	SET_TEMPOSMPTE_OFFSETTIME_SIGNATUREKEY_SIGNATURESEQUENCER_SPECIFIC_META_EVENTUNKNOWNr%   r    r&   r'   r	   r	     sh    OJOEFIL !ILILNM$(!Gr&   r	   c                      \ rS rSrSrSrSrg)r   i        r    N)r!   r"   r#   r$   F0_SYSEX_EVENTF7_SYSEX_EVENTr%   r    r&   r'   r   r     s    NNr&   r   rV   r   c                  v   \ rS rSrSrS\R                  SS4       SS jjr\SS j5       r	SS jr
\SS	 j5       r\R                  SS
 j5       r\SS j5       r\R                  SS j5       r\SS j5       r\R                  SS j5       rSS S jjrS!S jrS!S jrS"S jrS#S jrS#S jrS#S jrS$S jrSrg)%r   i  aj  
A model of a MIDI event, including note-on, note-off, program change,
controller change, any many others.

MidiEvent objects are paired (preceded) by :class:`~music21.midi.DeltaTime`
objects in the list of events in a MidiTrack object.

The `track` argument must be a :class:`~music21.midi.MidiTrack` object.

The `type` attribute is an enumeration of a Midi event from the ChannelVoiceMessages,
ChannelModeMessages, SysExEvents, or MetaEvents enums; if unspecified,
defaults to MetaEvents.UNKNOWN.

The `channel` attribute is an integer channel id, from 1 to 16.

The `time` attribute is an integer duration of the event in ticks. This value
can be zero. This value is not essential, as ultimate time positioning is
determined by :class:`~music21.midi.DeltaTime` objects.

The `pitch` attribute is only defined for note-on and note-off messages.
The attribute stores an integer representation (0-127, with 60 = middle C).

The `velocity` attribute is only defined for note-on and note-off messages.
The attribute stores an integer representation (0-127).  A note-on message with
velocity 0 is generally assumed to be the same as a note-off message.

The `data` attribute is used for storing other messages,
such as SEQUENCE_TRACK_NAME string values.

.. warning::

    The attributes `.midiProgram` and `.midiChannel` on :class:`~music21.instrument.Instrument`
    objects are 0-indexed, just as they need to be in the written binary .mid.
    However, as a convenience, :attr:`MidiEvent.channel` is 1-indexed. No
    analogous convenience is provided for program change data.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = midi.ChannelVoiceMessages.NOTE_ON
>>> me1.channel = 3
>>> me1.time = 200
>>> me1.pitch = 60
>>> me1.velocity = 120
>>> me1
<music21.midi.MidiEvent NOTE_ON, t=200, track=1, channel=3, pitch=60, velocity=120>

>>> me2 = midi.MidiEvent(mt)
>>> me2.type = midi.MetaEvents.SEQUENCE_TRACK_NAME
>>> me2.data = 'guitar'
>>> me2
<music21.midi.MidiEvent SEQUENCE_TRACK_NAME, track=1, data=b'guitar'>

Changed in v9.7 - None is not a valid type anymore.  Use MetaEvents.UNKNOWN instead.
    Channel defaults to 1.
Nr   rM   c                z    Xl         X l        X0l        X@l        S U l        S U l        S U l        S U l        S U l        g r7   )	tracktypetimechannel
parameter1
parameter2	centShiftcorrespondingEventlastStatusByte)selfr   r   r   r   s        r'   __init__MidiEvent.__init__?  sC    
 &+
$(		#*.*. $(
 37 )-r&   c                    U R                   [        R                  :X  a  gU R                   [        R                  :X  a  gg)a  
Ensure that for MidiEvents at the same "time", that order is
NOTE_OFF, PITCH_BEND, all others.

>>> CVM = midi.ChannelVoiceMessages
>>> noteOn = midi.MidiEvent(type=CVM.NOTE_ON)
>>> noteOff = midi.MidiEvent(type=CVM.NOTE_OFF)
>>> pitchBend = midi.MidiEvent(type=CVM.PITCH_BEND)

>>> sorted([noteOn, noteOff, pitchBend], key=lambda me: me.sortOrder)
[<music21.midi.MidiEvent NOTE_OFF, track=None, channel=1>,
 <music21.midi.MidiEvent PITCH_BEND, track=None, channel=1>,
 <music21.midi.MidiEvent NOTE_ON, track=None, channel=1>]
iir   )r   r
   rk   rq   r   s    r'   	sortOrderMidiEvent.sortOrderZ  s3    " 99,555YY.999r&   c                6   U R                   c  S nOB[        U R                   [        5      (       a  U R                   nOU R                   R                  n[        U R                  [
        5      (       a  U R                  R                  nO%U R                  c  SnO[        U R                  5      nU S3nU R                  S:w  a  USU R                  < S3-  nUSU 3-  nU R                  [        ;   d  U R                  [        ;   a  USU R                  < 3-  nU R                  [        R                  [        R                  4;   a  SS/nOU R                  c  S	/nOS
S/nU H1  n[        X5      c  M  US-   U-   S-   [        [        X5      5      -   nM3     U$ )NNone, r   zt=ztrack=z
, channel=pitchvelocitydatar   r   =)r   r?   r@   indexr   r   namereprr   r
   r   r   rl   rk   r   getattr)r   
trackIndex	printTyperattrListattribs         r'   _reprInternalMidiEvent._reprInternalr  sf   ::J

C((J))J dii..		IYYITYYIk99>2dii]"%%A	vj\""99,,		=P0P:dll-..A99-557K7T7TUU,H&"8(,7Ft$0Hv%+d743H.II  r&   c                    U R                   [        R                  [        R                  4;   a"  U R                  b  [        U R                  5      $ g r7   )r   r
   rl   rk   r   r@   r   s    r'   r   MidiEvent.pitch  s?     II.668L8U8UVVOO/t''r&   c                    Xl         g r7   r   r   values     r'   r   r         r&   c                Z    [        U R                  [        5      (       d  g U R                  $ r7   )r?   r   r@   r   s    r'   r   MidiEvent.velocity  s     $//3//r&   c                    Xl         g r7   )r   r   s     r'   r   r     r   r&   c                    U R                   $ )z
Read or set the data (`.parameter1`) for the object

Does some automatic conversions:

>>> me = midi.MidiEvent(type=midi.ChannelModeMessages.LOCAL_CONTROL)
>>> me.data = True
>>> me.data
b'\x01'
r   r   s    r'   r   MidiEvent.data  s     r&   c                    Ubf  [        U[        5      (       dQ  [        U[        5      (       a  UR                  S5      nO*[        U[        5      (       a  [        [        U5      /5      nXl        g )Nzutf-8)r?   r4   rD   encodeboolr@   r   r   s     r'   r   r     sQ    Zu%=%=%%%W-E4((s5zl+r&   c                R   US-  nX:  a  UnOUSU-  :  a  SU-  nSnSU-
  nUnX-  nUS:  a  [        [        Xu-  5      5      nOUS:  a  [        [        Xv-  5      5      nOSnXH-   n	[        U	5      n
U
S   nUS-  n[        U
5      S:  a  U
S   nUS-  nOUnSnXl        Xl        g)	a  
Treat this event as a pitch bend value, and set the .parameter1 and
 .parameter2 fields appropriately given a specified bend value in cents.

Also called Pitch Wheel

The `bendRange` parameter gives the number of half steps in the bend range.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt, type=midi.ChannelVoiceMessages.PITCH_BEND)
>>> me1.setPitchBend(50)
>>> me1.parameter1, me1.parameter2
(0, 80)
>>> me1.setPitchBend(100)
>>> me1.parameter1, me1.parameter2
(0, 96)

Neutral is 0, 64

>>> me1.setPitchBend(0)
>>> me1.parameter1, me1.parameter2
(0, 64)

Parameter 2 is the most significant digit, not
parameter 1.

>>> me1.setPitchBend(101)
>>> me1.parameter1, me1.parameter2
(40, 96)

Exceeding maximum pitch bend sets the max (127, 127)

>>> me1.setPitchBend(200)
>>> me1.parameter1, me1.parameter2
(127, 127)
>>> me1.setPitchBend(300)
>>> me1.parameter1, me1.parameter2
(127, 127)

>>> me1.setPitchBend(-50)
>>> me1.parameter1, me1.parameter2
(0, 48)
>>> me1.setPitchBend(-100)
>>> me1.parameter1, me1.parameter2
(0, 32)
>>> me1.setPitchBend(-196)
>>> me1.parameter1, me1.parameter2
(36, 1)
>>> me1.setPitchBend(-200)
>>> me1.parameter1, me1.parameter2
(0, 0)

Again, excess trimmed

>>> me1.setPitchBend(-300)
>>> me1.parameter1, me1.parameter2
(0, 0)

But a larger `bendRange` can be set in semitones for non-GM devices:

>>> me1.setPitchBend(-300, bendRange=4)
>>> me1.parameter1, me1.parameter2
(0, 16)
>>> me1.setPitchBend(-399, bendRange=4)
>>> me1.parameter1, me1.parameter2
(20, 0)

OMIT_FROM_DOCS

Pitch bends very close to 0 formerly had problems

>>> me1.setPitchBend(-196)
>>> me1.parameter1, me1.parameter2
(36, 1)
>>> me1.setPitchBend(-197)
>>> me1.parameter1, me1.parameter2
(123, 0)
d   r]   i    i?  r   rL   rM   N)r@   roundr   r/   r   r   )r   cents	bendRange	centRangecentertopSpan
bottomSpanshiftScalarshifttarget	charValued1d2s                r'   setPitchBendMidiEvent.setPitchBend  s    b O	ER)^#NEv%
'19k345EQYk678EE ,F3	q\$Yy>A1BdBBB r&   c                \   [        U5      S:  a  [        SU< S35      eUS   nUS   nSn[        U5      S:  a  US   nUS-  nUS-  nUS-   U l        [        U5      U l        U R                  [        R
                  [        R                  4;   a-  US:  a  [        S	U R                  < S
U 35      eX0l        USS $ U R                  [        R                  :X  a  Sn[        R                  U5      (       ah  [        U5      U l        U R                  [        R                  :X  a  SnUS   S:H  U l        O*U R                  [        R                  :X  a  SnUS   U l        U(       d  X0l        X@l        USS $ U R                  [        R                   :X  a  X0l        X@l        USS $ U R                  [        R"                  [        R$                  4;   a  X0l        X@l        USS $ U R                  [        R*                  :X  a  X0l        X@l        USS $ [-        SU R                   35      e)a  
Take a set of bytes that represent a ChannelVoiceMessage and set the
appropriate event type and data, returning the remaining bytes.

Channel voice messages start with a one-byte message from 0x80 to 0xEF,
where the first nibble (8-E) is the message type and the second nibble (0-F)
is the channel represented in hex.

First let's create a MidiEvent that does not know its type.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1
<music21.midi.MidiEvent UNKNOWN, track=1>

Now create two messages -- a note on (at pitch = 60 or C4) at velocity 120

>>> midBytes = bytes([0x92, 60, 120])
>>> midBytes
b'\x92<x'

Add a second hypothetical message (would normally be a delta time)

>>> midBytes += b'hello'
>>> midBytes
b'\x92<xhello'


Now see how parsing this ChannelVoiceMessage changes the MidiEvent

>>> remainder = me1.parseChannelVoiceMessage(midBytes)
>>> me1
<music21.midi.MidiEvent NOTE_ON, track=1, channel=3, pitch=60, velocity=120>

The remainder would probably contain a delta time and following
events, but here we'll just show that it passes whatever is left through.

>>> remainder
b'hello'

We will ignore remainders for the rest of this demo.  Note that all
attributes are set properly:

>>> me1.type
<ChannelVoiceMessages.NOTE_ON: 0x90>
>>> me1.pitch  # 60 = middle C
60
>>> me1.velocity
120

The channel is 3 because 0x90 is NOTE_ON for channel 1, 0x91 is 2, and 0x92 is 3, etc.

>>> me1.channel
3

Now let's make a program change on channel 16:

>>> me2 = midi.MidiEvent(mt)
>>> rem = me2.parseChannelVoiceMessage(bytes([0xCF, 71]))
>>> me2
<music21.midi.MidiEvent PROGRAM_CHANGE, track=1, channel=16, data=71>
>>> me2.data  # 71 = clarinet (0-127 indexed)
71

Program changes and channel pressures only go to 127.  More than that signals an error:

>>> me2.parseChannelVoiceMessage(bytes([0xCF, 200]))
Traceback (most recent call last):
music21.midi.base.MidiException: Cannot have a
    <ChannelVoiceMessages.PROGRAM_CHANGE: 0xC0> followed by a byte > 127: 200
r*   z
length of z must be at least 2r   rM   r      rL   zCannot have a z followed by a byte > 127: NFTr   z"expected ChannelVoiceMessage, got )r/   
ValueErrorr   r
   r   ro   rp   r   r   rn   r   hasValuer|   r   r   r   rq   rl   rk   r   r   rm   	TypeError)r   rO   byte0byte1byte2	msgNybblechannelNybblespecificDataSets           r'   parseChannelVoiceMessage"MidiEvent.parseChannelVoiceMessage?  s   V y>Az)6IJKK!!y>AaLE	"T\$q((3	 99-<<-BBD Ds{#$TYYM1LUGTV VIQR= YY.@@@#O"++E22/6	99 3 A AA&*O!*1!5DIYY"5"B"BB&*O )!DI""'"'QR= YY.999#O#OQR= YY/779M9V9VWWJ!MQR= YY.FFF#O#OQR= <TYYKHIIr&   c           	     D   [        U5      S:  a!  [        R                  S[        U5      /5        gUS   nUS:  a0  U R                  b  [        U R                  /5      nOSnX1-   nUS   nOUS:w  a  X l        US	-  nUS
   n[        R                  U5      (       a  U R                  U5      $ [        R                  U5      (       a.  [        U5      U l
        [        US
S 5      u  pgUSU U l        XvS $ U[        :X  a^  [        R                  U5      (       a  [        U5      U l
        O[        R                  U l
        [        USS 5      u  pgUSU U l        XvS $ [        R                  S[!        U5      S[!        US
   5      /5        [#        S[!        U5       35      e)a  
Parse the bytes given and take the beginning
section and convert it into data for this event and return the
now truncated bytes.

>>> channel = 0x2
>>> noteOnMessage = midi.ChannelVoiceMessages.NOTE_ON | channel
>>> hex(noteOnMessage)
'0x92'

This is how the system reads note-on messages (0x90-0x9F) and channels

>>> hex(0x91 & 0xF0)  # testing message type extraction
'0x90'
>>> hex(0x92 & 0xF0)  # testing message type extraction
'0x90'
>>> (0x90 & 0x0F) + 1  # getting the channel
1
>>> (0x9F & 0x0F) + 1  # getting the channel
16
r*   z%MidiEvent.read(): got bad data stringr&   r   rN   N   rV   r   rM   zgot unknown midi event typezhex(midiBytes[1])zUnknown midi event type )r/   environLocal
printDebugr   r   r4   r
   r   r   r   r   r   r   r   r	   r   hexr   )r   rO   r   runningStatusBytemsgTyper   r:   midiBytesAfterLengths           r'   readMidiEvent.read  s   , y>A ##8$y/JL
 q\ 4< "".$)4+>+>*?$@!$+! *5IaLEd]"'t|q\  ((1100;;!!%((#E*DI+B9QR=+Q(F,Wf5DI'00 &&""5))&u-	 '..	+B9QR=+Q(F,Wf5DI'00 ##%BCJ%8#il:K%M N":3u:, GHHr&   c           	     	   [         R                  (       a!  [        U R                  [        5      (       d   eU R                  [
        ;   Ga  [        U R                  S-
  U R                  R                  -   /5      nU R                  [
        R                  [
        R                  4;  a  U R                  b  U R                  c  [        S5      e[        U R                  [        5      (       a  [        U R                  /5      nOU R                  n[        U R                  [        5      (       a  [        U R                  /5      nOU R                  nX#-   nX-   $ U R                  [
        R                  :X  a9  [        U R                  [        5      (       a  [        U R                  /5      nX-   $  [        U R                  [        5      (       a  [        U R                  /5      nX-   $ [        U R                  [        5      (       a  U R                  nX-   $ [!        S5      eU R                  [$        ;   a  U R                  b  [        SU R                  -   S-
  /5      n[        U R                  R                  /5      n[        U R                  [        5      (       a  [        U R                  /5      nOU R                  nXV-   U-   $ U R                  [&        ;   a  [        U R                  [        5      (       aj  [        U R                  R                  /5      nU[)        [+        U R                  5      5      -   n[         R,                  " [        U R                  5      nXx-   $ U R                  [.        ;   a  [        U R                  [        [0        45      (       a~  [        [2        /5      nU[        U R                  R                  /5      -  nU[)        [+        U R                  5      5      -  n [         R,                  " [        U R                  5      nXx-   $ [        SU R                  < 35      e! [         ["        4 a!    [        SU  SU R                  < S3S-   5      ef = f! [4        [         4 aP    U[6        R8                  " S	[         R,                  " [0        U R                  5      5      R;                  S
S5      -   s $ f = f)a  
Return a set of bytes for this MIDI event (used for translating from music21 to MIDI)

>>> noteOn = midi.MidiEvent(type=midi.ChannelVoiceMessages.NOTE_ON, channel=10)
>>> noteOn.pitch = 60
>>> noteOn.velocity = 127
>>> noteOn.getBytes()
b'\x99<\x7f'

Changing the pitch changes the second byte (from less than to greater than):

>>> noteOn.pitch = 62
>>> noteOn.getBytes()
b'\x99>\x7f'
>>> ord('>')
62

Changing the velocity changes the third byte:

>>> noteOn.velocity = 64
>>> noteOn.getBytes()
b'\x99>@'

The third byte is `\x40` but it is represented by '@'

>>> ord('@')
64
>>> hex(64)
'0x40'

And changing the channel changes the first byte:

>>> noteOn.channel = 11
>>> noteOn.getBytes()
b'\x9a>@'
rM   z>Cannot write MIDI event without parameter1 and parameter2 set.zdata must be bytes or intzGot incorrect data for z in .data: r   z"cannot parse Miscellaneous Messagerf   NFKDasciiignorezunknown midi event type: )rB   rC   r?   r   r   r
   r4   r   r   ro   rp   r   r   r   r@   r   r   r   r   r   r   r/   castr	   rD   r   UnicodeDecodeErrorunicodedata	normalizer   )	r   bytes0
param1data
param2datar   channelModemsgValuessys_datas	            r'   getBytesMidiEvent.getBytes  s   J ??dii666699,,DLL1,tyy>?@Fyy!5!D!D!5!J!J!L L??*doo.E'X  doos33!&'8!9J!%J doos33!&'8!9J!%J!. =  2AAAjQUQZQZ\_F`F`dii[) = 
@!$))S11$dii[1 =  $DIIu55#yy =  ((CDD YY--$))2G!4q!8 9:Kdiioo./H$))S))dii[)yy)D00YY+%*TYY*F*Ftyy'(A+C		N;;AvveTYY/H<YY*$DIIs|)L)L'()A		())A(TYY88A,66%3|#  ";DII= IJJO ":. @'1${499-rR>?@ @@: '	2 ,
 ;00FF3		* &(+, ,,s+   35P9 ,+P9 P9 7(Q- 91Q*-ASSc                b    U R                   [        R                  :X  a  U R                  S:w  a  gg)a  
Return a boolean if this is a note-on message and velocity is not zero.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = midi.ChannelVoiceMessages.NOTE_ON
>>> me1.velocity = 120
>>> me1.isNoteOn()
True
>>> me1.isNoteOff()
False

A zero velocity note-on is treated as a note-off:

>>> me1.velocity = 0
>>> me1.isNoteOn()
False
>>> me1.isNoteOff()
True

A midi event can be neither a note on or a note off.

>>> me1.type = midi.ChannelVoiceMessages.PROGRAM_CHANGE
>>> me1.isNoteOn()
False
>>> me1.isNoteOff()
False
r   TF)r   r
   rl   r   r   s    r'   isNoteOnMidiEvent.isNoteOn  s(    : 99,444!9Kr&   c                    U R                   [        R                  :X  a  gU R                   [        R                  :X  a  U R                  S:X  a  gg)a  
Return a boolean if this should be interpreted as a note-off message,
either as a real note-off or as a note-on with zero velocity.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = midi.ChannelVoiceMessages.NOTE_OFF
>>> me1.isNoteOn()
False
>>> me1.isNoteOff()
True

>>> me2 = midi.MidiEvent(mt)
>>> me2.type = midi.ChannelVoiceMessages.NOTE_ON
>>> me2.velocity = 0
>>> me2.isNoteOn()
False
>>> me2.isNoteOff()
True

See :meth:`~music21.midi.MidiEvent.isNoteOn` for more examples.
Tr   F)r   r
   rk   rl   r   r   s    r'   	isNoteOffMidiEvent.isNoteOff  s>    . 99,555YY.6664==A;Mr&   c                &    U R                   S:X  a  gg)z
Return a boolean if this is a DeltaTime subclass.

>>> mt = midi.MidiTrack(1)
>>> dt = midi.DeltaTime(mt)
>>> dt.isDeltaTime()
True
r   TF)r   r   s    r'   isDeltaTimeMidiEvent.isDeltaTime  s     99#r&   c                    U R                  5       (       aJ  UR                  5       (       a5  U R                  UR                  :X  a  U R                  UR                  :X  a  gg)a  
Returns True if `other` is a MIDI event that specifies
a note-off message for this message.  That is, this event
is a NOTE_ON message, and the other is a NOTE_OFF message
for this pitch on this channel.  Otherwise returns False

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = midi.ChannelVoiceMessages.NOTE_ON
>>> me1.velocity = 120
>>> me1.pitch = 60

>>> me2 = midi.MidiEvent(mt)
>>> me2.type = midi.ChannelVoiceMessages.NOTE_ON
>>> me2.velocity = 0
>>> me2.pitch = 60

`me2` is a Note off for `me1` because it has velocity 0 and matches
pitch.

>>> me1.matchedNoteOff(me2)
True

Now the pitch does not match, so it does not work.

>>> me2.pitch = 61
>>> me1.matchedNoteOff(me2)
False

>>> me2.type = midi.ChannelVoiceMessages.NOTE_OFF
>>> me1.matchedNoteOff(me2)
False

>>> me2.pitch = 60
>>> me1.matchedNoteOff(me2)
True

Channels must match also:

>>> me2.channel = 12
>>> me1.matchedNoteOff(me2)
False

Note that this method is no longer used in MIDI Parsing
because it is inefficient.
TF)r  r  r   r   )r   others     r'   matchedNoteOffMidiEvent.matchedNoteOff  sA    ^ ==??u00zzU[[(T\\U]]-Jr&   )r   r   r   r   r   r   r   r   r   r   r   r   )r   MidiTrack | Noner   MidiEventTypesr   r@   r   r@   returnr@   r#  rD   )r#  
int | None)r   r%  )r#  zint | bytes | None)r   zint | str | bytes | bool | None)r*   )r   zint | floatr#  r   rO   r4   r#  r4   r#  r4   r#  r   )r  r   r#  r   )r!   r"   r#   r$   rj   r	   r   r   propertyr   r   r   setterr   r   r   r   r   r  r  r  r  r  r%   r    r&   r'   r   r     s   6t *.(2(:(: !	-&-%- - 	-6  ."J   \\     
 __      
[[   vp~J@VIpsKlB:2r&   r   c                  h   ^  \ rS rSrSr   S     S	U 4S jjjrS
U 4S jjrSS jrSS jrSr	U =r
$ )r   i  a  
A :class:`~music21.midi.MidiEvent` subclass that stores the
time change (in ticks) since the start or since the last MidiEvent.

Pairs of DeltaTime and MidiEvent objects are the basic presentation of temporal data.

The `track` argument must be a :class:`~music21.midi.MidiTrack` object.

Time values are in integers, representing ticks.

The `channel` attribute, inherited from MidiEvent is not used and set to None
unless overridden (it does not do anything if set and is not written out to MIDI).

>>> mt = midi.MidiTrack(1)
>>> dt = midi.DeltaTime(mt)
>>> dt.time = 1
>>> dt
<music21.midi.DeltaTime t=1, track=1>

Changed in v9.7 -- DeltaTime repr no longer lists its channel (to de-emphasize it).
    Channel defaults to 1.
c                0   > [         TU ]  XUS9  SU l        g )N)r   r   r   )superr   r   )r   r   r   r   	__class__s       r'   r   DeltaTime.__init__$  s     	7;	r&   c                r   > [         TU ]  5       nUR                  SS5      nU R                  S:X  a  SU-   nU$ )Nz'DeltaTime',  r   z(empty) )r-  r   replacer   )r   repr.  s     r'   r   DeltaTime._reprInternal-  s:    g#%kk/2.99>s"C
r&   c                D    [        U5      u  U l        nU R                  U4$ )a  
Read a byte-string until hitting a character below 0x80
and return the converted number and the rest of the bytes.

The first number is also stored in `self.time`.

>>> mt = midi.MidiTrack(1)
>>> dt = midi.DeltaTime(mt)
>>> dt.time
0

>>> dt.readUntilLowByte(b'\x20')
(32, b'')
>>> dt.time
32

>>> dt.readUntilLowByte(b'\x20hello')
(32, b'hello')

here the '\x82' is above 0x80 so the 'h' is read
as part of the continuation.

>>> dt.readUntilLowByte(b'\x82hello')
(360, b'ello')

Changed in v9: had an incompatible signature with MidiEvent
)r   r   )r   oldBytesnewBytess      r'   readUntilLowByteDeltaTime.readUntilLowByte4  s$    8 6h?	8yy(""r&   c                0    [        U R                  5      nU$ )a*  
Convert the time integer into a set of bytes.

>>> mt = midi.MidiTrack(1)
>>> dt = midi.DeltaTime(mt)
>>> dt.time = 1
>>> dt.getBytes()
b'\x01'

>>> dt.time = 128
>>> dt.getBytes()
b'\x81\x00'

>>> dt.time = 257
>>> dt.getBytes()
b'\x82\x01'

>>> dt.time = 16385
>>> dt.getBytes()
b'\x81\x80\x01'
)r   r   )r   rO   s     r'   r  DeltaTime.getBytesS  s    , ,DII6	r&   )r   r   )Nr   rM   )r   r   r   r@   r   r@   r$  )r6  r4   r#  tuple[int, bytes]r'  )r!   r"   r#   r$   rj   r   r   r8  r  r%   __classcell__)r.  s   @r'   r   r     sM    0 !%	     	   #> r&   c                      \ rS rSrSrSrSSS jjrSS jr\SS j5       r	SS jr
SSS jjrSS	 jrS
 rSS jrSS jrSS jrSS jrSS jrSrg)r   im  a  
A MIDI Track. Each track contains an index and a list of events.

All events are stored in the `events` list, in order.

An `index` is an integer identifier for this object.  It is often called
"trackId" though technically the id for a MidiTrack is always b'MTrk'

>>> mt = midi.MidiTrack(index=3)
>>> mt.events
[]
>>> mt.index
3

The data consists of all the midi data after b'MTrk'

>>> mt.data
b''

And the .length is the same as the data's length

>>> mt.length
0

After reading a string

>>> mt.read(b'MTrk\x00\x00\x00\x16\x00\xff\x03\x00\x00'
...         + b'\xe0\x00@\x00\x90CZ\x88\x00\x80C\x00\x88\x00\xff/\x00')
b''

The returned value is what is left over after the track is read
(for instance the data for another track)

>>> mt.length
22

New in v9.7: len(mt) returns the same as mt.length, but more Pythonic.

>>> len(mt)
22

>>> mt.data[:8]
b'\x00\xff\x03\x00\x00\xe0\x00@'

Note that the '\x16' got translated to ascii '@'.

>>> mt.events
[<music21.midi.DeltaTime (empty) track=3>,
 <music21.midi.MidiEvent SEQUENCE_TRACK_NAME, track=3, data=b''>,
 <music21.midi.DeltaTime (empty) track=3>,
 <music21.midi.MidiEvent PITCH_BEND, track=3, channel=1, parameter1=0, parameter2=64>,
 <music21.midi.DeltaTime (empty) track=3>,
 <music21.midi.MidiEvent NOTE_ON, track=3, channel=1, pitch=67, velocity=90>,
 <music21.midi.DeltaTime t=1024, track=3>,
 <music21.midi.MidiEvent NOTE_OFF, track=3, channel=1, pitch=67, velocity=0>,
 <music21.midi.DeltaTime t=1024, track=3>,
 <music21.midi.MidiEvent END_OF_TRACK, track=3, data=b''>]

>>> mt
<music21.midi.MidiTrack 3 -- 10 events>

There is a class attribute of the headerId which is the same for
all MidiTrack objects

>>> midi.MidiTrack.headerId
b'MTrk'
s   MTrkc                ,    Xl         / U l        SU l        g )Nr&   )r   eventsr   )r   r   s     r'   r   MidiTrack.__init__  s    
')	r&   c                ,    [        U R                  5      $ )z
New in v9.7
r/   r   r   s    r'   __len__MidiTrack.__len__  s     499~r&   c                ,    [        U R                  5      $ r7   rC  r   s    r'   r:   MidiTrack.length  s    499~r&   c                    USS U R                   :X  d  [        S5      e[        USS S5      u  p!USU nX0l        XS nU R	                  U5        U$ )a  
Read as much of the bytes object (representing midi data) as necessary;
return the remaining bytes object for reassignment and further processing.

The string should begin with `MTrk`, specifying a Midi Track

Stores the read data (after the header and length information) in self.data

Calls `processDataToEvents` which creates
:class:`~music21.midi.DeltaTime`
and :class:`~music21.midi.MidiEvent` objects and stores them in self.events
Nr   z.badly formed midi string: missing leading MTrk)headerIdr   r   r   processDataToEvents)r   rO   r:   	trackData	remainders        r'   r   MidiTrack.read  sh     !}- PQQ%imQ7 gv&		g&	  +r&   c                f   SnSnU(       a  [        U S9nUR                  U5      u  pVX%-   n[        U S9nUb  UR                  Ul         UR	                  U5      nUnU R                  R                  U5        U R                  R                  U5        UnU(       a  M  gg! [
         a    Un M  f = f)z5
Populate .events with trackData.  Called by .read()
r   N)r   )r   r8  r   r   r   r   r@  rR   )	r   rK  r   previousMidiEventdelta_tdttrackDataCandidatetimeCandidate	midiEvents	            r'   rJ  MidiTrack.processDataToEvents  s     ,0 d+G%,%=%=i%H"B IM "-I ,+<+K+K	(%NN+=>	$ KKw'KKy) )7 i" !  /	s   
B   B0/B0c           	     @   / nU R                    H#  n UR                  UR                  5       5        M%     SR                  U5      nU R                  [        [        U5      S5      -   U-   $ ! [         a'  n[        R                  SU SU S35         SnAM  SnAff = f)az  
Returns bytes of midi-data from the `.events` in the object.
For conversion from music21 to MIDI.

For example: two events, one note-on and one note-off on C4 which appears as "<"
in the data.

>>> mt = midi.MidiTrack(index=2)
>>> dt1 = midi.DeltaTime(mt, time=0)
>>> noteOn = midi.MidiEvent(mt, type=midi.ChannelVoiceMessages.NOTE_ON, channel=3)
>>> noteOn.pitch = 60
>>> noteOn.velocity = 20
>>> dt2 = midi.DeltaTime(mt, time=1030)
>>> noteOff = midi.MidiEvent(mt, type=midi.ChannelVoiceMessages.NOTE_OFF, channel=3)
>>> noteOff.pitch = 60
>>> noteOff.velocity = 0

>>> mt.events = [dt1, noteOn, dt2, noteOff]
>>> bytes = mt.getBytes()
>>> bytes
b'MTrk\x00\x00\x00\t\x00\x92<\x14\x88\x06\x82<\x00'

Explanation:

The first four bytes `MTrk` are the header for any MIDI Track

>>> bytes[:4]
b'MTrk'

The next four bytes are the length of the data in bytes, the final `b'\t'`
indicates there are 9 bytes to follow.

>>> midi.base.getNumber(bytes[4:8], 4)
(9, b'')

The next byte is an empty delta time event.

>>> bytes[8]
0

The next three bytes are the note-on event.

>>> noteOn2 = midi.MidiEvent()
>>> _ = noteOn2.parseChannelVoiceMessage(bytes[9:12])
>>> noteOn2
<music21.midi.MidiEvent NOTE_ON, track=None, channel=3, pitch=60, velocity=20>

Followed by two bytes for the DeltaTime of 1030 ticks.

>>> dt3 = midi.DeltaTime()
>>> dt3.readUntilLowByte(bytes[12:14])
(1030, b'')

The 1030 is stored as b'\x88\x06' where the first byte is 136 and the second 6,
but MIDI stores each continuing digit as the last 7 bits of a 8-bit number with
first bit 1, so we remove the first bit by subtracting 128: 136 - 128 = 8.
Then we multiply 8 by 128 to get 1024 and add 6 to get 1030.

Finally, the last three bytes are the note-off event.

>>> noteOff2 = midi.MidiEvent()
>>> _ = noteOff2.parseChannelVoiceMessage(bytes[14:])
>>> noteOff2
<music21.midi.MidiEvent NOTE_OFF, track=None, channel=3, pitch=60, velocity=0>
zConversion error for z: z
; ignored.Nr&   r   )
r@  rR   r  r   r   warnjoinrI  r   r/   )r   rO   rT  ex	bytes_outs        r'   r  MidiTrack.getBytes  s    J "$	IW  !3!3!56 % HHY'	}}yY;;iGG	 ! W!!$9)Brd*"UVVWs   A,,
B6BBc                P    U R                    S[        U R                  5       S3nU$ )Nz -- z events)r   r/   r@  )r   r   s     r'   r   MidiTrack._reprInternalU  s'    zzl$s4;;/08r&   c                6    U R                    H	  nXl        M     g)a5  
We may attach events to this track before setting their `track` parameter.
This method will move through all events and set their track to this track.

>>> mt = midi.MidiTrack(index=2)
>>> noteOn = midi.MidiEvent(type=midi.ChannelVoiceMessages.NOTE_ON, channel=1)
>>> noteOn.pitch = 60
>>> noteOn.velocity = 20
>>> noteOn
<music21.midi.MidiEvent NOTE_ON, track=None, channel=1, pitch=60, velocity=20>

>>> mt.events = [noteOn]
>>> mt.updateEvents()
>>> noteOn
<music21.midi.MidiEvent NOTE_ON, track=2, channel=1, pitch=60, velocity=20>
>>> noteOn.track is mt
True
N)r@  r   r   es     r'   updateEventsMidiTrack.updateEventsZ  s    & AG r&   c                X    U R                    H  nUR                  5       (       d  M    g   g)z
Return True/False if this track has any note-ons defined.

>>> mt = midi.MidiTrack(index=2)
>>> mt.hasNotes()
False

>>> noteOn = midi.MidiEvent(type=midi.ChannelVoiceMessages.NOTE_ON, channel=1)
>>> mt.events = [noteOn]

>>> mt.hasNotes()
True
TF)r@  r  r_  s     r'   hasNotesMidiTrack.hasNotesp  s%     Azz||  r&   c                r    U[        SS5      ;  a  [        SU 35      eU R                   H	  nXl        M     g)a  
Set the one-indexed channel of all events in this Track.

>>> mt = midi.MidiTrack(index=2)
>>> noteOn = midi.MidiEvent(type=midi.ChannelVoiceMessages.NOTE_ON, channel=1)
>>> mt.events = [noteOn]
>>> mt.setChannel(11)
>>> noteOn.channel
11

Channel must be a value from 1-16

>>> mt.setChannel(22)
Traceback (most recent call last):
music21.midi.base.MidiException: bad channel value: 22
rM      zbad channel value: N)rA   r   r@  r   )r   r   r`  s      r'   
setChannelMidiTrack.setChannel  s8    " a$"5eW =>>AI r&   c                    [        5       nU R                   H-  nUR                  c  M  UR                  UR                  5        M/     [	        U5      $ )a  
Get all channels (excluding None) used in this Track (sorted)

>>> mt = midi.MidiTrack(index=2)
>>> noteOn = midi.MidiEvent(type=midi.ChannelVoiceMessages.NOTE_ON, channel=14)
>>> noteOn2 = midi.MidiEvent(type=midi.ChannelVoiceMessages.NOTE_ON, channel=5)
>>> noteOn3 = midi.MidiEvent(type=midi.ChannelVoiceMessages.NOTE_ON, channel=14)
>>> noteOn4 = midi.MidiEvent(type=midi.ChannelVoiceMessages.PROGRAM_CHANGE, channel=None)

>>> mt.events = [noteOn, noteOn2, noteOn3, noteOn4]

>>> mt.getChannels()
[5, 14]
)setr@  r   addsortedr   rS   r`  s      r'   getChannelsMidiTrack.getChannels  s?     Ayy$#  d|r&   c                   / nU R                    Hq  nUR                  [        R                  :X  d  M#  [	        UR
                  [        5      (       d  MD  UR
                  U;  d  MV  UR                  UR
                  5        Ms     U$ )a  
Get all unique program changes used in this Track, in order they appear.

>>> mt = midi.MidiTrack(index=2)
>>> pc1 = midi.MidiEvent(type=midi.ChannelVoiceMessages.PROGRAM_CHANGE)
>>> pc1.data = 14
>>> noteOn = midi.MidiEvent(type=midi.ChannelVoiceMessages.NOTE_ON, channel=14)
>>> pc2 = midi.MidiEvent(type=midi.ChannelVoiceMessages.PROGRAM_CHANGE)
>>> pc2.data = 1

>>> mt.events = [pc1, noteOn, pc2]
>>> mt.getProgramChanges()
[14, 1]
)r@  r   r
   ro   r?   r   r@   rR   rn  s      r'   getProgramChangesMidiTrack.getProgramChanges  s^     A.==="1663//d*AFF#	 
 r&   )r   r@  r   N)r   )r   r@   r"  r&  )r&   )rK  r4   r#  r   r'  r#  r   r(  )r   r@   r#  r   )r#  	list[int])r!   r"   r#   r$   rj   rI  r   rD  r)  r:   r   rJ  r  r   ra  rd  rh  ro  rr  r%   r    r&   r'   r   r   m  s_    BF H
  6&*PNH`
,&,*r&   r   c                      \ rS rSrSrSrSS jrSSS jjrSS jrSS jr	SS jr
SS	 jrSS
 jrSS jrSS jrSS jrSrg)r   i  a  
Low-level MIDI file writing, emulating methods from normal Python files.

For most users, do not go here, simply use:

    score = converter.parse('path/to/file/in.mid')
    midi_out = score.write('midi', fp='path/to/file/out.mid')

The `ticksPerQuarterNote` attribute must be set before writing. 1024 is a common value.

This object is returned by some properties for directly writing files of midi representations.

>>> mf = midi.MidiFile()
>>> mf
<music21.midi.MidiFile 0 tracks>

Music21 can read format 0 and format 1, and writes format 1.  Format 2 files
are not parsable.

>>> mf.format
1

After loading or before writing, tracks are stored in this list.

>>> mf.tracks
[]

Most midi files store `ticksPerQuarterNote` and not `ticksPerSecond`

>>> mf.ticksPerQuarterNote
10080
>>> mf.ticksPerSecond is None
True

All MidiFiles have the same `headerId`

>>> midi.MidiFile.headerId
b'MThd'
   MThdc                f    S U l         SU l        / U l        [        R                  U l        S U l        g )NrM   )fileformattracksr   ticksPerQuarterticksPerQuarterNoteticksPerSecondr   s    r'   r   MidiFile.__init__  s-    %)	')(0(@(@ (,r&   c                    US;  a  [        SU5      e[        R                  " [        R                  [	        X5      5      U l        g)ze
Open a MIDI file path for reading or writing.

For writing to a MIDI file, `attrib` should be "wb".
)rbwbz0cannot read or write unless in binary mode, not:N)r   rB   r  BinaryIOopenry  )r   filenamer   s      r'   r  MidiFile.open  s6     % RTZ[[FF1::tH'=>	r&   c                    Xl         g)z
Assign a file-like object, such as those provided by BytesIO, as an open file object.

>>> from io import BytesIO
>>> fileLikeOpen = BytesIO()
>>> mf = midi.MidiFile()
>>> mf.openFileLike(fileLikeOpen)
>>> mf.close()
N)ry  )r   fileLikes     r'   openFileLikeMidiFile.openFileLike  s	     	r&   c                N    [        U R                  5      nUS:w  a  SOSnU SU 3$ )NrM   r  r1  z track)r/   r{  )r   	lenTracksplurals      r'   r   MidiFile._reprInternal  s.    $	!QBF6(++r&   c                \    U R                   (       d  gU R                   R                  5         g)z
Close the file.
N)ry  closer   s    r'   r  MidiFile.close  s     yy		r&   c                    U R                   (       d  [        S5      eU R                  U R                   R                  5       5        g)z,
Read and parse MIDI data stored in a file.
No file is open.N)ry  r   readstrr   r   s    r'   r   MidiFile.read  s.     yy.//TYY^^%&r&   c                0   USS S:X  d  [        SUSS < 35      e[        USS S5      u  p!US:w  a  [        S5      e[        US5      u  p1X0l        US	;  a  [        S
[         35      e[        US5      u  pA[        US5      u  pQUS-  (       a4  US-	  S-  * nUS-  nUS;  a  [        SU 35      eUS:X  a  SnXv-  U l        O
US-  U l        [        U5       H:  n[        U5      n	U	R                  U5      nU R                  R                  U	5        M<     g)z
Read and parse MIDI data as a bytes, putting the
data in `.ticksPerQuarterNote` and a list of
`MidiTrack` objects in the attribute `.tracks`.

The name readstr is a carryover from Python 2.
It works on bytes objects, not strings
Nr   rw  z!badly formatted midi bytes, got:    r   zbadly formatted midi bytesr*   )r   rM   z cannot handle midi file format:    r+   irV   )            zcannot handle ticks per frame: r  r  i  )
r   r   rz  r~  r}  rA   r   r   r{  rR   )
r   rO   r:   midiFormatType	numTracksdivisionframesPerSecondticksPerFramerF   trks
             r'   r  MidiFile.readstr&  sB    !}'"CIcrNCU VWW &imQ7Q; <==$-i$;!$'"B6( KLL(A6	'	15 f!)Q% 78O$tOM$44#&Em_$UVV" ""/"AD'/&'8D$ y!AA,C+IKKs# "r&   c                    U R                   (       d  [        S5      eU R                  5       nU R                   R                  U5        g)z>
Write MIDI data as a file to the file opened with `.open()`.
r  N)ry  r   writestrwrite)r   wss     r'   r  MidiFile.writeU  s2     yy.//]]_		r&   c                p    U R                  5       nU R                   H  nXR                  5       -   nM     U$ )z
Generate the MIDI data header and convert the list of
MidiTrack objects in self.tracks into MIDI data and return it as bytes.

The name `writestr` is a carry-over from Python 2.  It works on bytes, not strings.
)writeMThdStrr{  r  )r   rO   r  s      r'   r  MidiFile.writestr_  s4     %%'	;;C!LLN2I r&   c                   U R                   nUS-  S:w  a  [        S5      eU R                  [        SS5      -   [        U R                  S5      -   nU[        [        U R                  5      S5      -   nU[        US5      -   nU$ )z
Convert the information in self.ticksPerQuarterNote
into MIDI data header and return it as bytes.

The name `writeMThdStr` is a carry-over from Python 2.  It works on bytes, not strings.
r  r   zMCannot write midi bytes unless self.ticksPerQuarterNote is a multiple of 1024r   r   r*   )r}  r   rI  r   rz  r/   r{  )r   r  rO   s      r'   r  MidiFile.writeMThdStrk  s     ++v!#_a aMMIaO3iQ6OO		#dkk*:A >>		(A 66	r&   )ry  rz  r}  r~  r{  Nrt  )r  )r  z
t.BinaryIOr#  r   r$  )rO   r4   r#  r   r'  )r!   r"   r#   r$   rj   rI  r   r  r  r   r  r   r  r  r  r  r%   r    r&   r'   r   r     sB    &N H-	?
,
'-$^
r&   r   z
list[type]
_DOC_ORDER__main__)r0   rD   )r5   Iterable[int]r#  r4   )r9   r@   r:   r@   r#  ztuple[int, int])r9   rD   r:   r@   r#  ztuple[int, str])r9   r4   r:   r@   r#  r<  )r9   zstr | bytes | intr:   r@   r#  ztuple[int, str | bytes | int])rO   r4   r#  r<  )rO   zbytes | Iterable[int]r#  ru  )rX   r@   r:   r@   r#  r4   )rP   r@   r#  r4   )rb   r  r#  r4   )/rj   
__future__r   __all__collections.abcr   r  typingr   rB   music21r   music21.common.enumsr   r   r   r   r   Environmentr   Music21Exceptionr   
deprecatedr   r   r   r   r   r   r   r   r
   r   r	   r   r   Literalr!  ProtoM21Objectr   r   r   r   r  __annotations__r!   mainTestr    r&   r'   <module>r     s   # %     -     &&{3
	L11 	 65"?@ A* 65"?@ A$ 
 
 
 
 
 
>#B<?~ 65"?@ A6:bJ,^< ,  6, 
     ii	 E&& EP]	 ]@V&& Vr
tw%% tr $Y	8D
J Dz r&   