§
    ƒØj¼*  ã                  ó   — d Z ddlmZ ddlmZ ddlm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  G d
„ de¦  «        Z G d„ d¦  «        Z G d„ dej        ¦  «        Z G d„ dej        ¦  «        Zedk    rddlZ ej        e¦  «         dS dS )a‰  
Objects for realtime playback of Music21 Streams as MIDI.

From an idea of Joe "Codeswell":

https://joecodeswell.wordpress.com/2012/06/13/how-to-produce-python-controlled-audio-output-from-music-made-with-music21

https://stackoverflow.com/questions/10983462/how-can-i-produce-real-time-audio-output-from-music-made-with-music21

Requires pygame 2 (or 1.9) install with: pip3 install pygame
é    )Úannotations)Ú	find_spec)ÚBytesION)Údefaults)ÚMusic21Exception)Ústream)Ú	translatec                  ó   — e Zd ZdS )ÚStreamPlayerExceptionN©Ú__name__Ú
__module__Ú__qualname__© ó    úŠ/Users/tedpeters/Documents/Projects/Claude Projects/Misc Tools/notename-sheets/.venv/lib/python3.11/site-packages/music21/midi/realtime.pyr   r   "   ó   € € € € € Ø€Dr   r   c                  óˆ   — e Zd ZdZdZ	 	 	 	 	 ddd„Z	 	 	 	 	 d ed¦  «        ddœd„Zd„ Z	 	 d ed¦  «        ddœd„Z	d„ Z
dS )ÚStreamPlayera)  
    Create a player for a stream that plays its midi version in realtime using pygame.

    Set up a detuned piano (where each key has a random but
    consistent detuning from 30 cents flat to sharp)
    and play a Bach Chorale on it in real time.

    >>> import random
    >>> keyDetune = []
    >>> for i in range(127):
    ...    keyDetune.append(random.randint(-30, 30))

    >>> #_DOCS_SHOW b = corpus.parse('bwv66.6')
    >>> #_DOCS_SHOW for n in b.flatten().notes:
    >>> class PitchMock: midi = 20  #_DOCS_HIDE
    >>> class Mock: pitch = PitchMock()  #_DOCS_HIDE
    >>> #_DOCS_HIDE -- should not play back in doctests, see TestExternal
    >>> n = Mock()  #_DOCS_HIDE
    >>> for i in [1]:  #_DOCS_HIDE
    ...    n.pitch.microtone = keyDetune[n.pitch.midi]
    >>> #_DOCS_SHOW sp = midi.realtime.StreamPlayer(b)
    >>> #_DOCS_SHOW sp.play()

    The stream is stored (unaltered) in `StreamPlayer.streamIn`, and can be changed any time the
    midi file is not playing.

    A number of mixer controls can be passed in with keywords:

    *  mixerFreq (default 44100 -- CD quality)
    *  mixerBitSize (default -16 (=unsigned 16bit) --
         really, are you going to do 24bit audio with Python?? :-)  )
    *  mixerChannels (default 2 = stereo)
    *  mixerBuffer (default 1024 = number of samples)
    FéD¬  éðÿÿÿé   é   ÚstreamInústream.StreamÚreinitMixerÚboolÚ	mixerFreqÚintÚmixerBitSizeÚmixerChannelsÚmixerBufferc                ó¸   — 	 dd l }|| _         n# t          $ r t          d¦  «        ‚w xY w| j        du s|r|j                             ||||¦  «         || _        d S )Nr   z,StreamPlayer requires pygame.  Install firstF)ÚpygameÚImportErrorr   ÚmixerInitializedÚmixerÚinitr   )Úselfr   r   r   r    r!   r"   r$   s           r   Ú__init__zStreamPlayer.__init__K   s‚   € ð	XàˆMˆMˆMØ ˆDŒKˆKøÝð 	Xð 	Xð 	XÝ'Ð(VÑWÔWÐWð	XøøøàÔ  EÐ)Ð)¨[Ð)ØŒL×Ò˜i¨°}ÀkÑRÔRÐRà ˆŒˆˆs   ‚ Ž(Né2   ÚinfT)ÚplayForMillisecondsÚblockedc          
     óh   — |                       ¦   «         }|                      ||||||||¬¦  «         dS )a  
        busyFunction is a function that is called with busyArgs when the music is busy every
        busyWaitMilliseconds.

        endFunction is a function that is called with endArgs when the music finishes playing.

        playForMilliseconds is the amount of time in milliseconds after which
        the playback will be automatically stopped.

        If blocked is False, the method will finish before ending the stream, allowing
        you to completely control whether to stop it. Ignore every other arguments
        )ÚbusyFunctionÚbusyArgsÚendFunctionÚendArgsÚbusyWaitMillisecondsr-   r.   N)ÚgetStringOrBytesIOFileÚplayStringIOFile)	r)   r0   r1   r2   r3   r4   r-   r.   ÚstreamStringIOFiles	            r   ÚplayzStreamPlayer.play_   sU   € ð* "×8Ò8Ñ:Ô:ÐØ×ÒÐ0Ø+7Ø'/Ø*5Ø&-Ø3GØ2EØ&-ð 	ñ 	/ô 	/ð 	/ð 	/ð 	/r   c                óz   — t          j        | j        ¦  «        }|                     ¦   «         }t	          |¦  «        S ©N)ÚmidiTranslateÚstreamToMidiFiler   Úwritestrr   )r)   ÚstreamMidiFileÚstreamMidiWrittens      r   r5   z#StreamPlayer.getStringOrBytesIOFile~   s5   € Ý&Ô7¸¼ÑFÔFˆØ*×3Ò3Ñ5Ô5ÐÝÐ(Ñ)Ô)Ð)r   c               ó  — | j         j                             ¦   «         }		 | j         j        j                             |¦  «         n-# | j         j        $ r}
t          d|› d|
› �¦  «        |
‚d}
~
ww xY w| j         j        j                             ¦   «          |sdS t          d|z  ¦  «        }| j         j         
                    ¦   «         }| j         j        j                             ¦   «         rŽ|� ||¦  «         | j         j         
                    ¦   «         |z
  |k    r$| j         j        j                             ¦   «          n8|	                     |¦  «         | j         j        j                             ¦   «         °Ž|� ||¦  «         dS dS )a'  
        busyFunction is a function that is called with busyArgs when the music is busy every
        busyWaitMilliseconds.

        endFunction is a function that is called with endArgs when the music finishes playing.

        playForMilliseconds is the amount of time in milliseconds after which the
        playback will be automatically stopped.

        If blocked is False, the method will finish before ending the stream, allowing you to
        completely control whether to stop it. Ignore every other arguments but for stringIOFile
        zCould not play music file z
 because: Néè  )r$   ÚtimeÚClockr'   ÚmusicÚloadÚerrorr   r8   r   Ú	get_ticksÚget_busyÚstopÚtick)r)   ÚstringIOFiler0   r1   r2   r3   r4   r-   r.   ÚpygameClockÚpgeÚ	framerateÚ
start_times                r   r6   zStreamPlayer.playStringIOFileƒ   s¥  € ð  ”kÔ&×,Ò,Ñ.Ô.ˆð	ØŒKÔÔ#×(Ò(¨Ñ6Ô6Ð6Ð6øØŒ{Ô ð 	ð 	ð 	Ý'ØJ¨\ÐJÐJÀSÐJÐJñô àðøøøøð	øøøð 	ŒÔÔ×$Ò$Ñ&Ô&Ð&Øð 	ØˆFÝ˜Ð3Ñ3Ñ4Ô4ˆ	Ø”[Ô%×/Ò/Ñ1Ô1ˆ
ØŒkÔÔ%×.Ò.Ñ0Ô0ð 	(ØÐ'Ø�˜XÑ&Ô&Ð&ØŒ{Ô×)Ò)Ñ+Ô+¨jÑ8Ð;NÒNÐNØ”Ô!Ô'×,Ò,Ñ.Ô.Ð.ØØ×Ò˜YÑ'Ô'Ð'ð ŒkÔÔ%×.Ò.Ñ0Ô0ð 	(ð Ð"ØˆK˜Ñ Ô Ð Ð Ð ð #Ð"s    $A ÁA/ÁA*Á*A/c                óL   — | j         j        j                             ¦   «          d S r:   )r$   r'   rD   rI   )r)   s    r   rI   zStreamPlayer.stopª   s"   € ØŒÔÔ×$Ò$Ñ&Ô&Ð&Ð&Ð&r   )Fr   r   r   r   )r   r   r   r   r   r   r    r   r!   r   r"   r   )NNNNr+   )r   r   r   Ú__doc__r&   r*   Úfloatr8   r5   r6   rI   r   r   r   r   r   &   sæ   € € € € € ð!ð !ðD Ðð
 "ØØØØð!ð !ð !ð !ð !ð* ØØØØ"$ð/ð "'  u¡¤Øð/ð /ð /ð /ð /ð>*ð *ð *ð
 JNØNPð%!ð .3¨U°5©\¬\À4ð%!ð %!ð %!ð %!ð %!ðN'ð 'ð 'ð 'ð 'r   r   c                  ó   — e Zd ZdS )ÚTestNr   r   r   r   rT   rT   ®   r   r   rT   c                  óx   — e Zd Z ed¦  «        Ze�dZndZ ej        ed¦  «        d„ ¦   «         Zd„ Z	d„ Z
d	„ ZdS )
ÚTestExternalr$   NTFzpygame is not installedc                ót  — ddl m} dd l}|                     d¦  «        }g }t	          d¦  «        D ]+}|                     |                     dd¦  «        ¦  «         Œ,|                     ¦   «         j        D ]}||j	        j
                 |j	        _        Œt          |¦  «        }|                     ¦   «          d S )Nr   ©Úcorpusúbwv66.6é   éâÿÿÿé   )Úmusic21rY   ÚrandomÚparseÚrangeÚappendÚrandintÚrecurseÚnotesÚpitchÚmidiÚ	microtoner   r8   )r)   rY   r_   ÚbÚ	keyDetuneÚiÚnÚsps           r   ÚtestBachDetunezTestExternal.testBachDetune¹   s¹   € à"Ð"Ð"Ð"Ð"Ð"ØˆˆˆØ�LŠL˜Ñ#Ô#ˆØˆ	Ý�s‘”ð 	6ð 	6ˆAØ×Ò˜VŸ^š^¨C°Ñ4Ô4Ñ5Ô5Ð5Ð5Ø—’‘”Ô"ð 	8ð 	8ˆAØ )¨!¬'¬,Ô 7ˆAŒGÔÐÝ˜!‰_Œ_ˆØ
�Š‰	Œ	ˆ	ˆ	ˆ	r   c                óÀ  — ddl m} ddl}d„ } G d„ d¦  «        } |¦   «         }d|_        |                     d¦  «        }g }t          d	¦  «        D ]+}|                     |                     d
d¦  «        ¦  «         Œ,|                     ¦   «         j	        D ]}	||	j
        j                 |	j
        _        Œt          |¦  «        }
|
                     ||gd¬¦  «         dS )zN
        tests to see if the busyCallback function is called properly
        r   rX   Nc                óp   — | d         }|xj         |j        z  c_         t          d|j         › d�¦  «         d S )Nr   zhi! waited z milliseconds)ÚtimesÚ
updateTimeÚprint)ÚtimeListÚtimeCounter_inners     r   ÚbusyCounterz4TestExternal.x_testBusyCallback.<locals>.busyCounter×   sH   € Ø (¨¤ÐØÐ#Ô#Ð'8Ô'CÑCÐ#Ô#ÝÐFÐ 1Ô 7ÐFÐFÐFÑGÔGÐGÐGÐGr   c                  ó   — e Zd ZdZdS )ú-TestExternal.x_testBusyCallback.<locals>.Mockr   N)r   r   r   rq   r   r   r   ÚMockrx   Ü   s   € € € € € ØˆEˆEˆEr   ry   éô  zbach/bwv66.6r[   r\   r]   ©r0   r1   r4   )r^   rY   r_   rr   r`   ra   rb   rc   rd   re   rf   rg   rh   r   r8   )r)   rY   r_   rv   ry   ÚtimeCounterri   rj   rk   rl   rm   s              r   Úx_testBusyCallbackzTestExternal.x_testBusyCallbackÐ   s  € ð 	#Ð"Ð"Ð"Ð"Ð"Øˆˆˆð	Hð 	Hð 	Hð
	ð 	ð 	ð 	ð 	ñ 	ô 	ð 	ð �d‘f”fˆØ!$ˆÔà�LŠL˜Ñ(Ô(ˆØˆ	Ý�s‘”ð 	6ð 	6ˆAØ×Ò˜VŸ^š^¨C°Ñ4Ô4Ñ5Ô5Ð5Ð5Ø—’‘”Ô"ð 	8ð 	8ˆAØ )¨!¬'¬,Ô 7ˆAŒGÔÐÝ˜!‰_Œ_ˆØ
�Š˜[°K°=ÐWZˆÑ[Ô[Ð[Ð[Ð[r   c                ó˜  — ddl m} dt          _        |                     d¦  «        }g }t          |j        d                              t          j	        ¦  «        ¦  «        }t          |¦  «        D ]*}|                     |                     |¦  «        ¦  «         Œ+t          |¦  «        }|D ]}||_        |                     ¦   «          Œd S )Nr   rX   rZ   )r^   rY   r   ÚticksAtStartr`   ÚlenÚpartsÚgetElementsByClassr   ÚMeasurera   rb   Úmeasurer   r   r8   )r)   rY   ri   ÚmeasuresÚ
maxMeasurerk   rm   r„   s           r   Úx_testPlayOneMeasureAtATimez(TestExternal.x_testPlayOneMeasureAtATimeë   sÅ   € Ø"Ð"Ð"Ð"Ð"Ð"Ø !�ÔØ�LŠL˜Ñ#Ô#ˆØˆÝ˜œ œ×6Ò6µv´~ÑFÔFÑGÔGˆ
Ý�zÑ"Ô"ð 	*ð 	*ˆAØ�OŠO˜AŸIšI a™LœLÑ)Ô)Ð)Ð)Ý˜!‰_Œ_ˆàð 	ð 	ˆGØ!ˆBŒKØ�GŠG‰IŒIˆIˆIð	ð 	r   c                óF  ‡‡‡— ddl mŠ ddlŠˆˆfd„Šˆfd„} G d„ d¦  «        } |¦   «         } ‰¦   «         }t          |¦  «        }|                     ¦   «         |_        |j        dk    r4d|_        |                     |j        |||gd	¬
¦  «         |j        dk    °2dS dS )zf
        doesn't work -- no matter what there's always at least a small lag, even with queues
        r   )ÚnoteNc                 ó,  •— t          j        ¦   «         } t          d¦  «        D ]F}‰                     ¦   «         }‰                     dd¦  «        |_        |                      |¦  «         ŒG‰                     ¦   «         }|                      |¦  «         | S )Né   é0   éH   )r   ÚStreamra   ÚNoterc   Úpsrb   )Úsrk   rl   ÚlastNr‰   r_   s       €€r   ÚgetRandomStreamz8TestExternal.x_testPlayRealTime.<locals>.getRandomStream  sw   ø€ Ý”‘”ˆAÝ˜1‘X”Xð ð �Ø—I’I‘K”K�Ø—~’~ b¨"Ñ-Ô-�”Ø—’˜‘”��Ø—I’I‘K”KˆEà�HŠH�U‰OŒOˆOØˆHr   c                ó”  •— | d         }| d         }|j         j        j                             ¦   «         }|dcxk     r|j        k    rzn nw|xj        dz  c_        |j        dk    rZ ‰¦   «         |_        |                     ¦   «         |_        |j         j        j         	                    |j        ¦  «         ||_        d S d S ||_        d S )Nr   é   rz   )
r$   r'   rD   Úget_posÚlastPosrq   r   r5   ÚstoredIOFileÚqueue)rt   r|   ÚstreamPlayerÚ
currentPosr“   s       €r   ÚrestoreListz4TestExternal.x_testPlayRealTime.<locals>.restoreList  sà   ø€ Ø" 1œ+ˆKØ# Aœ;ˆLØ%Ô,Ô2Ô8×@Ò@ÑBÔBˆJØ˜CÐ6Ð6Ò6Ð6 ;Ô#6Ò6Ð6Ð6Ð6Ð6ØÐ!Ô! QÑ&Ð!Ô!ØÔ$ qÒ(Ð(Ø,;¨OÑ,=Ô,=�LÔ)à/;×/RÒ/RÑ/TÔ/T�KÔ,Ø Ô'Ô-Ô3×9Ò9¸+Ô:RÑSÔSÐSØ*4�KÔ'Ð'Ð'ð )Ð(ð '1�Ô#Ð#Ð#r   c                  ó   — e Zd ZdZdZdZdS )ú3TestExternal.x_testPlayRealTime.<locals>.TimePlayerFé   rA   N)r   r   r   Úreadyrq   r—   r   r   r   Ú
TimePlayerrž     s   € € € € € ØˆEØˆEØˆGˆGˆGr   r¡   Fr]   r{   )	r^   r‰   r_   r   r5   r˜   rq   r    r6   )	r)   rœ   r¡   r|   ri   rm   r“   r‰   r_   s	         @@@r   Úx_testPlayRealTimezTestExternal.x_testPlayRealTimeù   s  øøø€ ð
 	!Ð Ð Ð Ð Ð Øˆˆˆð		ð 		ð 		ð 		ð 		ð 		ð	1ð 	1ð 	1ð 	1ð 	1ð	ð 	ð 	ð 	ð 	ñ 	ô 	ð 	ð
 !�j‘l”lˆàˆOÑÔˆÝ˜!‰_Œ_ˆØ#%×#<Ò#<Ñ#>Ô#>ˆÔ ØÔ !Ò#Ð#Ø %ˆKÔØ×Ò Ô 8Ø-8Ø*5°rÐ):Ø57ð  ñ 9ô 9ð 9ð Ô !Ò#Ð#Ð#Ð#Ð#Ð#r   )r   r   r   r   ÚloaderÚpygame_installedÚunittestÚ
skipUnlessrn   r}   r‡   r¢   r   r   r   rV   rV   ²   s”   € € € € € ØˆY�xÑ Ô €FØÐØÐÐà Ðà€XÔÐ)Ð+DÑEÔEð
ð 
ñ FÔEð
ð,\ð \ð \ð6ð ð ð29ð 29ð 29ð 29ð 29r   rV   Ú__main__)rQ   Ú
__future__r   Úimportlib.utilr   Úior   r¥   r^   r   Úmusic21.exceptions21r   r   Úmusic21.midir	   r;   r   r   ÚTestCaserT   rV   r   ÚmainTestr   r   r   ú<module>r¯      sŽ  ðð
ð 
ð #Ð "Ð "Ð "Ð "Ð "à $Ð $Ð $Ð $Ð $Ð $Ø Ð Ð Ð Ð Ð Ø €€€à Ð Ð Ð Ð Ð Ø 1Ð 1Ð 1Ð 1Ð 1Ð 1Ø Ð Ð Ð Ð Ð à 3Ð 3Ð 3Ð 3Ð 3Ð 3ð	ð 	ð 	ð 	ð 	Ð,ñ 	ô 	ð 	ðE'ð E'ð E'ð E'ð E'ñ E'ô E'ð E'ðP	ð 	ð 	ð 	ð 	ˆ8Ôñ 	ô 	ð 	ðy9ð y9ð y9ð y9ð y9�8Ô$ñ y9ô y9ð y9ðx ˆzÒÐØ€N€N€NØ€GÔ�\Ñ"Ô"Ð"Ð"Ð"ð Ðr   