B
    £ �aº[  ã               @   s�   d Z ddlZddlmZ ddlmZmZ ddlZdZdZ	e	e Z
dZdZd	d
ddddddddddddddddœZG dd„ dƒZG dd„ dƒZdS )z­
A Python library for interfacing with SooperLooper.

Tracks full state and provides interface to all loop commands. Almost a complete client, just missing saving sessions.
é    N)Ú
namedtuple)ÚEventÚLock) Ú
rec_threshÚfeedbackÚdryÚwetÚ
input_gainÚrateÚscratch_posÚdelay_triggerÚquantizeÚroundÚredo_is_tapÚsyncÚplayback_syncÚuse_rateÚfade_samplesÚuse_feedback_playÚuse_common_insÚuse_common_outsÚrelative_syncÚuse_safety_feedbackÚpan_1Úpan_2Úpan_3Úpan_4Úinput_latencyÚoutput_latencyÚtrigger_latencyÚautoset_latencyÚmute_quantizedÚoverdub_quantizedÚpitch_shiftÚstretch_ratio)ÚstateÚ
next_stateÚloop_lenÚloop_posÚ	cycle_lenÚ	free_timeÚ
total_timeÚrate_outputÚchannel_countÚin_peak_meterÚout_peak_meterÚ	is_soloedÚwaiting)ÚrecordZoverdubZmultiplyÚinsertÚreplaceÚreverseZmuteÚundoÚredoZoneshotÚtriggerÚ
substituteZundo_allZredo_allZmute_onZmute_offZsoloÚpauseZ	solo_nextZ	solo_prevZrecord_soloZrecord_solo_nextZrecord_solo_prevZset_sync_posZreset_sync_posscratch)ÚtempoÚeighth_per_cycler   r   r	   Úsync_sourceÚ	tap_tempoÚ	save_loopÚauto_disable_latencyÚselect_next_loopÚselect_prev_loopÚselect_all_loopsÚselected_loop_numÚunknownÚOffZ	WaitStartZ	RecordingZWaitStopZPlayingZOverdubbingZMultiplyingZ	InsertingZ	ReplacingÚDelayZMutedZ
ScratchingZOneShotZ
SubstituteÚPausedzOff and muted)éÿÿÿÿr   é   é   é   é   é   é   é   é   é	   é
   é   é   é   é   é   c                   sF  e Zd ZdZdEdd„Zdd„ Z‡ fd	d
„Zdd„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ Zd#d$„ ZdFd&d'„Zd(d)„ Zd*d+„ Zd,d-„ Zed.d/„ ƒZejd0d/„ ƒZed1d2„ ƒZejd3d2„ ƒZed4d5„ ƒZed6d7„ ƒZejd8d7„ ƒZd9d:„ Zd;d<„ Zd=d>„ Z d?d@„ Z!dAdB„ Z"dCdD„ Z#‡  Z$S )GÚLooperThreadzó
    Handles I/O with SooperLooper via OSC. Organizes loops.

    Uses a threaded liblo server to register for updates and automatically track looper and loop state.

    See documentation here: http://essej.net/sooperlooper/doc_osc.html

    éÞ&  éß&  Fc             C   s\   || _ || _|| _t | j ¡| _tƒ | _d| _g | _	g | _
g | _g | _g | _g | _g | _d S )Nr   )ÚportÚsl_portÚverboseÚlibloZServerThreadÚserverr   Ú	ping_flagÚ
loop_countÚloopsÚloop_callbacksÚlooper_callbacksÚping_callbacksÚloop_added_callbacksÚloop_removed_callbacksÚmidi_binding_callbacks)Úselfr\   r]   r^   © rk   ú/home/debian/UI/dooper.pyÚ__init__�   s    zLooperThread.__init__c             C   s   d  | j| j| j¡S )Nz-LooperThread(port={}, sl_port={}, verbose={}))Úformatr\   r]   r^   )rj   rk   rk   rl   Ú__repr__¢   s    zLooperThread.__repr__c                s<   |dkrt ƒ  ||¡ n |tkr.|  ||¡ n
|| j|< d S )N)r=   r   rD   )ÚsuperÚ__setattr__Úlooper_parametersÚsetÚ__dict__)rj   ÚnameÚval)Ú	__class__rk   rl   rq   ¦   s
    zLooperThread.__setattr__c             C   s„   t  dg¡ | j dd | j¡ | j dd | j¡ | j dd | j¡ | j dd | j¡ | j dd | j¡ | j 	¡  |  
¡  |  ¡  d S )Nz/usr/bin/sooperlooperz/sl/pingz/sl/loopz
/sl/looperz/sl/loop_numz/sl/midi_bindings)Ú
subprocessÚPopenr`   Z
add_methodÚping_responderÚloop_responderÚlooper_responderÚloop_num_responderÚmidi_binding_responderÚstartÚ
initializeÚregister_updates)rj   rk   rk   rl   Ústart_server°   s    
zLooperThread.start_serverc             C   sf   | j  dd ¡ | j  dd ¡ | j  dd ¡ | j  dd ¡ | j  dd ¡ |  d¡ |  ¡  | j  ¡  d S )Nz/sl/pingz/sl/loopz
/sl/looperz/sl/loop_numz/sl/midi_bindingsz/quit)r`   Z
del_methodÚsend_oscÚunregister_updatesÚstop)rj   rk   rk   rl   Ústop_server¾   s    
zLooperThread.stop_serverc             C   sÜ   d| _ g | _d}x(|  ¡ s8|d }|dkrtdƒ d S qW x tD ]}|  d|| jjd¡ q@W |  dd| jjd¡ |  dd	| jjd¡ | j rÐxLt| j ƒD ]4}| j 	t
| |ƒ¡ xtD ]}| j|  |¡ q²W q–W ntd
ƒ d S )Nr   rJ   é2   zNo ping reply from SooperLooperz/getz
/sl/looperz	/sl/0/getr   r   zLoop count is zero)rb   rc   ÚpingÚprintrr   rƒ   r`   ÚurlÚrangeÚappendÚLoopÚloop_parametersÚget)rj   ZattemptÚparamÚirk   rk   rl   r€   Ê   s$    


zLooperThread.initializec             G   s4   | j rtd ||¡ƒ t | jtj|f|žŽ ¡ d S )NzSending OSC message: {} {})r^   r‰   rn   r_   Úsendr]   ZMessage)rj   ÚpathÚargsrk   rk   rl   rƒ   å   s    zLooperThread.send_oscc             C   sF   | j rtd ||¡ƒ |d | _| j ¡  x| jD ]}||ƒ q2W d S )Nz ping Received OSC message: {} {}rK   )r^   r‰   rn   rb   ra   rs   rf   )rj   r“   r”   Úfrk   rk   rl   rz   ê   s    

zLooperThread.ping_responderc          	   C   s  | j rtd ||| jj¡ƒ | j}|d | _| j|kr¸xât|| jƒD ]n}| j t	| |ƒ¡ x| j
D ]}||ƒ qbW x>tD ]6}| j|  |¡ |  dt|ƒ d |d| jjd¡ qxW qDW nb| j|k �r| j}x| jD ]}||ƒ qÒW | j ¡  x,tD ]$}|  dt|ƒ d || jjd¡ qòW dS )	z- Listens for replies from SL about loop countz8loop num responder Received OSC message: {} {} server {}rK   z/sl/z/register_auto_updateéd   z/sl/loopz/unregister_auto_updateN)r^   r‰   rn   r`   rŠ   rb   r‹   rc   rŒ   r�   rg   rŽ   r�   rƒ   Ústrrh   Úpop)rj   r“   r”   Zprev_loop_countÚloop_numr•   r�   rk   rk   rl   r}   ô   s&    


,

zLooperThread.loop_num_responderc             C   s|   y| j |d  }W n tk
r&   dS X |dd… \}}| jrV|dkrVtd ||¡ƒ ||j|< x| jD ]}||ƒ qhW dS )zO Listens for replies from SL about loops, then updates loop object accordingly.r   NrJ   r(   z*loop responder Received OSC message: {} {})rc   Ú
IndexErrorr^   r‰   rn   rt   rd   )rj   r“   r”   ÚloopÚcontrolÚvaluer•   rk   rk   rl   r{     s    
zLooperThread.loop_responderc             C   sJ   | j rtd ||| jj¡ƒ |d | j|d < x| jD ]}||ƒ q6W dS )z6 Listens for replies from SL about looper global statez6looper responder Received OSC message: {} {} server {}rK   rJ   N)r^   r‰   rn   r`   rŠ   rt   re   )rj   r“   r”   r•   rk   rk   rl   r|   !  s
    zLooperThread.looper_responderc             C   sD   | j rtd ||| jj¡ƒ |d dkr@x| jD ]}||ƒ q0W dS )z0 Listens for replies from SL about midi bindingsz<midi binding responder Received OSC message: {} {} server {}r   ÚdoneN)r^   r‰   rn   r`   rŠ   ri   )rj   r“   r”   r•   rk   rk   rl   r~   +  s
    z#LooperThread.midi_binding_responderc             G   s4   dt |ƒ }|r |dt |ƒ 7 }| j|f|žŽ  d S )Nz/sl/ú/)r—   rƒ   )rj   Zpath1Zpath2r”   Úmessagerk   rk   rl   r’   8  s    zLooperThread.sendc             C   s   |   d||¡ d S )Nz/set)rƒ   )rj   rœ   r�   rk   rk   rl   rs   >  s    zLooperThread.setc          	   C   s’   x"t D ]}|  d|d| jjd¡ qW |  ddd| jjd¡ |  d| jjd¡ x@| jD ]6}x0tD ](}|  dt|jƒ d |d| jjd	¡ q^W qTW d
S )a»   Ask SL to updates us on changes to global and loop states. While the documentation indicates that register_update should trigger whenever any client updates an input control, in practice the auto variety seems necessary to catch changes not initiated from SL's frontend. Auto is always necessary for loop states. We pass a polling interval of 100ms, but this is actually fixed on the backend. Updates only fire if the value has been changed. z/register_auto_updater–   z
/sl/looperz/sl/0/register_auto_updater   z	/registerz/sl/loop_numz/sl/z/sl/loopN)rr   rƒ   r`   rŠ   rc   rŽ   r—   Únumber)rj   r�   r›   rk   rk   rl   r�   A  s    

zLooperThread.register_updatesc             C   sŒ   x t D ]}|  d|| jjd¡ qW |  dd| jjd¡ |  d| jjd¡ x>| jD ]4}x.tD ]&}|  dt|jƒ d || jjd¡ qZW qPW d	S )
z Ask SL to stop updating usz/unregister_auto_updatez
/sl/looperz/sl/0/unregister_auto_updater   z/unregisterz/sl/loop_numz/sl/z/sl/loopN)rr   rƒ   r`   rŠ   rc   rŽ   r—   r¡   )rj   r�   r›   rk   rk   rl   r„   N  s    

zLooperThread.unregister_updatesrJ   c             C   s(   | j  ¡  |  d| jjd¡ | j  |¡S )Nz/pingz/sl/ping)ra   Úclearrƒ   r`   rŠ   Úwait)rj   Útimeoutrk   rk   rl   rˆ   [  s    
zLooperThread.pingc             C   s   |   d|d¡ d S )Nz	/loop_addg     €E@)rƒ   )rj   Únum_channelsrk   rk   rl   Úadd_loop`  s    zLooperThread.add_loopc             C   s   |   dd¡ d S )Nz	/loop_delrI   )rƒ   )rj   rk   rk   rl   Úremove_loopc  s    zLooperThread.remove_loopc             C   s
   || _ d S )N)rD   )rj   Únrk   rk   rl   Úselect_loopf  s    zLooperThread.select_loopc             C   s   dt | jd ƒ S )N)ÚoffÚcycleÚ8thr›   r   )Úintrt   )rj   rk   rk   rl   r   i  s    zLooperThread.quantizec             C   s   d  |¡}|  dd|¡ d S )N)rª   r«   r¬   r›   z	/sl/0/setr   )Úindexrƒ   )rj   rv   Úqrk   rk   rl   r   m  s    
c             C   s"   | j d }|dkrdS t|ƒS d S )NrD   rI   Úall)rt   r­   )rj   r¨   rk   rk   rl   rD   r  s    
zLooperThread.selected_loop_numc             C   s"   |dkrd}n|}|   d|¡ d S )Nr°   rI   rD   )rs   )rj   rv   r¨   rk   rk   rl   rD   z  s    c             C   s   | j }t|tƒr| j| S d S )N)rD   Ú
isinstancer­   rc   )rj   r¨   rk   rk   rl   Úselected_loop‚  s    
zLooperThread.selected_loopc             C   s   | j d }t|ƒS )Nr=   )rt   r­   )rj   Úsrk   rk   rl   r=   ˆ  s    
zLooperThread.sync_sourcec             C   s   |}|   d|¡ d S )Nr=   )rs   )rj   rv   r³   rk   rk   rl   r=   �  s    c             C   s   |   d| jjd¡ d S )Nz/cancel_midi_learnz/sl/midi_bindings)rƒ   r`   rŠ   )rj   rk   rk   rl   Úcancel_midi_learn˜  s    zLooperThread.cancel_midi_learnc             C   s   |   d|| jjd¡ d S )Nz/save_sessionz/error)rƒ   r`   rŠ   )rj   Útarget_filerk   rk   rl   Úsave_sessionœ  s    zLooperThread.save_sessionc             C   s   |   d|d¡ d S )Nz/save_midi_bindingsÚ )rƒ   )rj   rµ   rk   rk   rl   Úsave_midi_bindingsŸ  s    zLooperThread.save_midi_bindingsc             C   s   |   d|| jjd¡ d S )Nz/load_sessionz/error)rƒ   r`   rŠ   )rj   rµ   rk   rk   rl   Úload_session¢  s    zLooperThread.load_sessionc             C   s   |   d|d¡ d S )Nz/load_midi_bindingsr·   )rƒ   )rj   rµ   rk   rk   rl   Úload_midi_bindings¥  s    zLooperThread.load_midi_bindingsc             C   s2  t ddddddddd	d
g	ƒ}d}|}d|_d|_d|_||_d|_d|_d|_|dkrld|_d|_d|_�n`|dkr„d|_d|_�nH|dkr¢d|_d|_d|_�n*|dkrÀd|_d|_d|_�n|dkrÞd|_d|_d|_�nî|dkrüd|_d|_d|_�nÐ|d k�rd |_d!|_�n¶|d"k�r0d"|_d!|_�nœ|d#k�rJd#|_d!|_�n‚|d$k�rdd%|_d$|_�nh|d&k�r„d'|_d(|_d)|_�nH|d*k�rªd%|_d*|_d|_d+|_�n"|d,k�rÄd,|_d%|_�n|d-k�rÜd-|_d%|_nð|d.k�rôd.|_d%|_nØ|d/k�rd/|_d%|_nÀ|d0k�r6d|_d1|_d|_d|_d|_n–|d2k�r`d|_d1|_d|_d3|_d3|_nl|d4k�rŠd|_d1|_d|_d5|_d5|_nB|d1k�r¨||_d6|_d7|_n$|d8k�rº||_nd|_||_d9|_|jdk�ràd|_	nd:|_	|�s.d; 
|j|j|j	|j|j|j|j|j|j¡	}|  d<|d=| jjd>¡ d S )?NZMidiBindingÚchannelÚtyper�   Úcommandrœ   ÚinstanceÚlboundÚuboundÚstyleFr   Úccrs   g        g      ð?Znormr;   g      4@g      q@Ztaptempoéþÿÿÿr>   rA   ZonrB   Zeighthr<   g      `@r   g      Ð@r   Úgainr   r	   r   rI   r   r=   g      Àg      0@r   g      @r!   r"   Zreplace_quantizedZsmart_eighthsZrate_1r
   Zrate_05g      à?Zrate_2g       @g      Ð?g      @)r   r   r   r   r   ZnoteiŒxz {} {} {} {} {} {} {} {} {} 0 127z/learn_midi_bindingZ	exclusivez/sl/midi_bindings)r   r»   r¼   r½   r¾   r¿   rÀ   rÁ   rœ   r�   rn   rƒ   r`   rŠ   )rj   rœ   r™   ÚinfoZ	donothingrv   Zinfo_strrk   rk   rl   Ú
midi_learn¨  sÆ    



























,zLooperThread.midi_learn)rZ   r[   F)rJ   )%Ú__name__Ú
__module__Ú__qualname__Ú__doc__rm   ro   rq   r‚   r†   r€   rƒ   rz   r}   r{   r|   r~   r’   rs   r�   r„   rˆ   r¦   r§   r©   Úpropertyr   ÚsetterrD   r²   r=   r´   r¶   r¸   r¹   rº   rÆ   Ú__classcell__rk   rk   )rw   rl   rY   ƒ   sD   




rY   c               @   sv   e Zd Zddd„Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zedd„ ƒZedd„ ƒZdS )r�   rF   c             C   s   || _ || _d S )N)Úlooperr¡   )rj   rÎ   r¡   r%   rk   rk   rl   rm   0  s    zLoop.__init__c             C   s   d  | j| j¡S )NzLoop({}, {}))rn   r¡   r%   )rj   rk   rk   rl   ro   5  s    zLoop.__repr__c             C   s   d  | j| j¡S )NzLoop({}, {}))rn   r¡   r%   )rj   rk   rk   rl   Ú__str__:  s    zLoop.__str__c                s   ˆ t kr‡ ‡fdd„S d S )Nc                  s
   ˆ  ˆ ¡S )N)Úhitrk   )ru   rj   rk   rl   Ú<lambda>?  ó    z"Loop.__getattr__.<locals>.<lambda>)Úloop_commands)rj   ru   rk   )ru   rj   rl   Ú__getattr__=  s    zLoop.__getattr__c             C   s&   |t kr|  d||¡ n
|| j|< d S )Nrs   )Úloop_parameters_settabler’   rt   )rj   ru   rv   rk   rk   rl   rq   B  s    zLoop.__setattr__c             C   s    t d||ƒ | j d||¡ d S )Nzsending set valuers   )r‰   rÎ   r’   )rj   rœ   r�   rk   rk   rl   rs   H  s    zLoop.setc             C   s   |   d||¡ d S )Nrs   )r’   )rj   ru   rv   rk   rk   rl   Úloop_setL  s    zLoop.loop_setc             C   s   |   d|| jjjd¡ d S )Nr�   z/sl/loop)r’   rÎ   r`   rŠ   )rj   rœ   rk   rk   rl   r�   O  s    zLoop.getc             G   s   | j j| j|f|žŽ  d S )N)rÎ   r’   r¡   )rj   Úactionr”   rk   rk   rl   r’   R  s    z	Loop.sendc             C   s   |   d|¡ d S )NrÐ   )r’   )rj   r½   rk   rk   rl   rÐ   U  s    zLoop.hitc             C   s   t t| jd ƒ S )Nr%   )Ústate_codesr­   rt   )rj   rk   rk   rl   r%   X  s    z
Loop.statec             C   s   t t| jd ƒ S )Nr&   )rØ   r­   rt   )rj   rk   rk   rl   r&   \  s    zLoop.next_stateN)rF   )rÇ   rÈ   rÉ   rm   ro   rÏ   rÔ   rq   rs   rÖ   r�   r’   rÐ   rË   r%   r&   rk   rk   rk   rl   r�   /  s   
r�   )rÊ   r_   Úcollectionsr   Ú	threadingr   r   rx   rÕ   Zloop_parameters_gettablerŽ   rÓ   rr   rØ   rY   r�   rk   rk   rk   rl   Ú<module>   s>   #   /