
    3jY                      d Z ddlmZ ddlmZ ddlZddlZddlZddl	Z	ddl
mZ ddl
mZ ddlmZ ddl
mZ dd	l
mZ dd
l
mZ ddl
mZ ddl
mZ ddl
mZ ddlmZmZmZ ddl
mZ ddl
mZ ddl
mZ ddl
mZ ddl
mZ ddl
mZ ddl
mZ ddl
m Z  ddl!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z* ddl+m,Z,m-Z- ej\                  rddl
m/Z/ ddl0m1Z1  ejd                  d      Z3 e-       Z4 ejj                  dejl                        Z7 G d dejp                        Z9 G d  d!ejt                        Z; G d" d#e<      Z=dfdgd%Z>dhd&Z?ej                  df	 	 	 	 	 	 	 did'ZA	 	 	 djd)d*	 	 	 	 	 	 	 	 	 dkd+ZB	 dld,d-	 	 	 	 	 dmd.ZCd$d,d)d/	 	 	 	 	 dnd0ZD	 	 	 	 	 	 	 	 	 	 dod1ZEej                  f	 	 	 	 	 dpd2ZFd,d(d)d3	 	 	 	 	 	 	 	 	 dqd4ZGej                  f	 	 	 	 	 drd5ZHd,d(d)d3	 	 	 	 	 	 	 	 	 dsd6ZIdtd7ZJ	 	 	 du	 	 	 	 	 	 	 dvd8ZK ej                  d9d:d;      d)d*	 	 	 	 	 dwd<       ZMd)d*	 	 	 	 	 dxd=ZNd> ZOdydzd?ZPd{d@ZQ	 dy	 	 	 d|dAZRdB ZS	 dy	 	 	 d}dCZT	 	 d~	 	 	 	 	 	 	 	 	 	 	 ddDZU	 d	 	 	 	 	 ddEZV	 	 	 d	 	 	 	 	 	 	 	 	 ddFZW	 	 	 ddGZX	 dl	 	 	 	 	 ddHZY	 	 	 	 	 	 ddIZZdd,d-dJZ[	 	 	 	 ddKZ\	 	 	 	 ddLZ]d)d*	 	 	 	 	 ddMZ^d)d*	 	 	 	 	 ddNZ_d$dO	 	 	 	 	 ddPZ`ej                  d,ddd$dQd)dR	 	 	 	 	 	 	 	 	 	 	 ddSZaddTZbddUZc	 dl	 	 	 	 	 ddVZdd$d)dW	 	 	 	 	 ddXZe	 	 	 	 	 	 ddYZfdd$d,d)dZd[Zgej                  d,dfd)d*	 	 	 	 	 	 	 	 	 dd\Zhd$d,dd)d]	 	 	 	 	 	 	 	 	 	 	 dd^Zidd)d_	 dd`Zj	 	 	 d	 ddaZkdb Zldd,d)dc	 	 	 dddZmeiemgZneodek(  rddl
Z
 e
j                          yy)z
Module to translate MIDI data to music21 Streams and vice versa.  Note that quantization of
notes takes place in the :meth:`~music21.stream.Stream.quantize` method not here.
    )annotations)SequenceN)chord)common)opFrac)defaultsduration)dynamics)exceptions21)environment)
instrument)	ConductorUnpitchedPercussiondeduplicatekey)meter)note)
percussion)pitch)stream)tempo)volume)		MidiTrack	DeltaTimeMidiFile	MidiEventChannelVoiceMessages
MetaEventsputNumbersAsList	getNumber	putNumber)MIDIPercussionExceptionPercussionMapper)base)
OffsetQLInzmidi.translateNotRestType)boundc                  ,    e Zd ZU ded<   ded<   ded<   y)TimedNoteEventintonTimeoffTimer   eventN)__name__
__module____qualname____annotations__     C/DATA/.local/lib/python3.12/site-packages/music21/midi/translate.pyr+   r+   <   s    KLr5   r+   c                      e Zd Zy)TranslateExceptionNr0   r1   r2   r4   r5   r6   r8   r8   B       r5   r8   c                      e Zd Zy)TranslateWarningNr9   r4   r5   r6   r<   r<   F   r:   r5   r<   Fc                z    t        t        | t        j                  z              }|r|t        j                  z  }|S )a  
    Helper function to convert a music21 offset value to MIDI ticks,
    depends on *defaults.ticksPerQuarter* and *defaults.ticksAtStart*.

    Returns an int.

    >>> defaults.ticksPerQuarter
    10080
    >>> defaults.ticksAtStart
    10080

    >>> midi.translate.offsetToMidiTicks(0)
    0
    >>> midi.translate.offsetToMidiTicks(0, addStartDelay=True)
    10080

    >>> midi.translate.offsetToMidiTicks(1)
    10080

    >>> midi.translate.offsetToMidiTicks(20.5)
    206640
    )r,   roundr   ticksPerQuarterticksAtStart)oaddStartDelaytickss      r6   offsetToMidiTicksrD   M   s6    . a(22234E&&&Lr5   c                `    t        t        | j                  t        j                  z              S )aY  
    Converts a :class:`~music21.duration.Duration` object to midi ticks.

    Depends on *defaults.ticksPerQuarter*, Returns an int.
    Does not use defaults.ticksAtStart

    >>> n = note.Note()
    >>> n.duration.type = 'half'
    >>> midi.translate.durationToMidiTicks(n.duration)
    20160

    >>> d = duration.Duration('quarter')
    >>> dReference = midi.translate.ticksToDuration(10080, inputM21DurationObject=d)
    >>> dReference is d
    True
    >>> d.type
    'quarter'
    >>> d.type = '16th'
    >>> d.quarterLength
    0.25
    >>> midi.translate.durationToMidiTicks(d)
    2520
    )r,   r>   quarterLengthr   r?   )ds    r6   durationToMidiTicksrH   j   s#    2 uQ__x'?'??@AAr5   c                ^    |t        j                         }n|}t        | |z        |_        |S )a  
    Converts a number of MIDI Ticks to a music21 duration.Duration() object.

    Optional parameters include ticksPerQuarter -- in case something other
    than the default.ticksPerQuarter (10080) is used in this file.  And
    it can take a :class:`~music21.duration.Duration` object to modify, specified
    as *inputM21DurationObject*

    >>> d = midi.translate.ticksToDuration(10080)
    >>> d
    <music21.duration.Duration 1.0>
    >>> d.type
    'quarter'

    >>> n = note.Note()
    >>> midi.translate.ticksToDuration(30240, inputM21DurationObject=n.duration)
    <music21.duration.Duration 3.0>
    >>> n.duration.type
    'half'
    >>> n.duration.dots
    1

    More complex rhythms can also be set automatically:

    >>> d2 = duration.Duration()
    >>> d2reference = midi.translate.ticksToDuration(23625, inputM21DurationObject=d2)
    >>> d2 is d2reference
    True
    >>> d2.quarterLength
    2.34375
    >>> d2.type
    'complex'
    >>> d2.components
    (DurationTuple(type='half', dots=0, quarterLength=2.0),
     DurationTuple(type='16th', dots=0, quarterLength=0.25),
     DurationTuple(type='64th', dots=1, quarterLength=0.09375))
    >>> d2.components[2].type
    '64th'
    >>> d2.components[2].dots
    1

    )r
   Durationr   rF   )rC   r?   inputM21DurationObjectrG   s       r6   ticksToDurationrL      s6    ` %" U_45AOHr5      utf-8encodingc               t   g }t        |t              r|S ||j                         x}d}n|}t        | |      }|j	                  |       t        | |      }t        j                  |_        |j                  |d      |_
        |j	                  |       | |j                  t        |d| |      }	||	z  }|S )a  
    Returns a list of midi.MidiEvent objects found at the beginning of a track.

    A MidiTrack reference can be provided via the `mt` parameter.

    >>> startEvents = midi.translate.getStartEvents()
    >>> startEvents
    [<music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent SEQUENCE_TRACK_NAME, track=None, data=b''>]

    (Music21 DeltaTime events get assigned to the given channel, but this is not written out)

    >>> startEvents[0].channel
    1

    >>> mt = midi.MidiTrack(3)
    >>> midi.translate.getStartEvents(mt, channel=2, instrumentObj=instrument.Harpsichord())
    [<music21.midi.DeltaTime (empty) track=3>,
     <music21.midi.MidiEvent SEQUENCE_TRACK_NAME, track=3, data=b'Harpsichord'>,
     <music21.midi.DeltaTime (empty) track=3>,
     <music21.midi.MidiEvent PROGRAM_CHANGE, track=3, channel=2, data=6>]

    Bug fixed in v9.6 -- the program change and delta time are written to the given track.
     channelignoreT)includeDeltaTime	midiTrackrT   )
isinstancer   bestNamer   appendr   r    SEQUENCE_TRACK_NAMEtypeencodedatamidiPrograminstrumentToMidiEvents)
rW   rT   instrumentObjrP   eventsrY   partNamedtmesubs
             r6   getStartEventsrg      s    > )+F-+		}/E/E/G#G8"P	9g	.B
MM"	9g	.B,,BGooh1BG
MM"  ]%>%>%J$]6:/8-46 	#Mr5   TaddEndDelayc                   g }t        |       }|rt        j                  nd|_        |j	                  |       t        | t        j                        }d|_        |j	                  |       |S )a  
    Returns a list of midi.MidiEvent objects found at the end of a track.

    >>> midi.translate.getEndEvents()
    [<music21.midi.DeltaTime t=10080, track=None>,
     <music21.midi.MidiEvent END_OF_TRACK, track=None, data=b''>]

    Set `addEndDelay` to False to omit the trailing rest before END_OF_TRACK:

    >>> midi.translate.getEndEvents(addEndDelay=False)
    [<music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent END_OF_TRACK, track=None, data=b''>]

    * Changed in v10: getEndEvents does not take a channel.
    * New in v10.3: addEndDelay keyword.

    Note: the addEndDelay keyword and its threading through the MIDI export
    functions was AI-assisted (issue #1141).
    trackr   rl   r\   r5   )	r   r   r@   timerZ   r   r    END_OF_TRACKr^   )rW   ri   rb   rd   re   s        r6   getEndEventsrp     s`    0 )+F		#B'2h##BG
MM"	$$
B BG
MM"Mr5   rB   ri   rP   c               h   t        | t        j                        rO| j                  du r| j	                         } t        t        j                  t        j                  |       |||      S t        j                  |       }t        j                         }|j                  d|       t        ||||      S )z
    Either calls streamToMidiFile on the music21Object or
    puts a copy of that object into a Stream (so as
    not to change activeSites, etc.) and calls streamToMidiFile on
    that object.

    * New in v10.3: addEndDelay keyword.
    Frq   r   )rX   r   StreamatSoundingPitchtoSoundingPitchstreamToMidiFiletcastcopydeepcopyinsert)music21ObjectrB   ri   rP   m21ObjectCopyss         r6   music21ObjectToMidiFiler   ,  s     -/((E1)99;Mv}}m D.;,7)13 	3
 m4!==?	M",7)13 	3r5   c                   t        |t        j                        st        d|       || z
  dk7  r |t	        || z
  |            }|S  |       }|j                  d       |S )aP  
    Construct (or edit the duration of) a NotRest subclass, usually
    a note.Note (or a chord.Chord if provided to `returnClass`).

    * Changed in v8: no inputM21.
    * Changed in v10: Remove part about creating an Unpitched object -- that has been wrong
      for some time (probably since PercussionChords were introduced).
    z'Expected subclass of note.NotRest; got r   )r?   r	   TinPlace)
issubclassr   NotRest	TypeErrorrL   getGrace)tOntOffr?   returnClassnrs        r6   !_constructOrUpdateNotRestSubclassr   O  sr     k4<<0A+OPP 	s
q/$*BQ#S T I ]
D!Ir5   c                   | \  }}}|j                   dk(  rt        j                  }nt        j                  }t	        ||||      }t        |t        j                        r|j                  |j                  _        nPt        |t        j                        r(	 t        j                  |j                        }||_        nt        d|       |j                  |j                   _        d|j                   _        t%        j&                  t        j                  t        j                  z  |      S # t        $ r t        j                         }Y w xY w)a[  
    Convert a TimedNoteEvent to a music21.note.Note or a music21.note.Unpitched.
    A timed note event is a tuple of (onTime, offTime, MidiEvent) where the
    MidiEvent is the Note On.  (The Note Off event is not used).

    This method is called as part of the midiToStream() conversion.

    In this example, we start a NOTE_ON event at offset 1.0 (at the standard 10080 to quarter)

    >>> mt = midi.MidiTrack(1)
    >>> dt1 = midi.DeltaTime(mt)
    >>> dt1.time = 10080

    >>> me1 = midi.MidiEvent(mt)
    >>> me1.type = midi.ChannelVoiceMessages.NOTE_ON
    >>> me1.pitch = 45
    >>> me1.velocity = 94

    This lasts until we send a NOTE_OFF event at offset 2.0.

    >>> dt2 = midi.DeltaTime(mt)
    >>> dt2.time = 20160
    >>> me2 = midi.MidiEvent(mt)
    >>> me2.type = midi.ChannelVoiceMessages.NOTE_ON
    >>> me2.pitch = 45
    >>> me2.velocity = 0

    Another system will package dt1, dt2 and me1 into a TimedNoteEvent tuple.
    In this example, me2 is not used.

    >>> tne1 = midi.translate.TimedNoteEvent(dt1.time, dt2.time, me1)
    >>> n = midi.translate.midiEventsToNote(tne1)
    >>> n.pitch
    <music21.pitch.Pitch A2>
    >>> n.duration.quarterLength
    1.0
    >>> n.volume.velocity
    94

    If the channel is 10, an Unpitched element is returned.

    >>> me1.channel = 10
    >>> unp = midi.translate.midiEventsToNote(tne1)
    >>> unp
    <music21.note.Unpitched 'Tom-Tom'>

    Access the `storedInstrument`:

    >>> unp.storedInstrument
    <music21.instrument.TomTom 'Tom-Tom'>

    And with values that cannot be translated, a generic
    :class:`~music21.instrument.UnpitchedPercussion` instance is given:

    >>> me1.pitch = 1
    >>> unp = midi.translate.midiEventsToNote(tne1)
    >>> unp.storedInstrument
    <music21.instrument.UnpitchedPercussion 'Percussion'>

    * Changed in v7.3: Returns None if `inputM21` is provided. Returns a
        :class:`~music21.note.Unpitched` instance if the event is on Channel 10.
    * Changed in v8: `inputM21` is no longer supported.
        The only supported usage now is two tuples.
    * Changed in v9.7: Expects a single TimedNoteEvent.
    
   r   z>Got something other than a Note or Unpitched from conversion: F)rT   r   	UnpitchedNoter   rX   r   midiPERCUSSION_MAPPERmidiPitchToInstrumentr$   r   r   storedInstrumentr8   velocityr   velocityIsRelativerw   rx   )timedNoteEventr?   r   r   midiOnEventr   r   is           r6   midiEventsToNoter   m  s   L ,C{ b nnii	*	
B "dii #))	B	'	1!778I8IJA   !LRDQ
 	
 %--BII#(BII 66$))DNN*B// ' 	1..0A	1s   D- -EErV   rT   rP   c                  | }d}g }| j                   | j                   dk7  rs|rt        ||      }|j                  |       t        |      }t        j
                  |_        | j                   j                  |d      |_        |j                  |       |rt        |      }|j                  |       t        |      }	t        j                  |	_        ||	_        t        |t        j                        rt        |      |	_        nT|j                   j"                  |	_        |j                   j%                         s|j                   j'                         |	_        t+        t-        |j.                  j0                  dz              |	_        |j                  |	       |r8t        ||      }t5        |j6                        |_        |j                  |       t        |      }
t        j:                  |
_        ||
_        |	j                   |
_        |	j(                  |
_        d|
_        |j                  |
       |
|	_        |	|
_        |S )a  
    Translate a music21 Note to a list of four MIDI events --
    the DeltaTime for the start of the note (0), the NOTE_ON event, the
    DeltaTime to the end of the note, and the NOTE_OFF event.

    If `includeDeltaTime` is not True then the DeltaTime events
    aren't returned, thus only two events are returned.

    The initial deltaTime object is always 0.  It will be changed when
    processing Notes from a Stream.

    The `channel` can be specified, otherwise channel 1 is assumed.

    >>> n1 = note.Note('C#4')
    >>> eventList = midi.translate.noteToMidiEvents(n1)
    >>> eventList
    [<music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent NOTE_ON, track=None, channel=1, pitch=61, velocity=90>,
     <music21.midi.DeltaTime t=10080, track=None>,
     <music21.midi.MidiEvent NOTE_OFF, track=None, channel=1, pitch=61, velocity=0>]

    >>> n1.duration.quarterLength = 2.5
    >>> eventList = midi.translate.noteToMidiEvents(n1)
    >>> eventList
    [<music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent NOTE_ON, track=None, channel=1, pitch=61, velocity=90>,
     <music21.midi.DeltaTime t=25200, track=None>,
     <music21.midi.MidiEvent NOTE_OFF, track=None, channel=1, pitch=61, velocity=0>]

    Omitting DeltaTimes:

    >>> eventList2 = midi.translate.noteToMidiEvents(n1, includeDeltaTime=False, channel=9)
    >>> eventList2
    [<music21.midi.MidiEvent NOTE_ON, track=None, channel=9, pitch=61, velocity=90>,
     <music21.midi.MidiEvent NOTE_OFF, track=None, channel=9, pitch=61, velocity=0>]

    * Changed in v7: made keyword-only.
    * Changed in v8: added support for :class:`~music21.note.Unpitched`.
    NrR   rS   rk   rU      r   )lyricr   rZ   r   r    LYRICr\   r]   r^   r   NOTE_ONrT   rX   r   r   _get_unpitched_pitch_valuer   r   isTwelveTonegetCentShiftFromMidi	centShiftr,   r>   r   cachedRealizedr   rH   r
   rn   NOTE_OFFcorrespondingEvent)inputM21rV   rT   rP   nmt	eventListrd   re   me1me2s              r6   noteToMidiEventsr     s   ^ 	A	B+-I"x~~';2w/BR R ""..''(;R 
"
C#++CHCK!T^^$.q1	GGLL	ww##%GG88:CM uQXX44s:;<CLSr7+%ajj1
"
C#,,CHCK		CIMMCMCLS !C Cr5   c                   | d   d   }| d   d   }g }g }d}| D ]  \  }}}	|	j                   dk(  rd}t        j                         }
|	j                  |
_        |j	                  |
       t        j                  |	j                        }d|_        |j	                  |        |rt        j                  }nt        j                  }t        ||||      }t        |t        j                        rJ|D ]D  }t        j                          }	 t"        j%                  |      }||_        |j/                  |       F nt1        |      |_        |j5                  |       |S # t&        $ r t)        j*                         }Y ]w xY w)	aR  
    Creates a Chord from a list of TimedNoteEvents which
    store the noteOn tick, noteOff tick, and Note-On MidiEvent for each note.

    Timings of all objects except the first (for the first note on)
    and last (for the last note off) are ignored.

    >>> mt = midi.MidiTrack(1)

    >>> dt1 = midi.DeltaTime(mt)
    >>> me1 = midi.MidiEvent(mt)
    >>> me1.type = midi.ChannelVoiceMessages.NOTE_ON
    >>> me1.pitch = 45
    >>> me1.velocity = 94

    Note that only the times of the first NOTE_ON and last NOTE_OFF matter, so
    we don't even bother setting the time of dt3 and dt4.

    >>> dt3 = midi.DeltaTime(mt)
    >>> me3 = midi.MidiEvent(mt)
    >>> me3.type = midi.ChannelVoiceMessages.NOTE_OFF

    The pitches of the NOTE_OFF events are not checked by this function.  They
    are assumed to have been aligned by the previous parser.

    >>> me3.pitch = 45
    >>> me3.velocity = 0

    >>> dt2 = midi.DeltaTime(mt)
    >>> me2 = midi.MidiEvent(mt)
    >>> me2.type = midi.ChannelVoiceMessages.NOTE_ON
    >>> me2.pitch = 46
    >>> me2.velocity = 94

    >>> dt4 = midi.DeltaTime(mt)
    >>> dt4.time = 20160

    >>> me4 = midi.MidiEvent(mt)
    >>> me4.type = midi.ChannelVoiceMessages.NOTE_OFF
    >>> me4.pitch = 46
    >>> me4.velocity = 0

    >>> tne1 = midi.translate.TimedNoteEvent(dt1.time, dt3.time, me1)
    >>> tne2 = midi.translate.TimedNoteEvent(dt2.time, dt4.time, me2)

    >>> c = midi.translate.midiEventsToChord([tne1, tne2])
    >>> c
    <music21.chord.Chord A2 B-2>
    >>> c.duration.quarterLength
    2.0

    If the channel of the last element is set to 10, then a PercussionChord is returned:

    >>> me2.channel = 10
    >>> midi.translate.midiEventsToChord([tne1, tne2])
    <music21.percussion.PercussionChord [Tom-Tom Hi-Hat Cymbal]>

    * Changed in v7: Uses the last DeltaTime in the list to get the end time.
    * Changed in v7.3: Returns a :class:`~music21.percussion.PercussionChord` if
      any event is on channel 10.
    * Changed in v8: inputM21 is no longer supported.  Flat list format is removed.
    * Changed in v9.7: expects a list of TimedNoteEvents.
    r   rM   Fr   T)r   r   )rT   r   Pitchr   rZ   r   Volumer   r   r   PercussionChordr   Chordr   rX   r   r   r   r   r$   r   r   r   addtuplepitches
setVolumes)timedNoteListr?   	first_tOn	last_tOffr   volumesany_channel_10_tOn_tOffr   pvr   c
midi_pitchunpr   s                    r6   midiEventsToChordr   D  sb   P #2&q)I"2&q)I!#G#%GN %2 e["$!NKKM""qMM;#7#78$q %2  00kk)		A !Z//0!J.."C5%;;JG $%C EE#J " 'N	LLH + 52245s   EE:9E:c                  d}g }| }g }g }|j                   }	|j                         }
| j                  | j                  dk7  rr|rt        |      }|j	                  |       t        |      }t        j                  |_        | j                  j                  |d      |_
        |j	                  |       t        |      D ]U  \  }}|rt        |      }|j	                  |       t        |      }t        j                  |_        d|_        t        |t         j"                        rU|j$                  j&                  |_        |j$                  j)                         sV|j$                  j+                         |_        n6t        |t         j.                        rt1        |      |_        nt3        d      |
r|j                   j4                  }n|	j4                  }t7        t9        |dz              |_        |j	                  |       |j	                  |       X t        |      D ]  \  }}|r<t        |      }|dk(  rt=        |j>                        |_         |j	                  |       t        |      }t        jB                  |_        ||_        |j$                  |_        |j,                  |_        d|_        |j	                  |       |j	                  |        t        |      D ]  \  }}||   }||_"        ||_"         |S )	aj  
    Translates a :class:`~music21.chord.Chord` object to a
    list of base.DeltaTime and base.MidiEvents objects.

    The `channel` can be specified, otherwise channel 1 is assumed.

    See noteToMidiEvents above for more details.

    >>> c = chord.Chord(['c3', 'g#4', 'b5'])
    >>> c.volume = volume.Volume(velocity=90)
    >>> c.volume.velocityIsRelative = False
    >>> eventList = midi.translate.chordToMidiEvents(c)
    >>> eventList
    [<music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent NOTE_ON, track=None, channel=1, pitch=48, velocity=90>,
     <music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent NOTE_ON, track=None, channel=1, pitch=68, velocity=90>,
     <music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent NOTE_ON, track=None, channel=1, pitch=83, velocity=90>,
     <music21.midi.DeltaTime t=10080, track=None>,
     <music21.midi.MidiEvent NOTE_OFF, track=None, channel=1, pitch=48, velocity=0>,
     <music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent NOTE_OFF, track=None, channel=1, pitch=68, velocity=0>,
     <music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent NOTE_OFF, track=None, channel=1, pitch=83, velocity=0>]

    * Changed in v7: made keyword-only.
    * Changed in v8: added support for :class:`~music21.percussion.PercussionChord`.
    NrR   rk   rU   rM   z8ChordBase can only contain Note and Unpitched as membersr   r   )#r   hasComponentVolumesr   r   rZ   r   r    r   r\   r]   r^   	enumerater   r   rT   rX   r   r   r   r   r   r   r   r   r   r   r   r,   r>   r   rH   r
   rn   r   r   )r   rV   rT   rP   r   r   r   noteOnnoteOffchordVolumer   rd   re   r   chordComponent	volScalarnoteOnEventmeOnmeOffs                      r6   chordToMidiEventsr     s   J 
B+-IA !F!G((K//1"x~~';$BR R ""..''(;&q\> $B
 R R &..
ndii0%++00BH!''446-33HHJ71.ABHVWW  '--<<I
 $22I%	C01bM *R $F+;$BAv-ajj9R R &//
$$",,r! ,& V$4
"'#'  %
 r5   c                D   t        | j                  t        j                        r| j                  }nU| j                  *| j                  j                  t        j                        }n| j                  t        j                        }||j                  |j                  S y)N<   )rX   r   r   r   _chordAttachedgetContextByClasspercMapPitch)r   unpitched_instruments     r6   r   r   ;  s    #&&
(F(FG"33)#&#5#5#G#G..$0  $'#8#89W9W#X ',@,M,M,Y#000r5   c                   | }|}g }t        |t              r|S |rt        ||      }|j                  |       t	        |      }t
        j                  |_        ||_        |j                  }	|	d}	|	|_
        |j                  |       |S )zu
    Converts a :class:`~music21.instrument.Instrument` object to a list of MidiEvents

    TODO: DOCS and TESTS
    )rl   rT   rk   r   )rX   r   r   rZ   r   r   PROGRAM_CHANGEr\   rT   r_   r^   )
r   rV   rW   rT   instr   rb   rd   re   instMidiPrograms
             r6   r`   r`   K  s     D	B(*F$	"R1b		B"11BGBJ&&OBG
MM"Mr5   v10v11z@passing a list was never used; use midiEventToInstrument insteadc                   t        j                  |       st        j                  t        |       }n| d   }t        ||      S )NrM   rO   )r   
isListLikerw   rx   r   midiEventToInstrument)r   rP   r/   s      r6   midiEventsToInstrumentr   m  s8     Y'y),! ::r5   c                  d}	 t        | j                  t              rS| j                  j                  |      j	                  d      d   }|j                         }t        j                  |      }n| j                  dk(  r@t        | j                  t              r&t        j                         }| j                  |_        nct        | j                  t              r1t        j                  | j                        }| j                  |_        nt        j                  d|        | j                  d
z
  |_        |r|j)                         dv s\|j)                         j+                  dd      j-                         s.|j)                         j+                  dd      j-                         r|S | j.                  t0        j2                  k(  r	||_        |S | j.                  t0        j6                  k(  r||_        |S # t        $ r8 t        j                   d|  dt"        d	       t        j$                         }Y t        j                  $ r t        j$                         }Y ;w xY w)up  
    Convert a single MIDI event into a music21 Instrument object.

    MIDI Events that can be properly read are PROGRAM_CHANGE, INSTRUMENT_NAME
    and SEQUENCE_TRACK_NAME

    >>> me = midi.MidiEvent(channel=2)
    >>> me.type = midi.ChannelVoiceMessages.PROGRAM_CHANGE
    >>> me.data = 53  # MIDI program 54: Voice Oohs
    >>> midi.translate.midiEventToInstrument(me)
    <music21.instrument.Vocalist 'Voice'>

    The percussion map will be used if the channel is 10:

    >>> me.channel = 10
    >>> instrumentObj = midi.translate.midiEventToInstrument(me)
    >>> instrumentObj
    <music21.instrument.UnpitchedPercussion 'Percussion'>
    >>> instrumentObj.midiChannel  # 0-indexed in music21
    9
    >>> instrumentObj.midiProgram  # 0-indexed in music21
    53

    Get from instrument name with particular encodings

    >>> encoded_flute = 'flöte'.encode('latin-1')
    >>> me = midi.MidiEvent(channel=4)
    >>> me.type = midi.MetaEvents.SEQUENCE_TRACK_NAME
    >>> me.data = encoded_flute
    >>> fl = midi.translate.midiEventToInstrument(me, encoding='latin-1')
    >>> fl
    <music21.instrument.Flute 'flöte'>
    rR    r   r   z!Could not get an instrument from z$Unable to determine instrument from z; getting generic Instrument   
stacklevelrM   )r   r   zinstrument zinst )rX   r^   bytesdecodesplitstripr   
fromStringrT   r,   r   r_   instrumentFromMidiProgramInstrumentExceptionUnicodeDecodeErrorwarningswarnr<   
InstrumentmidiChannellowerreplaceisdigitr\   r    r[   rc   INSTRUMENT_NAMEinstrumentName)r/   rP   decodedr   s       r6   r   r   z  s   L G$ejj%( jj''177?BGmmoG%%g.A]]b Z

C%@..0A!JJAM

C(44UZZ@A!JJAM003TUZT[1\]] MMA%AM  MMO55}}&&}b9AAC}}&&w3;;=HZZ:999 AJ H ZZ:555&AH9  $25'9UV	

 !!#)) $!!#$s   DG5 5=I5&IIc                    t        j                  |       s| }n| d   }t        |j                        }|d   }t	        d|d         }t        j                  | d|       }|S )am  
    Convert a single MIDI event into a music21 TimeSignature object.

    >>> mt = midi.MidiTrack(1)
    >>> me1 = midi.MidiEvent(mt)
    >>> me1.type = midi.MetaEvents.TIME_SIGNATURE
    >>> me1.data = midi.putNumbersAsList([3, 1, 24, 8])  # 3/2 time
    >>> ts = midi.translate.midiEventsToTimeSignature(me1)
    >>> ts
    <music21.meter.TimeSignature 3/2>

    >>> me2 = midi.MidiEvent(mt)
    >>> me2.type = midi.MetaEvents.TIME_SIGNATURE
    >>> me2.data = midi.putNumbersAsList([3, 4])  # 3/16 time
    >>> ts = midi.translate.midiEventsToTimeSignature(me2)
    >>> ts
    <music21.meter.TimeSignature 3/16>

    rM   r   r   /)r   r   listr^   powr   TimeSignature)r   r/   postr   rG   tss         r6   midiEventsToTimeSignaturer     sh    R Y'! 

DQAAtAwA			s!A3Z	(BIr5   c                   d}g }|rt        |      }|j                  |       | j                  }|dkD  r!t        j                  d|  t
        d       g S t        t        j                  | j                              }d}d}t        |      }	t        j                  |	_        d	|	_        t        ||||g      |	_        |j                  |	       |S )
a  
    Translate a :class:`~music21.meter.TimeSignature` to a pair of events: a DeltaTime and
    a MidiEvent TIME_SIGNATURE.

    Returns a two-element list unless there is an error.

    >>> ts = meter.TimeSignature('5/4')
    >>> eventList = midi.translate.timeSignatureToMidiEvents(ts)
    >>> eventList[0]
    <music21.midi.DeltaTime (empty) track=None>
    >>> eventList[1]
    <music21.midi.MidiEvent TIME_SIGNATURE, track=None, data=b'\x05\x02\x18\x08'>

    Note that time signatures with numerators above 255 cannot be stored in MIDI.
    (A feature?) They will not be stored and an empty list will be returned.
    A warning will be issued.

    >>> ts = meter.TimeSignature('267/32')  # found on music21 list
    >>> import warnings  #_DOCS_HIDE
    >>> with warnings.catch_warnings(): #_DOCS_HIDE
    ...      warnings.simplefilter('ignore') #_DOCS_HIDE
    ...      out = midi.translate.timeSignatureToMidiEvents(ts) #_DOCS_HIDE
    >>> #_DOCS_SHOW out = midi.translate.timeSignatureToMidiEvents(ts)
    >>> out
    []
    Nrk      zFTimeSignature with numerator > 255 cannot be stored in MIDI. Ignoring r   r         rM   )r   rZ   	numeratorr   r   r<   r,   mathlog2denominatorr   r    TIME_SIGNATUREr\   rT   r!   r^   )
r   rV   r   r   rd   r   rG   
metroClicksubCountre   s
             r6   timeSignatureToMidiEventsr  	  s    8 
B+-IR  	
A3wTUWTXY	

 	 	DIIbnn%&AJH		B''BGBJ1j(;<BGRr5   c                    t        j                  |       s| }n| d   }t        |j                        }|d   dkD  r	|d   dz
  }n|d   }d}|d   dk(  rd}t	        j
                  |      }|j                  |      }|S )a  
    Convert a single MIDI event into a :class:`~music21.key.KeySignature` object.

    >>> mt = midi.MidiTrack(1)
    >>> me1 = midi.MidiEvent(mt)
    >>> me1.type = midi.MetaEvents.KEY_SIGNATURE
    >>> me1.data = midi.putNumbersAsList([2, 0])  # d major
    >>> ks = midi.translate.midiEventsToKey(me1)
    >>> ks
    <music21.key.Key of D major>
    >>> ks.mode
    'major'

    >>> me2 = midi.MidiEvent(mt)
    >>> me2.type = midi.MetaEvents.KEY_SIGNATURE
    >>> me2.data = midi.putNumbersAsList([-2, 1])  # g minor
    >>> me2.data
    b'\xfe\x01'
    >>> list(me2.data)
    [254, 1]
    >>> ks = midi.translate.midiEventsToKey(me2)
    >>> ks
    <music21.key.Key of g minor>
    >>> ks.sharps
    -2
    >>> ks.mode
    'minor'
    rM   r         majorminor)r   r   r   r^   r   KeySignatureasKey)r   r/   r   
sharpCountmodeksks          r6   midiEventsToKeyr  D  s    F Y'!

D Aw|!Ws]
!W
DAw!| 
		*	%B
AHr5   c                <   d}g }|rt        |      }|j                  |       | j                  }t        | t        j
                        r| j                  dk(  rd}nd}t        |t        j                        }t        ||g      |_        |j                  |       |S )a  
    Convert a single :class:`~music21.key.Key` or
    :class:`~music21.key.KeySignature` object to
    a two-element list of midi events,
    where the first is an empty DeltaTime (unless includeDeltaTime is False) and the second
    is a KEY_SIGNATURE :class:`~music21.midi.MidiEvent`

    >>> ks = key.KeySignature(2)
    >>> ks
    <music21.key.KeySignature of 2 sharps>
    >>> eventList = midi.translate.keySignatureToMidiEvents(ks)
    >>> eventList
    [<music21.midi.DeltaTime (empty) track=None>,
     <music21.midi.MidiEvent KEY_SIGNATURE, track=None, data=b'\x02\x00'>]

    Note that MIDI Key Signatures are connected to tracks but not to channels.

    MIDI Key Signatures store sharps or flats as the first number, and mode (0 = major
    1 = minor) as the second number.

    Flats are encoded as offsets at 0xff (=1 flat) or below (0xfe = 2 flats ... etc.,
    through 0xfb = 5 flats, below).

    >>> k = key.Key('b-')
    >>> k
    <music21.key.Key of b- minor>
    >>> eventList = midi.translate.keySignatureToMidiEvents(k, includeDeltaTime=False)
    >>> eventList
    [<music21.midi.MidiEvent KEY_SIGNATURE, track=None, data=b'\xfb\x01'>]
    Nrk   r  rM   r   rm   )r   rZ   sharpsrX   r   Keyr  r   r    KEY_SIGNATUREr!   r^   )r  rV   r   r   rd   r  r  re   s           r6   keySignatureToMidiEventsr    s    F 
B+-IR  	 J"cgg277g#5	%%
B 
D12BGRr5   c                    t        j                  |       s| }n| d   }t        |j                  d      d   }t	        d|z  d      }t        j                  |      }|S )zX
    Convert a single MIDI event into a music21 Tempo object.

    TODO: Need Tests
    rM      r    r   number)r   r   r"   r^   r>   r   MetronomeMark)r   r/   mspqbpmmms        r6   midiEventsToTempor'    s]     Y'!UZZ#A&D

T!1
%C 
		C	(BIr5   c                   | j                   | j                  yd}g }|rt        |      }|j                  |       t	        |      }t
        j                  |_        d|_        | j                         }|j                         }t        t        d|z              }t        |d      |_        |j                  |       |S )aF  
    Given any TempoIndication, convert it to list of :class:`~music21.midi.MidiEvent`
    objects that signifies a MIDI tempo indication.

    >>> mm = tempo.MetronomeMark(number=90)
    >>> events = midi.translate.tempoToMidiEvents(mm)
    >>> events
    [<music21.midi.DeltaTime ...>, <music21.midi.MidiEvent SET_TEMPO...>]
    >>> len(events)
    2

    >>> events[0]
    <music21.midi.DeltaTime (empty) track=None>

    >>> evt1 = events[1]
    >>> evt1
    <music21.midi.MidiEvent SET_TEMPO, track=None, data=b'\n,+'>
    >>> evt1.data
    b'\n,+'
    >>> microSecondsPerQuarterNote = midi.getNumber(evt1.data, len(evt1.data))[0]
    >>> microSecondsPerQuarterNote
    666667

    >>> round(60_000_000 / microSecondsPerQuarterNote, 1)
    90.0

    If includeDeltaTime is False then the DeltaTime object is omitted:

    >>> midi.translate.tempoToMidiEvents(mm, includeDeltaTime=False)
    [<music21.midi.MidiEvent SET_TEMPO...>]

    Test round-trip.  Note that for pure tempo numbers, by default
    we create a text name if there's an appropriate one:

    >>> midi.translate.midiEventsToTempo(events)
    <music21.tempo.MetronomeMark maestoso Quarter=90>

    `None` is returned if the MetronomeMark lacks a number, which can
    happen with metric modulation marks.

    >>> midi.translate.tempoToMidiEvents(tempo.MetronomeMark(number=None)) is None
    True

    Sounding numbers also translate even if number is None

    >>> mm = tempo.MetronomeMark(numberSounding=80)
    >>> midi.translate.tempoToMidiEvents(mm)
    [<music21.midi.DeltaTime ...>, <music21.midi.MidiEvent SET_TEMPO...>]
    Nrk   rM   r   r  )r"  numberSoundingr   rZ   r   r    	SET_TEMPOr\   rT   getSoundingMetronomeMarkgetQuarterBPMr,   r>   r#   r^   )	tempoIndicationrV   r   r   rd   re   r&  r%  r$  s	            r6   tempoToMidiEventsr.    s    l %/*H*H*P	B+-IR 		B""BGBJ 
	1	1	3B



CuZ#%&'Da BGRr5   c                    | ||||j                   d|d}|j                  t        j                  k7  r|t	        |j
                        |d<   |S )a  
    Pack a dictionary of parameters for each event.
    Packets are used for sorting and configuring all note events.
    Includes offset, any cent shift, the midi event, and the source object.

    Offset and duration values stored here are MIDI ticks, not quarter lengths.

    >>> n = note.Note('C4')
    >>> midiEvents = midi.translate.elementToMidiEventList(n)
    >>> getPacket = midi.translate.getPacketFromMidiEvent
    >>> getPacket(trackId=1, offset=0, midiEvent=midiEvents[0], obj=n)
    {'trackId': 1,
     'offset': 0,
     'midiEvent': <music21.midi.MidiEvent NOTE_ON, track=None, channel=1, pitch=60, velocity=90>,
     'obj': <music21.note.Note C>,
     'centShift': None,
     'duration': 10080,
     'lastInstrument': None}
    >>> inst = instrument.Harpsichord()
    >>> getPacket(trackId=1, offset=0, midiEvent=midiEvents[1], obj=n, lastInstrument=inst)
    {'trackId': 1,
     'offset': 0,
     'midiEvent': <music21.midi.MidiEvent NOTE_OFF, track=None, channel=1, pitch=60, velocity=0>,
     'obj': <music21.note.Note C>,
     'centShift': None,
     'duration': 0,
     'lastInstrument': <music21.instrument.Harpsichord 'Harpsichord'>}
    r   )trackIdoffset	midiEventobjr   r
   lastInstrumentr
   )r   r\   r   r   rH   r
   )r0  r1  r2  r3  r4  r   s         r6   getPacketFromMidiEventr5  !  s\    H (((	D ~~-6663? /s||<Z Kr5   c                   | xt         j                  d x\    y xt         j                  d x\    t        | d|      S  xt         j                  d x\    t        | dd|      S  xt
        j                  d x\    t        | d|      S  xt        j                  d x\    t        | dd|      S  xt        j                  d x\    y xt        j                  d x\    t        | d      S  xt        j                   d x\    t#        | d      S  xt$        j&                  d x\    t)        | d      S  t*        j,                  d x\   t/        | d      S  	 y)a	  
    Return a list of MidiEvents (or None) from a Music21Object,
    assuming that dynamics have already been applied, etc.
    Does not include DeltaTime objects.

    Channel (1-indexed) is set to the default, 1.
    Track is not set.

    >>> n = note.Note('C4')
    >>> midiEvents = midi.translate.elementToMidiEventList(n)
    >>> midiEvents
    [<music21.midi.MidiEvent NOTE_ON, track=None, channel=1, pitch=60, velocity=90>,
     <music21.midi.MidiEvent NOTE_OFF, track=None, channel=1, pitch=60, velocity=0>]
    r4   NF)rV   rP   r   r   )rV   )r   Restr   r   r   r   r   r   r   r   r   Dynamicr   r   r  r   r  r  r   r#  r.  r   r   r`   )elrP   s     r6   elementToMidiEventListr:  [  sF   ( TYY[ TYY[ $BRR	 
 T^^#BU]^^ U[[]$R%(SS  *Z'')$R%V^__ *X  "U  ",R%HH #S+BGG  "U  " %R%@@ # ""$)"uEE % r5   c           	     j   g }d}| D ]  }t        ||      }t        |t        j                        r|}|0g }d}	|D ]  }
|
j                  t
        j                  k(  r|	du rd}	|	du rt        | j                  |      d      }nt        | j                  |      |      }|
j                  t
        j                  k7  r"t        |||
||      }|j                  |       t        ||t        |j                        z   |
||      }|j                  |        ||z  } |j                  d        |S )	al  
    Convert a flattened, sorted Stream to MIDI Packets.

    This assumes that the Stream has already been flattened,
    ties have been stripped, and instruments,
    if necessary, have been added.

    In converting from a Stream to MIDI, this is called first,
    resulting in a collection of packets by offset.
    Then, getPacketFromMidiEvent is called.
    NrO   FT)rB   )r3  r4  c                *    | d   | d   j                   fS Nr1  r2  	sortOrder)xs    r6   <lambda>z!streamToPackets.<locals>.<lambda>  s    q{AkN$<$<=r5   r   )r:  rX   r   r   r\   r   r   rD   elementOffsetr   r5  rZ   rH   r
   sort)r~   r0  rB   rP   packetsByOffsetr4  r9  midiEventListelementPacketsfirstNotePlayedr2  rA   r   s                r6   streamToPacketsrH    sT   & O15N .rHEb*//0N  &I "6">">>'50"&%'%aoob&9O%aoob&9W~~!5!>!>>*#1 %%a( ++BKK88#13 %%a(A 'B 	>)_ f =   r5   c                ^   |i }|g }|i }i }g }g }| D ]  }|d   |vr|j                  |d          |d   j                  t        j                  k7  r|d   j                  t        j                  k7  r|d   |d   _        |j                  |       |d   j                  t        j                  k(  rq|d   rlt        |d   j                  t        j                  |d   j
                        }|j                  d       t        |d   |d   |	      }	|j                  |	       |d   |d   _        |d   }
|d   |d
   z   }g }|d   }|D ]u  }|\  }}}|
|cxk  r|k  s+n |
|cxk  r|k  sn ||
cxk  r|k  sn ||cxk  r|k  s<n ?||   }|r||vsK|j                  |       ]|s`||vse|j                  |       w |rd}|D ]
  }||vs|} n |t        d      ||d   _        ||d   j                  _        |d   ht        |d   d|d   j                  |      }t        |d   |
|d   	      }|j                  |       n#|d   j
                  }||d   j                  _        |r\t        |d   j                  t        j                  |      }|j                  |       t        |d   |
|	      }|j                  |       |d   |d   |d
   z   |f}||vrg ||<   |r||   j                  |       |j                  |        g }t        |      D ]  \  }}}||vs|j                  |        |D ]Y  }|dk(  r	||   }t        |t        j                  |      }|j                  d       t        |d|	      }	|j                  |	       [ |j                  d        |S )aO  
    Given a list of packets, assign each to a channel.

    Do each track one at time, based on the track id.

    Shift to different channels if a pitch bend is necessary.

    Keep track of which channels are available.
    Need to insert a program change in the empty channel
    too, based on last instrument.

    Insert pitch bend messages as well,
    one for start of event, one for end of event.

    `packets` is a list of packets.
    `channelByInstrument` should be a dictionary.
    `channelsDynamic` should be a list.
    `initTrackIdToChannelMap` should be a dictionary.
    Nr0  r2  initChannelr   )r\   rT   r   r1  )r0  r1  r2  r
   z@no unused channels available for microtone/instrument assignmentr4  F)r   rV   rW   rT   )rl   r\   rT   c                *    | d   | d   j                   fS r=  r>  )x_events    r6   rA  z)assignPacketsToChannels.<locals>.<lambda>  s    WX.0D0N0NOr5   r   )rZ   r\   r   r   r   rT   r   rl   
PITCH_BENDsetPitchBendr5  r8   r   r`   r   rC  )packetschannelByInstrumentchannelsDynamicinitTrackIdToChannelMapuniqueChannelEventsr   
usedTracksr   re   pBendEndrA   oEndchannelExcluder   	key_tuplestartstopusedChannelcentShiftListchr@  meListpgmChangePacket
pBendStartfoundChannels_start_stopr0  s                               r6   assignPacketsToChannelsrd    sM   2 " &"$DJ Y<z)a	l+ [>"6">">>~""&:&C&CC)*=)9+&KKN ~""&:&C&CC [>"1[>#7#7(<(G(G+,[>+A+ACB
 OOA&5 !) {"$ H
 KK) "#=!1+
 hK{Qz]*kN	 -I'0$E4
 e"d"D4)T)+t+ !4I > ".8&--k: ".8&--k:+ -4 B$N*B % z(VX X%'AkN"8:AkN--5 !"./;K9LAF:;K.:N:N8:< #9iL$Qi#
 O, ;''B8:AkN--5
 1[>// 4 ? ?#%'B OOI&/)J
 KK
#
 x[!H+*"=rB	// .0	*	*11)<AY f M&*+>&?"{m+  - '@ a<$W-W0;;!# 	)

 	H $ 	IIO   Kr5   c                T    || S g }| D ]  }|d   |k(  s|j                  |        |S )a  
    Given a list of Packet dictionaries, return a list of
    only those whose trackId matches the filter.

    >>> packets = [
    ...     {'trackId': 1, 'name': 'hello'},
    ...     {'trackId': 2, 'name': 'bye'},
    ...     {'trackId': 1, 'name': 'hi'},
    ... ]
    >>> midi.translate.filterPacketsByTrackId(packets, 1)
    [{'trackId': 1, 'name': 'hello'},
     {'trackId': 1, 'name': 'hi'}]
    >>> midi.translate.filterPacketsByTrackId(packets, 2)
    [{'trackId': 2, 'name': 'bye'}]

    If no trackIdFilter is passed, the original list is returned:

    >>> midi.translate.filterPacketsByTrackId(packets) is packets
    True
    r0  )rZ   )
packetsSrctrackIdFilter
outPacketspackets       r6   filterPacketsByTrackIdrj    sB    0 J)-f%  r5   c                    g }d}| D ]^  }|d   }|d   |z
  }|dk  rt        d      t        |||j                        }|j                  |       |j                  |       |d   }` |S )a  
    Given a list of packets (which already contain MidiEvent objects)
    return a list of those Events with proper delta times between them.

    At this stage MIDI event objects have been created.
    The key process here is finding the adjacent time
    between events and adding DeltaTime events before each MIDI event.

    Delta time channel values are derived from the previous midi event.
    r   r2  r1  zgot a negative delta time)rn   rT   )r8   r   rT   rZ   )rO  rW   rb   
lastOffsetri  r2  deltaTimeIntrd   s           r6   packetsToDeltaSeparatedEventsrn    s     )+FJ;'	h'*4!$%@AAy|Y=N=NObi H%
  Mr5   c                  t        |      }|xj                  t        |||      z  c_        t        | |      }|xj                  t	        ||      z  c_        |xj                  t        ||      z  c_        |j                          |S )a  
    Given packets already allocated with channel
    and/or instrument assignments, place these in a MidiTrack.

    Note that all packets can be sent; only those with
    matching trackIds will be collected into the resulting track

    The `channel` defines the channel that startEvents and endEvents
    will be assigned to

    Use streamToPackets to convert the Stream to the packets

    * New in v10.3: addEndDelay keyword.
    )rT   ra   rh   )r   rb   rg   rj  rn  rp   updateEvents)rO  r0  rT   ra   ri   r   trackPacketss          r6   packetsToMidiTrackrr    su      
7	BII(/.;= =I
 *'7;LII.|R@@I IIbk::IOOIr5   c                   g }d}d}|t        | j                        k  r| j                  |   }	 | j                  |dz      }|j                         }|j                         }|r,|s*||j                  z  }||f}|j                  |       |dz  }n|s|s|dz  }n|r|r|dz  }n|dz  }|t        | j                        k  r|S # t        $ r Y |S w xY w)zY
    Get a list of tuples of (tickTime, MidiEvent) from the events with time deltas.
    r   rM   r   )lenrb   
IndexErrorisDeltaTimern   rZ   )	r   rb   currentTimer   currentEvent	nextEvent	currentDtnextDttupleAppends	            r6   getTimeForEventsr}  '  s     FK 	
A
c"))n
yy|			!a%(I !,,.	&&( V<,,,K&	2KMM+&FAFA6FA FAA c"))n
D M=  	: M=	s   C 	CCc                F   g }i }| ddd   D ]|  \  }}|j                         r|||j                  |j                  f<   2|j                         sC	 ||j                  |j                  f   }t	        |||      }|j                  |       ~ |ddd   S # t        $ r Y w xY w)a  
    Takes in a list of tuples of (tickTime, MidiEvent) and returns a list of
    TimedNoteEvent objects which contain the note on time, the note off time,
    and the MidiEvent of the note on.  (The note off MidiEvent is not included)

    If timedEvents is sorted in non-decreasing order of tickTime, then the
    output here will also be sorted in non-decreasing order of note on time.

    Example: here are two pitches, represented as note on and note off events:

    >>> CVM = midi.ChannelVoiceMessages
    >>> ev1on = midi.MidiEvent(type=CVM.NOTE_ON)
    >>> ev1on.pitch = 60
    >>> ev2on = midi.MidiEvent(type=CVM.NOTE_ON)
    >>> ev2on.pitch = 62
    >>> ev1off = midi.MidiEvent(type=CVM.NOTE_OFF)
    >>> ev1off.pitch = 60
    >>> ev2off = midi.MidiEvent(type=CVM.NOTE_OFF)
    >>> ev2off.pitch = 62

    >>> events = [(0, ev1on), (1, ev2on), (2, ev2off), (3, ev1off)]

    >>> notes = midi.translate.getNotesFromEvents(events)
    >>> len(notes)
    2
    >>> notes
    [TimedNoteEvent(onTime=0, offTime=3, event=<music21.midi.MidiEvent NOTE_ON...>),
     TimedNoteEvent(onTime=1, offTime=2, event=<music21.midi.MidiEvent NOTE_ON...>)]
    >>> (notes[0].event.pitch, notes[1].event.pitch)
    (60, 62)
    Nr   )	isNoteOffr   rT   isNoteOnr+   rZ   KeyError)timedEventsnotesawaitingNoteOnrn   r/   r.   tnes          r6   getNotesFromEventsr  \  s    D #%E 79N #4R4(e??9=N5;;56^^ )emm)CD$T7E:S! )* 2;  s   9B	B B c               0   i }| D ]]  \  }}|j                   t        j                  k(  s$t        |j                  t
              s?	 |j                  j                  |      ||<   _ |S # t        $ r% t        j                  d| d| t        d       Y w xY w)a   
    From a list of timed events, that is a tuple of a tick time and a MidiEvent
    Return a dictionary mapping a tick time to a string representing a lyric.

    If more than one lyric is found at a given tick time, the last one found is
    stored.
    zUnable to decode lyrics from z as r   r   )r\   r    r   rX   r^   r   r   r   r   r   r<   )rb   rP   lyricsrn   es        r6   lyricTimingsFromEventsr    s      Fa66Z%%%*QVVU*C vv}}X6t  M & 3A3d8*E$ s   A''+BBc               z   g }d}| D ]0  \  }}d}|j                   t        j                  k(  rt        |      }n|j                   t        j                  k(  rt        |      }n|j                   t        j                  k(  rt        |      }n|j                   t        j                  t        j                  fv rt        ||      }|dk7  rV||_        nN|j                   t        j                  k(  r1t        |j                  t               rt        |      }|j                  }|s||f}|j#                  |       3 |S )z
    Translate MidiEvents whose type is a MetaEvent into Music21Objects.

    Note: this does not translate MetaEvent.LYRIC, since that becomes a
    bare string.

    New in 9.7: add encoding
    r   NrO   )r\   r    r	  r   r  r  r*  r'  r   r[   r   r_   r   r   rX   
parameter1r,   rZ   )rb   rP   
metaEventslast_program	timeEventr  metaObjpairs           r6   getMetaEventsr    s	    8:JL	1+/66Z.../2GVVz///%a(GVVz+++'*GVV
22J4R4RSS ,AAGr!&2#VV+:::z!,,X[?\+A.G<<L w'Dd#7 : r5   isFirstc                   | j                  d      D ]`  }t        j                  |      }d|j                  v r|sd|j                  _        d|_        |j                  | j                  |      |       b y)z
    Insert a deepcopy of any TimeSignature, KeySignature, or MetronomeMark
    found in the `conductorPart` into the `target` Part at the same offset.

    Obligatory to do this before making measures. New in v7.
    )r   r  r#  TempoIndicationTN)	getElementsByClassry   rz   classesstylehideObjectOnPrintnumberImplicitr{   rB  )conductorParttargetr  r  	eventCopys        r6   insertConductorEventsr    sk     -->@ MM!$		 1 11'04IOO-'+I$m11!4i@@r5   r4   )r?   quantizePostr   r  r  quarterLengthDivisorsrP   c                  |t        j                         }	n|}	t        |       }
t        |
      }t	        |
|      }t        |
|      }|D ]#  \  }}|	j                  t        ||z        |       % |	j                          t        |	d       g }dgt        |      z  }d}|st        j                  }|rt        |      }nd}||z  }t        |      D ]  \  }}||   r|j                  }|j                   }|g}t#        |dz   t        |            D ]`  }||   j                  }||   j                   }t%        ||z
        |k\  r n/t%        ||z
        |kD  rd}H|j'                  ||          d||<   b t        |      dkD  rt)        ||      }nt+        ||      }t        ||z        }||j,                  _        |j1                  |      x}r||_        |	j                  ||        |	j5                  d       |r|	j7                  |dddd	       |s|	S |t9        ||	|
       d}|`|d   } | rY| j                         }t:        j<                  r|J |j?                  d      s$|jA                  dtC        jD                                |	jG                  |d       |r7|	jI                  t         jJ                        D ]  }!|!jM                  dd        |	jO                  d       |	jQ                  ddd       |	S )aS  
    Note that quantization takes place in stream.py since it's useful not just for MIDI.

    >>> fp = common.getSourceFilePath() / 'midi' / 'testPrimitive' / 'test05.mid'
    >>> mf = midi.MidiFile()
    >>> mf.open(fp)
    >>> mf.read()
    >>> mf.close()
    >>> mf
    <music21.midi.MidiFile 1 track>
    >>> len(mf.tracks)
    1
    >>> mt = mf.tracks[0]
    >>> mt
    <music21.midi.MidiTrack 0 -- 56 events>
    >>> mt.events
    [<music21.midi.DeltaTime ...>,
     <music21.midi.MidiEvent SEQUENCE_TRACK_NAME...>,
     <music21.midi.DeltaTime ...>,
     <music21.midi.MidiEvent NOTE_ON, track=0, channel=1, pitch=36, velocity=90>,
     ...]
    >>> p = midi.translate.midiTrackToStream(mt, ticksPerQuarter=mf.ticksPerQuarterNote)
    >>> p
    <music21.stream.Part ...>
    >>> len(p.recurse().notesAndRests)
    14
    >>> p.recurse().notes.first().pitch.midi
    36
    >>> p.recurse().notes.first().volume.velocity
    90

    Note that as of music21 v7, the Part object already has measures made:

    >>> p.show('text')
    {0.0} <music21.stream.Measure 1 offset=0.0>
        {0.0} <music21.instrument.Instrument ''>
        {0.0} <music21.clef.TrebleClef>
        {0.0} <music21.meter.TimeSignature 4/4>
        {0.0} <music21.note.Note C>
        {1.0} <music21.note.Rest quarter>
        {2.0} <music21.chord.Chord F3 G#4 C5>
        {3.0} <music21.note.Rest quarter>
    {4.0} <music21.stream.Measure 2 offset=4.0>
        {0.0} <music21.note.Rest eighth>
        {0.5} <music21.note.Note B->
        {1.5} <music21.note.Rest half>
        {3.5} <music21.chord.Chord D2 A4>
    {8.0} <music21.stream.Measure 3 offset=8.0>
        {0.0} <music21.note.Rest eighth>
        {0.5} <music21.chord.Chord C#2 B-3 G#6>
        {1.0} <music21.note.Rest dotted-quarter>
        {2.5} <music21.chord.Chord F#3 A4 C#5>
    {12.0} <music21.stream.Measure 4 offset=12.0>
        {0.0} <music21.chord.Chord F#3 A4 C#5>
        {2.5} <music21.note.Rest dotted-quarter>
        {4.0} <music21.bar.Barline type=final>

    * Changed in v7: Now makes measures.
    * Changed in v8: all but the first attribute are keyword only.
    NrO   Tr   F   rM   )force)r  processOffsetsprocessDurationsr   recurser  r   r   )meterStreamr   )r   fillGaps)r   r  timeRangeFromBarDuration))r   Partr}  r  r  r  
coreInsertr   coreElementsChangedr   rt  r   !quantizationQuarterLengthDivisorsmaxr   r-   r.   rangeabsrZ   r   r   	editorialmidiTickStartgetr   rC  quantizer  rw   TYPE_CHECKINGgetElementsByOffsetr{   r   r   makeMeasuresr  Measure
makeVoicesmakeTies	makeRests)"r   r?   r  r   r  r  r  rP   keywordsr~   r  r  r  
lyricsDicttickr3  chordSub	iGatheredvoicesRequireddivisorchunkTolerancer   r   	tickStartr   jtSubtOffSubnote_or_chordrA   r   r  ts_iterms"                                     r6   midiTrackToStreamr    s    X KKM #2&K #5["AE{X>J'hGJ  	c	VD?23S9   4 
 &(H #Gc%j0IN  ( J J +, $w.N&u->Q<"))	%%"# q1uc%j)A8??DAh&&G 4)#$6 7T>"^3 "&OOE!H%IaL! ** x=1-hHM -^_MM9./09-NN9--5-"'M	Q&i .l FFF	

)>"&$( 	 	 	"   mQ@&*K 0!..*K"... 2215""1e&9&9&;< NN{DN9%%fnn5ALLL6 6 JJtJKKtdKKHr5   c                   | t         j                     r| j                         } n| j                  d      } t	        |       }| j                         rO| j                  t         j                        D ]  }t        j                  |        | j                  d|       | }|S t        j                  |        t        j                         }|j                  d|       |j                  d|        |S )a
  
    Given a score, prepare it for MIDI processing, and return a new Stream:

    1. Expand repeats.

    2. Make changes that will let us later create a conductor (tempo) track
    by placing `MetronomeMark`, `TimeSignature`, and `KeySignature`
    objects into a new Part, and remove them from other parts.

    3.  Ensure that the resulting Stream always has part-like substreams.

    Note: will make a deepcopy() of the stream.

    >>> s = stream.Score()
    >>> p = stream.Part()
    >>> m = stream.Measure(number=1)
    >>> m.append(tempo.MetronomeMark(100))
    >>> m.append(note.Note('C4', type='whole'))  # MIDI 60
    >>> p.append(m)
    >>> s.append(p)
    >>> sOut = midi.translate.prepareStreamForMidi(s)
    >>> sOut.show('text')
    {0.0} <music21.stream.Part 0x10b0439a0>
        {0.0} <music21.tempo.MetronomeMark Quarter=100>
        {0.0} <music21.meter.TimeSignature 4/4>
    {0.0} <music21.stream.Part 0x10b043c10>
        {0.0} <music21.stream.Measure 1 offset=0.0>
            {0.0} <music21.note.Note C>
    prepareStreamForMidir   )r   r  expandRepeatscoreCopyAsDerivationconductorStreamhasPartLikeStreamsr  rs   r   realizeVolumer{   Score)r~   	conductorr   outs       r6   r  r    s    > 	OO""#9:"I
 %%fmm4A  # 5 	
I J 	Qlln

1i 

1aJr5   c                   t        | j                  t        j                        j	                  d            }|rt        d |D              nd}|dz
  }t        j                         }||_        |j                  dt                      dD ]a  }d}| |   D ],  }|j                  |       }||kD  r|j                  ||       |}. | j                  dd      D ]  }	|	j                  |        c |j                  t        j                        s%|j                  t        j                  d	             |j                  t        j                         s$|j                  t        j                   d
             |S )a  
    Strip the given stream of any events that belong in a conductor track
    rather than in a music track, and returns a :class:`~music21.stream.Part`
    containing just those events, without duplicates, suitable for being a
    Part to turn into a conductor track.

    Sets a default MetronomeMark of 120 if no MetronomeMarks are present
    and a TimeSignature of 4/4 if not present.

    Ensures that the conductor track always sorts before other parts.

    Here we purposely use nested generic streams instead of Scores, Parts, etc.
    to show that this still works.  But you should use Score, Part, Measure instead.

    >>> s = stream.Stream(id='scoreLike')
    >>> p = stream.Stream(id='partLike')
    >>> p.priority = -2
    >>> m = stream.Stream(id='measureLike')
    >>> m.append(tempo.MetronomeMark(100))
    >>> m.append(note.Note('C4'))
    >>> p.append(m)
    >>> s.insert(0, p)
    >>> conductor = midi.translate.conductorStream(s)
    >>> conductor.priority
    -3

    The MetronomeMark is moved and a default TimeSignature is added:

    >>> conductor.show('text')
    {0.0} <music21.instrument.Conductor 'Conductor'>
    {0.0} <music21.tempo.MetronomeMark Quarter=100>
    {0.0} <music21.meter.TimeSignature 4/4>

    The original stream still has the note:

    >>> s.show('text')
    {0.0} <music21.stream.Stream partLike>
        {0.0} <music21.stream.Stream measureLike>
            {0.0} <music21.note.Note C>
    r   c              3  4   K   | ]  }|j                     y wN)priority).0r   s     r6   	<genexpr>z"conductorStream.<locals>.<genexpr>:	  s     4)Qajj)s   rM   )r#  r   r  r   T)streamsOnlyincludeSelfx   r!  z4/4)r   r  r   rs   r  minr  r  r{   r   getOffsetInHierarchyr  removeByClassr   r#  r   r   )
r~   	partsListminPriorityconductorPriorityr  klassrl  r9  offset_in_ss_or_inner_streams
             r6   r  r  	  sB   T Q))&--8LLQOPI8A#4)44qK#aKKMM.MIK(C
E(B11!4KZ'$$["5$J  "#t!N++E2 "O D ++E,?,?@U00<=++E,?,?@U0078r5   c                   ||dd }n+t        t        dd            t        t        dd            z   }g }i }g }t               }g }| j                         rS| j	                  t
        j                        D ]0  }|t        j                     s
|t           r |j                  |       2 n|j                  |        |D ]  }	|	t        j                     }
d}|
D ]  }|j                  O|j                  |vrA|j                  dz   }	 |j                  |       |j)                  |       |||j                  <   |j                  |vr|j                  |j                         d} |rd|vs|j                  d        |D cg c]	  }||vs| }}t+        |      D ]O  \  }}|t-        |      dz
  k  r||   ||<   |j)                  ||          4|d   ||<   |j)                  |d          Q |D ]  }||vs|j                  |        ||fS # t         $ r0 |dk7  r't#        j$                  | d| d| d	t&        d
       d}Y 2w xY wc c}w )a  
    Read through Stream `s` and finding instruments in it, return a 2-tuple,
    the first a dictionary mapping MIDI program numbers to channel numbers,
    and the second, a list of unassigned channels that can be used for dynamic
    allocation. One channel is always left unassigned for dynamic allocation.
    If the number of needed channels exceeds the number of available ones,
    any further MIDI program numbers are assigned to channel 1.

    Substreams without notes or rests (e.g. representing a conductor track)
    will not consume a channel.

    Only necessarily works if :func:`~music21.midi.translate.prepareStreamForMidi`
    has been run before calling this routine.

    An instrument's `.midiChannel` attribute is observed.
    `None` is the default `.midiChannel` for all instruments except
    :class:`~music21.instrument.UnpitchedPercussion`
    subclasses. Put another way, the priority is:

    - Instrument instance `.midiChannel` (set by user or imported from MIDI)
    - `UnpitchedPercussion` subclasses receive MIDI Channel 10 (9 in music21)
    - The channel mappings produced by reading from `acceptableChannelList`,
      or the default range 1-16. (More precisely, 1-15, since one dynamic channel
      is always reserved.)

    .. warning::

        The attribute `.midiChannel` on :class:`~music21.instrument.Instrument`
        is 0-indexed, but `.channel` on :class:`~music21.midi.MidiEvent` is 1-indexed,
        as are all references to channels in this function.
    NrM   r         Fz" specified 1-indexed MIDI channel z but acceptable channels were z. Defaulting to channel 1.r   r   Tr   )r   r  setr  r  r   rs   r   GeneralNoter   rZ   r   r   r   r_   remove
ValueErrorr   r   r<   r   r   rt  )r~   acceptableChannelListacceptableChannelsallUniqueInstrumentsrP  rQ  channelsAssignedsubstreamListr3  subsinstrumentStreamsetAnInstrumentr   thisChannelr@  programsStillNeededr   iPgmr]  s                      r6   channelInstrumentDatar  U	  s   H (215!%2,/$uR}2EE O u M''6C(()s9~$$S) 7 	Q 
 5 56$D+0@0@H[0[ #..2(&--k: !$$[18C#D$4$45';;$++D,<,<="O3 %6 //$++D1C F ';[&:aGZ>Z1&:[014s%&** );1(=%  !3A!67(:1(=%  !3A!67 2 !%%""2& ! //U " ( #b( !#f$F{m T<<N;O P77 -'(* '((0 \s   H 	I

I
5IIrB   rP   c                  i }t        |       D ]  \  }}|j                         }|j                  t        j                        j                         }||j                  dk7  s|j                  U|j                  t        j                  t        j                  f      rt               }n|dk(  r|j                  s
t               }t        ||||      }||d||<    |S )a{  
    Make a dictionary of raw packets and the initial instrument for each
    subStream.

    If the first Part in the list of parts is empty then a new
    :class:`~music21.instrument.Conductor` object will be given as the instrument.

    >>> s = stream.Score()
    >>> p = stream.Part()
    >>> m = stream.Measure(number=1)
    >>> m.append(tempo.MetronomeMark(100))
    >>> m.append(instrument.Oboe())
    >>> m.append(note.Note('C4', type='whole'))  # MIDI 60
    >>> p.append(m)
    >>> s.append(p)
    >>> sOut = midi.translate.prepareStreamForMidi(s)
    >>> partList = list(sOut.parts)
    >>> packetStorage = midi.translate.packetStorageFromSubstreamList(partList)
    >>> list(sorted(packetStorage.keys()))
    [0, 1]
    >>> list(sorted(packetStorage[0].keys()))
    ['initInstrument', 'rawPackets']

    >>> from pprint import pprint
    >>> pprint(packetStorage)
    {0: {'initInstrument': <music21.instrument.Conductor 'Conductor'>,
         'rawPackets': [{'centShift': None,
                         'duration': 0,
                         'lastInstrument': <music21.instrument.Conductor 'Conductor'>,
                         'midiEvent': <music21.midi.MidiEvent SET_TEMPO, ...>,
                         'obj': <music21.tempo.MetronomeMark Quarter=100>,
                         'offset': 0,
                         'trackId': 0},
                        {'centShift': None,
                         'duration': 0,
                         'lastInstrument': <music21.instrument.Conductor 'Conductor'>,
                         'midiEvent': <music21.midi.MidiEvent TIME_SIGNATURE, ...>,
                         'obj': <music21.meter.TimeSignature 4/4>,
                         'offset': 0,
                         'trackId': 0}]},
     1: {'initInstrument': <music21.instrument.Oboe 'Oboe'>,
         'rawPackets': [{'centShift': None,
                         'duration': 0,
                         'lastInstrument': <music21.instrument.Oboe 'Oboe'>,
                         'midiEvent': <music21.midi.MidiEvent PROGRAM_CHANGE,
                                          track=None, channel=1, data=68>,
                         'obj': <music21.instrument.Oboe 'Oboe'>,
                         'offset': 0,
                         'trackId': 1},
                        {'centShift': None,
                         'duration': 40320,
                         'lastInstrument': <music21.instrument.Oboe 'Oboe'>,
                         'midiEvent': <music21.midi.MidiEvent NOTE_ON,
                                          track=None, channel=1, pitch=60, velocity=90>,
                         'obj': <music21.note.Note C>,
                         'offset': 0,
                         'trackId': 1},
                        {'centShift': None,
                         'duration': 0,
                         'lastInstrument': <music21.instrument.Oboe 'Oboe'>,
                         'midiEvent': <music21.midi.MidiEvent NOTE_OFF,
                                           track=None, channel=1, pitch=60, velocity=0>,
                         'obj': <music21.note.Note C>,
                         'offset': 40320,
                         'trackId': 1}]}}
    r   )r0  rB   rP   )
rawPacketsinitInstrument)r   flattenr  r   r   firstr1  r_   r   r   r   r   r   notesAndRestsr   rH  )r  rB   rP   packetStorager0  r  instObjrq  s           r6   packetStorageFromSubstreamListr  	  s    R M"=1||~ /3.E.E!!/

%' 	 ?w~~2g6I6I6Q&&
8R8R'ST ./Ad&8&8#+&tWM08: '%"
g) 20 r5   c                   | j                         D ]  \  }}|d   }|	 |d   }nut        |t        j                        rd}nXt        |t        j
                        rd}n;t        j                  rt        |t        j                        sJ ||j                     }||d<   |d   D ]  }||d<   	  y# t        $ r d}Y $w xY w)z
    Take the packetStorage dictionary and using information
    from 'initInstrument' and channelByInstrument, add an 'initChannel' key to each
    packetStorage bundle and to each rawPacket in the bundle['rawPackets']
    r  NrM   r   rJ  r  )
itemsr  rX   r   r   r   rw   r  r   r_   )r  rP  unused_trackIdbundler  initCh	rawPackets          r6   "updatePacketStorageWithChannelInfor  6
  s     #0"5"5"7)*?,T2 !?!?@F!5!56F!':+@+@AAA()<)<=F &}-I'-Im$ .% #8  s   B11B?>B?)r  rB   ri   rP   c               l   t        |       }t        ||      \  }}g }g }	|j                  t        j                        D ]7  }
|
j                  d      r|	j                  d|
       '|	j                  |
       9 |	D ]  }|j                  dd        t        |	||      }t        ||       i }|j                         D ]  \  }}|d   ||<    g }|j                         D ]
  }||d   z  } t        ||||      }|D ]3  }||   d   }||   d	   }t        |||||
      }|j                  |       5 |S )a  
    Given a Stream, Score, Part, etc., that may have substreams (i.e.,
    a hierarchy), return a list of :class:`~music21.midi.MidiTrack` objects.

    acceptableChannelList is a list of MIDI Channel numbers that can be used or None.
    If None, then 1-9, 11-16 are used (10 being reserved for percussion).

    In addition, if an :class:`~music21.instrument.Instrument` object in the stream
    has a `.midiChannel` that is not None, that channel is observed, and
    also treated as reserved. Only subclasses of :class:`~music21.instrument.UnpitchedPercussion`
    have a default `.midiChannel`, but users may manipulate this.
    See :func:`channelInstrumentData` for more, and for documentation on `acceptableChannelList`.

    Called by streamToMidiFile()

    The process:

    1. makes a deepcopy of the Stream (Developer TODO: could this
       be done with a shallow copy? Not if ties are stripped and volume realized.)

    2. we make a list of all instruments that are being used in the piece.

    * Changed in v6: acceptableChannelList is keyword only.  addStartDelay is new.
    * Changed in v6.5: Track 0 (tempo/conductor track) always exported.
    * New in v10.3: addEndDelay keyword.
    )r#  r   r   T)r   matchByPitchr  rJ  r  )rP  rQ  rR  r  )r0  rT   ra   ri   )r  r  r  r   rs   r{   rZ   	stripTiesr  r  r  valuesrd  rr  )r   r  rB   ri   rP   r~   rP  rQ  
midiTracksr  r3  r  r  rR  r0  r	  
netPacketsrJ  ra   r   s                       r6   streamHierarchyToMidiTracksr  V
  s{   F 	X&A+@DY+Z( J M##FMM2!!"DE  C(  % 3 t$7  3=P]<DFM&}6IJ (..0+1-+@( 1 J&&(f\**
 ) )/' 7	9J !#G,];%g./?@
(/(3.;,7	9
 	" ! r5   c                  |t        j                         }n|}t        j                         }d}| D ]T  }	|	j                         r+||	}t        j                         }
|j	                  d|
       n|}
t        |	f|||
||	|u |d| V |S )zt
    Given a list of midiTracks, populate either a new stream.Score or inputM21
    with a Part for each track.
    Nr   )r?   r  r   r  r  rP   )r   r  r  hasNotesr{   r  )r  r?   r  r   rP   r  r~   r  firstTrackWithNotesr   
streamParts              r6   midiTracksToStreamsr  
  s     LLN KKMM ;;="*&(#JHHQ
#&J" 	&*9'3#-(5#%)<#<#+	& %	& * Hr5   rB   ri   r  rP   c               v    | }t        |||||      }t               }||_        t        j                  |_        |S )a  
    Converts a Stream hierarchy into a :class:`~music21.midi.MidiFile` object.

    >>> s = stream.Stream()
    >>> n = note.Note('g#')
    >>> n.quarterLength = 0.5
    >>> s.repeatAppend(n, 4)
    >>> mf = midi.translate.streamToMidiFile(s)
    >>> mf.tracks[0].index  # Track 0: conductor track
    0
    >>> len(mf.tracks[1].events)  # Track 1: music track
    22

    From here, you can call mf.writestr() to get the actual file info.

    >>> sc = scale.PhrygianScale('g')
    >>> s = stream.Stream()
    >>> x=[s.append(note.Note(sc.pitchFromDegree(i % 11), quarterLength=0.25)) for i in range(60)]
    >>> mf = midi.translate.streamToMidiFile(s)
    >>> #_DOCS_SHOW mf.open('/Volumes/disc/_scratch/midi.mid', 'wb')
    >>> #_DOCS_SHOW mf.write()
    >>> #_DOCS_SHOW mf.close()

    See :func:`channelInstrumentData` for documentation on `acceptableChannelList`.

    Set `addEndDelay` to False to skip the trailing rest added by `getEndEvents`.

    * New in v10.3: addEndDelay keyword.
    r  )r  r   tracksr   r?   ticksPerQuarterNote)r   rB   ri   r  rP   r~   r  mfs           r6   rv   rv   
  sE    L 	A,Q;H9DCX6>	/J 
BBI%55BIr5   r   rP   c                   t               }|j                  |        |j                          |j                          t	        |f||d|S )a^  
    Used by music21.converter:

    Take in a file path (name of a file on disk) and using `midiFileToStream`,

    return a :class:`~music21.stream.Score` object (or if inputM21 is passed in,
    use that object instead).

    Keywords to control quantization:
    `quantizePost` controls whether to quantize the output. (Default: True)
    `quarterLengthDivisors` allows for overriding the default quantization units
    in defaults.quantizationQuarterLengthDivisors. (Default: (4, 3)).

    >>> sfp = common.getSourceFilePath() #_DOCS_HIDE
    >>> fp = str(sfp / 'midi' / 'testPrimitive' / 'test05.mid') #_DOCS_HIDE
    >>> #_DOCS_SHOW fp = '/Users/test/music21/midi/testPrimitive/test05.mid'
    >>> streamScore = midi.translate.midiFilePathToStream(fp)
    >>> streamScore
    <music21.stream.Score ...>

    * Changed in v8: inputM21 is keyword only.
    r  )r   openreadclosemidiFileToStream)filePathr   rP   r  r  s        r6   midiFilePathToStreamr%    s@    : 
BGGHGGIHHJBQHQQQr5   c                   t               }t        |      }|dk(  rd|_        n| |_        ||_        |t	        |      D ]  }t        |      }||   D ]T  }t        |      }t        |      }	t        |      j                  d      }
|dz   |	_
        t        |
d         |	_        |dz   |_
        t        |
d   d      |_        t        |
d         |_        d}|
d   dk7  rtt        |
d         d   d	k(  rt         j"                  |_        d
}nct        |
d         d   dk(  rd
}t         j&                  |_        n7t(        j+                  d|
d           nt(        j+                  d|
d           |s|j,                  j/                  |	       |j,                  j/                  |       W |j0                  j/                  |        d}||j3                         z   }|S )a  
    Convert Ascii midi data to a bytes object (formerly binary midi string).

    tracksEventsList contains a list of tracks which contain also a list of events.

        asciiMidiEventList = ['0 90 27 66', '0 90 3e 60', '3840 80 27 00', '0 80 3e 00']

    The format of one event is : 'aa bb cc dd'::

        aa = delta time to last event (integer)
        bb = Midi event type
        cc = Note number (hex)
        dd = Velocity (integer)

    Example:

    >>> asciiMidiEventList = []
    >>> asciiMidiEventList.append('0 90 31 15')
    >>> midiTrack = []
    >>> midiTrack.append(asciiMidiEventList)
    >>> midiBinaryBytes = midi.translate.midiAsciiStringToBinaryString(tracksEventsList=midiTrack)
    >>> midiBinaryBytes
    b'MThd\x00\x00\x00\x06\x00\x01\x00\x01\x03\xc0MTrk\x00\x00\x00\x04\x00\x901\x0f'

    Note that the name is from pre-Python 3.  There is now in fact nothing called a "binary string"
    it is in fact a bytes object.
    rM    r   r   r  r  FFF8T9zUnsupported midi event: 0xzUnsupported meta event: 0xr5   )r   rt  formatr  r  r   r   r   strr   rT   r,   rn   r   r   r   r   r   r\   r   environLocalr   rb   rZ   r  writestr)
midiFormatr  tracksEventsListr  	numTracksr   trkr  re   rd   chunk_event_paramvalid
midiBinStrs                r6   midiAsciiStringToBinaryStringr6  ?  s   @ 
B$%IA~		0B#y!AA,C%a(s^s^$'FLL$5!U
/23U
03R8!"3A"67$Q'4/-a01!4;"6"?"? $/23A6#= $"6">">$)),FGXYZG[F\*]^ %%(BCTUVCWBX&YZJJ%%b)JJ%%b)9 )< IIS!A "D Jbkkm+Jr5   c                P    t               }|j                  |        t        |fi |S )aT  
    Convert a string of binary midi data to a Music21 stream.Score object.

    Keywords to control quantization:
    `quantizePost` controls whether to quantize the output. (Default: True)
    `quarterLengthDivisors` allows for overriding the default quantization units
    in defaults.quantizationQuarterLengthDivisors. (Default: (4, 3)).

    N.B. -- this has been somewhat problematic, so use at your own risk.

    >>> midiBinStr = (b'MThd\x00\x00\x00\x06\x00\x01\x00\x01\x04\x00'
    ...               + b'MTrk\x00\x00\x00\x16\x00\xff\x03\x00\x00\xe0\x00@\x00'
    ...               + b'\x90CZ\x88\x00\x80C\x00\x88\x00\xff/\x00')
    >>> s = midi.translate.midiStringToStream(midiBinStr)
    >>> s.show('text')
    {0.0} <music21.stream.Part 0x108aa94f0>
        {0.0} <music21.stream.Measure 1 offset=0.0>
            {0.0} <music21.instrument.Instrument ''>
            {0.0} <music21.clef.TrebleClef>
            {0.0} <music21.meter.TimeSignature 4/4>
            {0.0} <music21.note.Note G>
            {1.0} <music21.note.Rest dotted-half>
            {4.0} <music21.bar.Barline type=final>
    )r   readstrr#  )strDatar  r  s      r6   midiStringToStreamr:    s'    2 
BJJwB+(++r5   )r   r  rP   c                   |t        j                         }n|}| j                  st        j                  d      t        | j                  f| j                  |||d| |S )a  
    Note: this is NOT the normal way to read a MIDI file.  The best way is generally:

        score = converter.parse('path/to/file.mid')

    Convert a :class:`~music21.midi.MidiFile` object to a
    :class:`~music21.stream.Stream` object.

    The `inputM21` object can specify an existing Stream (or Stream subclass) to fill.

    Keywords to control quantization:
    `quantizePost` controls whether to quantize the output. (Default: True)
    `quarterLengthDivisors` allows for overriding the default quantization units
    in defaults.quantizationQuarterLengthDivisors. (Default: (4, 3)).

    >>> import os
    >>> fp = common.getSourceFilePath() / 'midi' / 'testPrimitive' / 'test05.mid'
    >>> mf = midi.MidiFile()
    >>> mf.open(fp)
    >>> mf.read()
    >>> mf.close()
    >>> len(mf.tracks)
    1
    >>> s = midi.translate.midiFileToStream(mf)
    >>> s
    <music21.stream.Score ...>
    >>> len(s.flatten().notesAndRests)
    14

    * Changed in v8: inputM21 and quantizePost are keyword only.
    z(no tracks are defined in this MIDI file.)r?   r  r   rP   )r   r  r  r   StreamExceptionr  r  )r  r   r  rP   r  r~   s         r6   r#  r#    sl    R LLN99**+UVV 		 $(*(>(>%1!"!)	$
 #$ Hr5   __main__)F)rA   r'   rB   boolreturnr,   )rG   duration.Durationr?  r,   )rC   r,   r?   r,   rK   zduration.Duration | Noner?  r@  )NrM   N)
rW   MidiTrack | NonerT   r,   ra   instrument.Instrument | NonerP   r,  r?  list[DeltaTime | MidiEvent]r  )rW   rA  ri   r>  r?  list[MidiEvent | DeltaTime])r|   base.Music21ObjectrP   r,  r?  r   )
r   r,   r   r,   r?   r,   r   ztype[NotRestType]r?  r(   )r   r+   r?   r,   r?  note.Note | note.Unpitched)
r   rF  rV   r>  rT   r,   rP   r,  r?  rC  )r   zSequence[TimedNoteEvent]r?   r,   r?  chord.ChordBase)
r   rG  rV   r>  rT   r,   rP   r,  r?  rC  )r   znote.Unpitchedr?  r,   )TNrM   )r   instrument.InstrumentrV   r>  rW   rA  rT   r,   )r   z!MidiEvent | tuple[int, MidiEvent]rP   r,  r?  rH  )r/   r   rP   r,  r?  rH  )T)r?  rC  )r?  zkey.Key)r  zkey.KeySignaturer?  rC  )r-  ztempo.MetronomeMarkr?  z"list[DeltaTime | MidiEvent] | None)NN)r0  r,   r1  r,   r2  r   r3  zbase.Music21Object | Noner4  rB  r?  zdict[str, t.Any])rN   )r9  rE  rP   r,  r?  z"list[MidiEvent | DeltaTime] | None)rM   FrN   )
r~   stream.Streamr0  r,   rB   r>  rP   r,  r?  list[dict[str, t.Any]])NNN)rf  rJ  rg  z
int | Noner?  rJ  )rO  rJ  rW   r   r?  rD  )rM   rM   N)r   r   r?  list[tuple[int, MidiEvent]])r  rK  r?  zlist[TimedNoteEvent])rb   rK  rP   r,  r?  zdict[int, str])rb   rK  rP   r,  r?  z$list[tuple[int, base.Music21Object]])r  stream.Partr  rL  r  r>  )r?   r,   r  zstream.Part | Noner  r>  r  zSequence[int]rP   r,  r?  rL  )r?  rI  )r~   rI  r?  rL  )r~   rI  r  list[int] | Noner?  z'tuple[dict[int | None, int], list[int]])r  zlist[stream.Part]rP   r,  r?  dict[int, dict[str, t.Any]])r  rN  rP  zdict[int | None, int | None]r?  None)
r  zlist[MidiTrack]r?   r,   r   zstream.Score | NonerP   r,  r?  zstream.Score)r   rI  rB   r>  ri   r>  r  rM  rP   r,  r?  r   )rP   r,  )rM   i  N)r?  r   )r  r   rP   r,  )q__doc__
__future__r   collections.abcr   ry   r  typingrw   r   music21r   r   music21.common.numberToolsr   r   r
   r   r   r   r   music21.instrumentr   r   r   r   r   r   r   r   r   r   r   music21.midi.baser   r   r   r   r   r    r!   r"   r#   music21.midi.percussionr$   r%   r  r&   music21.common.typesr'   Environmentr-  r   TypeVarr   r(   
NamedTupler+   Music21Exceptionr8   UserWarningr<   rD   rH   r?   rL   rg   rp   r   r   r   r   r   r   r   r`   
deprecatedr   r   r   r  r  r  r'  r.  r5  r:  rH  rd  rj  rn  rr  r}  r  r  r  r  r  r  r  r  r  r  r  r  rv   r%  r6  r:  r#  
_DOC_ORDERr0   mainTestr4   r5   r6   <module>rb     s   # $       -        J J           N ??/ '{&&'78$& aiiT\\:Q\\ 	66 		{ 	:B< $3359777 37 	7~ !%04:
 ::: .:
 : :| !%% %% % 	%\ 3%3
 3 3F	
 
 # @ $33f0"f0f0 f0X "i&i i 	i
 i i` $33w+ww wz "zz z 	z
 z zz$ " $	#  	D 5%!cd 	;.	; 	; 		; e	; UU U 	Up4n8v8z << <~* I(I $Ih $(15777 7 
!	7
 /7 7x 222 $2n 	NNN N 	N
 Nf  	bN #& D# >Y] @22 2jC,CCR '  	: -'- - *	-f 	AAA 	A2 $33&*+-Q Q $Q Q )Q Q Qh7tCP -1x0x0)x0 +x0| 	c$c 	c
 !cL...1. 
.F \B $33"&	- ---  	- - -f  ,033 3 	3
 *3 3 3r 	!R 	!RJ Q 	Qh,D ;;
 ;~  01
 zG r5   