
    ̺i=:                        S r SSKrSSKrSSKrSSKJr  SSKJrJr  SSK	J
r
JrJrJr  SSKJrJrJr  SS	KJr  S
rSrSrSS jr " S S5      rS rS rS S jrS rS rS!S jrS!S jrS r S r!S"S jr"S r#S r$S r% " S S5      r&g)#a  
MIDI file reading and playback.

References:

http://home.roadrunner.com/~jgglatt/
http://home.roadrunner.com/~jgglatt/tech/miditech.htm
http://home.roadrunner.com/~jgglatt/tech/midifile.htm

http://www.sonicspot.com/guide/midifiles.html
http://www.ccarh.org/courses/253/assignment/midifile/
https://code.google.com/p/binasc/wiki/mainpage
http://stackoverflow.com/questions/2984608/midi-delta-time
http://www.recordingblogs.com/sa/tabid/82/EntryId/44/MIDI-Part-XIII-Delta-time-a
http://www.sonicspot.com/guide/midifiles.html
    N)Integral   )SPEC_BY_STATUSMessage   )MetaMessagebuild_meta_messageencode_variable_intmeta_charset)	MidiTrackfix_end_of_trackmerge_tracks)tick2secondi  i  i@B c                     [        U 5      nUR                  5       (       d  U[        R                  ;  a  Sn[	        SUS SU S SU 35        g )N.  06xz: 02x)chrisspacestring	printableprint)byteposchars      W/var/www/piano.thomer.com/venv/lib/python3.13/site-packages/mido/midifiles/midifiles.py
print_byter   )   sG    t9D||~~V%5%55	Bs3ir$s2dV
,-    c                   &    \ rS rSrS rS rS rSrg)DebugFileWrapper1   c                     Xl         g Nfile)selfr&   s     r   __init__DebugFileWrapper.__init__2   s    	r   c                     U R                   R                  U5      nU H&  n[        X0R                   R                  5       5        M(     U$ r$   )r&   readr   tell)r'   sizedatar   s       r   r+   DebugFileWrapper.read5   s8    yy~~d#DtYY^^-.  r   c                 6    U R                   R                  5       $ r$   )r&   r,   r'   s    r   r,   DebugFileWrapper.tell=   s    yy~~r   r%   N)__name__
__module____qualname____firstlineno__r(   r+   r,   __static_attributes__ r   r   r!   r!   1   s     r   r!   c                 R    U R                  S5      nUS:X  a  [        e[        U5      $ )Nr   r   )r+   EOFErrorord)r'   r   s     r   	read_byter<   A   s%    99Q<Ds{4yr   c                     U[         :  a  [        SR                  U[         5      5      e[        U5       Vs/ s H  n[	        U 5      PM     sn$ s  snf )Nz+Message length {} exceeds maximum length {})MAX_MESSAGE_LENGTHOSErrorformatranger<   )infiler-   _s      r   
read_bytesrD   I   sM      CJJ$& ' 	'',T{3{!If{333s   Ac                     [        U 5        g r$   )r   )texts    r   _dbgrG   P   s	    	$Kr   c                 |    U R                  S5      n[        U5      S:  a  [        e[        R                  " SU5      $ )N   z>4sL)r+   lenr:   structunpack)rB   headers     r   read_chunk_headerrN   \   s2    [[^F
6{Q ==((r   c                     [        U 5      u  pUS:w  a  [        S5      eU R                  U5      n[        U5      S:  a  [        e[
        R                  " SUS S 5      $ )N   MThdz(MThd not found. Probably not a MIDI file   >hhh)rN   r?   r+   rJ   r:   rK   rL   )rB   namer-   r.   s       r   read_file_headerrT   f   sV    "6*JDw@AA{{4 t9q=N}}VT"1X..r   c                 P    [         U   nUS   S-
  [        U5      -
  nU[	        X5      -   nU(       a  U V	s/ s H  oS:  a  U	OSPM     nn	OU H  n	U	S:  d  M  [        S5      e   [
        R                  " U/U-   US9$ ! [         a  n[        SUS 35      UeS nAff = fs  sn	f )Nzundefined status byte 0xr   lengthr      z!data byte must be in range 0..127time)r   LookupErrorr?   rJ   rD   r   
from_bytes)
rB   status_byte	peek_datadeltaclipspecler-   
data_bytesr   s
             r   read_messagerc   t   s    Lk*
 >AI.DZ55J>HIjdSjdc1j
I
DczABB  {mj8uEE  L0S0ABCKL Js   	B B#
B BB c                     [        U 5      n[        X5      nU(       a  US   S:X  a  USS  nU(       a  US   S:X  a  US S nU(       a  U Vs/ s H  oUS:  a  UOSPM     nn[        SXAS9$ s  snf )	Nr      r      rW   sysex)r.   rY   )read_variable_intrD   r   )rB   r^   r_   rV   r.   r   s         r   
read_sysexrj      s{    v&Ff%D Q4ABxRD CRy8<=s
+=722 >s   A+c                 H    Sn [        U 5      nUS-  US-  -  nUS:  a  U$ M   )Nr      rW      )r<   )rB   r^   r   s      r   ri   ri      s7    E
 !t,$;L	 r   c                 \    [        U 5      n[        U 5      n[        X5      n[        X$U5      $ r$   )r<   ri   rD   r	   )rB   r^   	meta_typerV   r.   s        r   read_meta_messagerp      s-    &!Iv&Ff%Diu55r   c                 v   [        5       n[        U 5      u  pEUS:w  a  [        S5      eU(       a  [        SU 35        [        5         U R	                  5       nS n U R	                  5       U-
  U:X  a   U$ U(       a  [        S5        [        U 5      nU(       a  [        SU 35        [        U 5      n	U	S:  a  Uc  [        S5      eU	/n
Un	O
U	S:w  a  U	n/ n
U	S:X  a  [        X5      nO U	S	;   a  [        XU5      nO[        X	XU5      nUR                  U5        U(       a  [        S
U< 35        [        5         M  )N   MTrkz no MTrk header at start of trackz-> size=zMessage:z	-> delta=rm   z"running status without last_status   )re   rg   z-> )r   rN   r?   rG   r,   ri   r<   rp   rj   rc   append)rB   debugr_   trackrS   r-   startlast_statusr^   r\   r]   msgs               r   
read_trackrz      s:   KE"6*JDw899xvKKMEK
;;=5 D(L LI !&)9UG$%'"BCC$I%Kd")I$#F2CL( VD1CvIdKCS3sgFO r   c                     U R                  U5        U R                  [        R                  " S[        U5      5      5        U R                  U5        g)z=Write an IFF chunk to the file.

`name` must be a bytestring.z>LN)writerK   packrJ   )outfilerS   r.   s      r   write_chunkr      s7     MM$MM&++dCI./MM$r   c                 n   [        5       nS n[        U5       GH  n[        UR                  [        5      (       d  [        S5      eUR                  S:  a  [        S5      eUR                  (       a  [        S5      eUR                  [        UR                  5      5        UR                  (       a#  UR                  UR                  5       5        S nM  UR                  S:X  ar  UR                  S5        UR                  [        [        UR                  5      S-   5      5        UR                  UR                  5        UR                  S5        S nGM?  UR                  5       nUS   nXc:X  a  UR                  USS  5        OUR                  U5        US:  a  UnGM  S nGM     [        U S	U5        g )
Nz%message time must be int in MIDI filer   z.message time must be non-negative in MIDI filez/realtime messages are not allowed in MIDI filesrh   re   r   rg   rr   )	bytearrayr   
isinstancerY   r   
ValueErroris_realtimeextendr
   is_metabytestypert   rJ   r.   r   )r~   rv   r.   running_status_bytery   	msg_bytesr\   s          r   write_trackr      sO   ;D&#((H--DEE88a<MNN??NOO'12;;KK		$"&XX KKKK+CMA,=>?KK!KK"&		I#A,K1IabM*I&T!&1#&*#C 'F $'r   c                     U S-  U-  $ )Ng    .Ar8   )tempoticks_per_beats     r   get_seconds_per_tickr     s     I//r   c                       \ rS rSrSSS\SSSS4S jr\S 5       r\R                  S 5       rSS	 jr	S
 r
\S 5       rS rS\R                  4S jrSS jrS rSS jrS rS rS rSrg)MidiFilei#  Nr   latin1Fc	                 t   Xl         X0l        X@l        XPl        X`l        Xpl        / U l        S U l        U[        S5      ;  a  [        S[         S35      eUb  Xl        g Ub  U R                  U5        g U R                   b'  [        US5       nU R                  U5        S S S 5        g g ! , (       d  f       g = f)N   zinvalid format z (must be 0, 1 or 2)rb)filenamer   r   charsetru   r_   tracks_merged_trackrA   r   r@   _loadopen)	r'   r   r&   r   r   r   ru   r_   r   s	            r   r(   MidiFile.__init__$  s     !	,
	!uQx!&)=>@ @  KJJt]]&h%

4  &% '%%s   B))
B7c                     U R                   S:X  a  [        S5      eU R                  c  [        U R                  SS9U l        U R                  $ )Nr   z0can't merge tracks in type 2 (asynchronous) fileT)skip_checks)r   	TypeErrorr   r   r   r1   s    r   merged_trackMidiFile.merged_trackB  sF     99>NOO%!-dkkt!LD!!!r   c                     S U l         g r$   )r   r1   s    r   r   r   M  s
    !r   c                 f    [        5       nUb  Xl        U R                  R                  U5        U ?U$ )zgAdd a new track to the file.

This will create a new MidiTrack object and append it to the
track list.
)r   rS   r   rt   r   )r'   rS   rv   s      r   	add_trackMidiFile.add_trackQ  s3     J5!r   c           
      l   U R                   (       a  [        U5      n[        U R                  5         U R                   (       a  [	        S5        [        U5      u  U l        nU l        U R                   (       a9  [	        SR                  U R                  X R                  5      5        [	        5         [        U5       H[  nU R                   (       a  [	        SU S35        U R                  R                  [        UU R                   U R                  S95        M]     S S S 5        g ! , (       d  f       g = f)NzHeader:z(-> type={}, tracks={}, ticks_per_beat={}zTrack :)ru   r_   )ru   r!   r   r   rG   rT   r   r   r@   rA   r   rt   rz   r_   )r'   rB   
num_tracksis       r   r   MidiFile._load^  s    ::%f-F$,,'zzY %5V$<"TY zz?FFIIz+>+>@ A:&::6!A'"":f48JJ3799$> ?	 ' (''s   C*D%%
D3c                 \    U R                   S:X  a  [        S5      e[        S U  5       5      $ )zzPlayback time in seconds.

This will be computed by going through every message in every
track and adding up delta times.
r   z;impossible to compute length for type 2 (asynchronous) filec              3   8   #    U  H  oR                   v   M     g 7fr$   rX   ).0ry   s     r   	<genexpr>"MidiFile.length.<locals>.<genexpr>  s     ,t88t   )r   r   sumr1   s    r   rV   MidiFile.lengthx  s6     99> ? @ @ ,t,,,r   c              #     #    [         nU R                   Hg  nUR                  S:  a"  [        UR                  U R                  U5      nOSnUR                  SUS9v   UR                  S:X  d  M[  UR                  nMi     g 7f)Nr   T)r   rY   	set_tempo)DEFAULT_TEMPOr   rY   r   r   copyr   r   )r'   r   ry   r^   s       r   __iter__MidiFile.__iter__  sl     $$C xx!|#CHHd.A.A5I((t%(88xx;&		 %s   A*B0Bc              #      #    U" 5       nSnU  H]  nXER                   -  nU" 5       U-
  nXF-
  nUS:  a  [         R                  " U5        [        U[        5      (       a	  U(       d  MY  Uv   M_     g7f)a  Play back all tracks.

The generator will sleep between each message by
default. Messages are yielded with correct timing. The time
attribute is set to the number of seconds slept since the
previous message.

By default you will only get normal MIDI messages. Pass
meta_messages=True if you also want meta messages.

You will receive copies of the original messages, so you can
safely modify them without ruining the tracks.

By default the system clock is used for the timing of yielded
MIDI events. To use a different clock (e.g. to synchronize to
an audio stream), pass now=time_fn where time_fn is a zero
argument function that yields the current time in seconds.
g        N)rY   sleepr   r   )r'   meta_messagesnow
start_time
input_timery   playback_timeduration_to_next_events           r   playMidiFile.play  sj     & U

C(("JEJ.M%/%?"%+

12#{++M	 s   A.A0c                     U R                   S:X  a$  [        U R                  5      S:w  a  [        S5      eUb  U R	                  U5        gUb'  [        US5       nU R	                  U5        SSS5        g[        S5      e! , (       d  f       g= f)a/  Save to a file.

If file is passed the data will be saved to that file. This is
typically an in-memory file or and already open file like sys.stdout.

If filename is passed the data will be saved to that file.

Raises ValueError if both file and filename are None,
or if a type 0 file has != one track.
r   r   z%type 0 file must have exactly 1 trackNwbzrequires filename or file)r   rJ   r   r   _saver   )r'   r   r&   s      r   saveMidiFile.save  sz     99>c$++.!3DEEJJt!h%

4  &% 899 &%s   A??
Bc                 8   [        U R                  5         [        R                  " SU R                  [        U R                  5      U R                  5      n[        USU5        U R                   H  n[        X5        M     S S S 5        g ! , (       d  f       g = f)NrR   rP   )
r   r   rK   r}   r   rJ   r   r   r   r   )r'   r~   rM   rv   s       r   r   MidiFile._save  si    $,,'[[!$T[[!1!%!4!46F &1G+ % (''s   A,B
Bc                     [        U R                  5       HG  u  p#[        SU 35        U H.  n[        U[        5      (       d	  U(       a  M!  [        U< 5        M0     MI     g)zPrints out all messages in a .midi file.

May take argument meta_only to show only meta messages.

Use:
print_tracks() -> will print all messages
print_tracks(meta_only=True) -> will print only MetaMessages
z
=== Track N)	enumerater   r   r   r   )r'   	meta_onlyr   rv   ry   s        r   print_tracksMidiFile.print_tracks  sM     "$++.HAJqc"#c;//yySG%  /r   c                    U R                   (       a>  SR                  S U R                    5       5      nSUR                  SS5      -   nSU S3nOSnS	R                  U R                  R
                  U R                  U R                  U5      $ )
Nz,
c              3   8   #    U  H  n[        U5      v   M     g 7fr$   )repr)r   rv   s     r   r   $MidiFile.__repr__.<locals>.<genexpr>  s     #I[EDKK[r   r   
z
  z, tracks=[
z
] z {}(type={}, ticks_per_beat={}{}))r   joinreplacer@   	__class__r3   r   r   )r'   
tracks_strs     r   __repr__MidiFile.__repr__  s~    ;;#IT[[#IIJ
 2 24 @@J'
|37JJ188NN##II	
 	
r   c                     U $ r$   r8   r1   s    r   	__enter__MidiFile.__enter__  s    r   c                     g)NFr8   )r'   r   value	tracebacks       r   __exit__MidiFile.__exit__  s    r   )r   r   r_   ru   r   r   r   r   r$   )NNF)r3   r4   r5   r6   DEFAULT_TICKS_PER_BEATr(   propertyr   deleterr   r   rV   r   rY   r   r   r   r   r   r   r   r7   r8   r   r   r   r   #  s     $4(>!!< " " " "?4 
- 
-" "'DII "H:,	,&
"r   r   )r   )r   r   )FF)'__doc__r   rK   rY   numbersr   messagesr   r   metar   r	   r
   r   r   r   r   r   unitsr   r   r   r>   r   r!   r<   rD   rG   rN   rT   rc   rj   ri   rp   rz   r   r   r   r   r8   r   r   <module>r      s   
"     . T T = =     .    4)/F(3"68v'(T0Z Zr   