
\c        
   @  s_  d  d l  m Z d  d l Z d  d l 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
 Z
 d  d l Z e j j d d  Z e r d  d l j j Z n e Z e a e j   Z d a d   Z d   Z d	 e f d
     YZ d e j j f d     YZ d a e
 j   Z d e f d     YZ  y d  d l! m" Z" Wn n Xy d  d l# m$ Z$ Wn n Xg  Z% i  Z& e e e' e( d d e' e( e' d 	 Z) d   Z* d   Z+ d   Z, e a- e' a. d   Z/ d   Z0 e a1 e( a2 d   Z3 e a4 e( a5 e
 j6   Z7 d   Z8 d   Z9 d   Z: d   Z; e( a< d   Z= d   Z> d   Z? d   Z@ d S(    i(   t   print_functionN(   t   sixt   RENPY_DISABLE_SOUNDt    i    c           C  s   t  d 7a  t t  f S(   sE   
    Gets a globally unique serial number for each music change.
    i   (   t   serialt   unique(    (    (    s   renpy/audio/audio.pyt
   get_serial9   s    
c         C  s   t  j j |   } | S(   s<   
    Returns a file-like object for the given filename.
    (   t   renpyt   loadert   load(   t   fnt   rv(    (    s   renpy/audio/audio.pyR	   C   s    t
   QueueEntryc           B  s   e  Z d  Z d   Z RS(   s   
    A queue entry object.
    c         C  s(   | |  _  | |  _ | |  _ | |  _ d  S(   N(   t   filenamet   fadeint   tightt   loop(   t   selfR   R   R   R   (    (    s   renpy/audio/audio.pyt   __init__Q   s    			(   t   __name__t
   __module__t   __doc__R   (    (    (    s   renpy/audio/audio.pyR   L   s   t   MusicContextc           B  s,   e  Z d  Z d Z e Z d   Z d   Z RS(   s   
    This stores information about the music in a game. This object
    participates in rollback, so when the user goes back in time, all
    the values get reverted as well.
    i    c         C  sh   t  t |   j   d  |  _ d |  _ d  |  _ d |  _ d |  _ t	 |  _
 g  |  _ t	 |  _ t	 |  _ d  S(   Ni    g      ?(   t   superR   R   t   Nonet   pan_timet   pant   secondary_volume_timet   secondary_volumet   last_changedt   Falset
   last_tightt   last_filenamest
   force_stopt   pause(   R   (    (    s   renpy/audio/audio.pyR   c   s    								c         C  s    t    } | j j |  j  | S(   s9   
        Returns a shallow copy of this context.
        (   R   t   __dict__t   update(   R   R   (    (    s   renpy/audio/audio.pyt   copy   s    	(   R   R   R   t   __version__R   R"   R   R%   (    (    (    s   renpy/audio/audio.pyR   X   s
   	t   Channelc           B  s   e  Z d  Z d   Z d   Z e e  Z d   Z e e  Z d   Z	 d   Z
 e d  Z d   Z d   Z e e d	 d e d
  Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z RS(   sD   
    This stores information about the currently-playing music.
    c
   
      C  s<  | |  _  d  |  _ d  |  _ d |  _ d |  _ g  |  _ g  |  _ t |  _	 t |  _
 t |  _ d |  _ d  |  _ d  |  _ d  |  _ | |  _ | |  _ d |  _ | |  _ | |  _ | |  _ d  |  _ | d  k r t |  _ t |  _ n | |  _ t |  _ | r&|	 rt j j j |  _ q8t j j j |  _ n t j j j  |  _ d  S(   Ng      ?i    (!   t   nameR   t   _numbert   mixert   chan_volumet   actual_volumet   queueR   R   t   playingt	   wait_stopt   synchro_startR   t   callbackR   R   t   stop_on_muteR   t
   keep_queuet   file_prefixt   file_suffixt   buffer_queuet   pausedt   Truet   default_loopt   default_loop_setR   t   audiot
   renpysoundt
   DROP_VIDEOt   moviet   NODROP_VIDEOt   NO_VIDEO(
   R   R(   R9   R2   R   R4   R5   R6   R>   t	   framedrop(    (    s   renpy/audio/audio.pyR      s>    																								c         C  s3   |  j  } | d k r/ t } |  _  t d 7a n  | S(   sk   
        Returns the number of this channel, allocating a number if that
        proves necessary.
        i   N(   R)   R   t   next_channel_number(   R   R   (    (    s   renpy/audio/audio.pyt
   get_number   s
    	c         C  sK   t  j j   j } | j |  j  } | d k rG t   } | |  j <n  | S(   s   
        Returns the MusicContext corresponding to this channel, taken from
        the context object. Allocates a MusicContext if none exists.
        N(   R   t   gamet   contextt   musict   getR(   R   R   (   R   t   mcdR   (    (    s   renpy/audio/audio.pyt   get_context  s
    c   
        sA   f d        f d   } t  j d   } | sF  d d f S| j d   | j d  }  j    d } d } d } x  r j d  }	 |	 d k r |   } q |	 d	 k r |   } q |	 d
 k r |   } q |	 d k r |   } d } q   d j |	    q W| d k	 r4| r4| } n  | | | f S(   sN   
        Splits a filename into a filename, start time, and end time.
        c           s   t  d j   |    S(   Ns   Parsing audio spec {!r}: {}.(   t	   Exceptiont   format(   t   msg(   R   (    s   renpy/audio/audio.pyt	   exception  s    c            sU    s   d   n   j  d  }  y t |   SWn   d j |     n Xd  S(   Ns   expected float at end.i    s   expected float, got {!r}.(   t   popt   floatRK   (   t   v(   RM   t   spec(    s   renpy/audio/audio.pyt   expect_float  s    s
   <(.*)>(.*)i    ii   i   t   fromt   toR   t   silences   _silence.oggs   expected keyword, got {!r}.N(   t   ret   matcht   groupt   splitR   RN   RK   (
   R   R   t   loopedRR   t   mR
   t   startR   t   endt   clause(    (   RM   R   RQ   s   renpy/audio/audio.pyt   split_filename  s4    				c         C  sW  |  j  t j j j j |  j d  } | |  j k rS t j	 |  j
 |  | |  _ n  |  j j p t j j j j |  j t  o |  j } |  j r | r t j |  j
  t |  _ n  | r t |  _ |  j r |  j t |  j  |  _ n	 g  |  _ d St } d } xot rpt j |  j
  } | d k r;t |  _ t |  _ n  |  j sHPn  | d k rXPn  |  j rr| d k rrPn  |  j r| rPn  t j |  j
  d k rPn  |  j j d  } | j j   |  j j   } x& d D] } | j |  rd } qqW| sqn  y|  j  | j | j  \ } }	 }
 |
 d k rS|
 |	 d k rS|  j rSwn  t! |  j" | |  j  } t j# |  j
 |  j$  | d k rt j% |  j
 | | j d
 |  j d | j& d | j' d |	 d |
 n7 t j |  j
 | | j d | j& d | j' d |	 d |
 t |  _ WnV x) | j |  j k rD|  j j( | j  qWt j) j* rdt j j+ rd  qld Sn XPqW|  j r|  j rxf |  j D]R } | d k	 rt, | d | j' t  } n t, | d t t  } |  j j- |  qWn t } | r	|  j. r	|  j.   n  |  j j/ pt0 } |  j1 | k rS| r=|  j/   n
 |  j2   | |  _1 n  d S(   s}   
        This is the periodic call that causes this channel to load new stuff
        into its queues, if necessary.
        g      ?Ni    i   i   s   .mods   .xms   .mids   .midiR7   R   R   R\   R]   (   s   .mods   .xms   .mids   .midi(3   R+   R   RD   t   preferencest   volumesRG   R*   R,   R<   t
   set_volumet   numberRE   R!   t   muteR   R2   R.   t   stopR/   R   R-   t   lenR   R8   t   queue_depthR6   R0   RN   R   t   lowerR5   t   endswithR_   R	   R4   t	   set_videoR>   t   playR   R   t   removet   configt   debug_soundt   after_rollbackR   t   appendR1   R"   t   global_pauseR7   t   unpause(   R   t   volR!   t   do_callbackt   topqt   deptht   lfnt   iR   R\   R]   t   topft   newqt
   want_pause(    (    s   renpy/audio/audio.pyt   periodicL  s    %3						!%C7
c         C  sn   t  b |  j |  j  |  _ g  |  _ t s- d S|  j d k rd t j |  j |  t |  _	 t |  _
 n  Wd QXd S(   s   
        Clears the queued music.

        If the first item in the queue has not been started, then it is
        left in the queue unless all is given.
        Ni    (   t   lockR-   R3   R   t   pcm_okR<   t   dequeueRc   R   R/   R0   (   R   t
   even_tight(    (    s   renpy/audio/audio.pyR     s    		c         C  s   d |  _  t r |  j |  j j k rR |  j j |  _ t j |  j |  j j d  n  |  j |  j j k r |  j j |  _ t j	 |  j |  j j
 d  q n  |  j r |  j r |  j   n  d S(   s7   
        Called (mostly) once per interaction.
        i    N(   R3   R~   R   RE   R<   t   set_panRc   R   R   t   set_secondary_volumeR   R-   R1   (   R   (    (    s   renpy/audio/audio.pyt   interact  s    		
	c         C  s`   t  T d |  _ |  j   t s$ d S| d k rC t j |  j  n t j |  j |  Wd QXd S(   s   
        Causes the playing music to be faded out for the given number
        of seconds. Also clears any queued music.
        i    N(   R}   R3   R   R~   R<   Re   Rc   t   fadeout(   R   t   secs(    (    s   renpy/audio/audio.pyR     s    	
i    c   
   
   C  s  t   x< | D]4 } |  j | t  \ } } } t t j j j | <q Wt sP d  S| s | d  k rn |  j
 } n  |  j d 7_ xC | D]; } t | t | d  | t  }	 |  j j |	  d } q W| |  _ | |  _ n  | r t |  |  _ n	 g  |  _ Wd  QXd  S(   Ni   i  i    (   R}   R_   R   R8   R   RD   t
   persistentt   _seen_audioR~   R   R   R3   R   t   intR-   Rp   R/   R0   t   listR   (
   R   t	   filenamesR   R0   R   R   t	   loop_onlyR   t   _t   qe(    (    s   renpy/audio/audio.pyt   enqueue  s&    
	c         C  s   t  s
 d  St j |  j  } t d t j |  j  } | d  k r] |  j r] |  j d j } n  | d  k r |  j r |  j d } n  Wd  QX| S(   Ni    (	   R~   R   R<   t   playing_nameRc   R}   R-   R   R   (   R   R   (    (    s   renpy/audio/audio.pyt   get_playing8  s    c         C  s   | |  _  d  S(   N(   R+   (   R   t   volume(    (    s   renpy/audio/audio.pyRb   K  s    c         C  s   t  s
 d St j |  j  S(   Ni(   R~   R<   t   get_posRc   (   R   (    (    s   renpy/audio/audio.pyR   N  s    c         C  s   t  s
 d St j |  j  S(   Ng        (   R~   R<   t   get_durationRc   (   R   (    (    s   renpy/audio/audio.pyR   U  s    c         C  sf   t  Z t   } | |  j _ | |  j _ t r\ |  j j |  _ t j |  j |  j j |  n  Wd  QXd  S(   N(	   R}   R   RE   R   R   R~   R<   R   Rc   (   R   R   t   delayt   now(    (    s   renpy/audio/audio.pyR   \  s    	c         C  sf   t  Z t   } | |  j _ | |  j _ t r\ |  j j |  _ t j |  j |  j j |  n  Wd  QXd  S(   N(	   R}   R   RE   R   R   R~   R<   R   Rc   (   R   R   R   R   (    (    s   renpy/audio/audio.pyR   h  s    	c         C  s!   t   t j |  j  Wd  QXd  S(   N(   R}   R<   R"   Rc   (   R   (    (    s   renpy/audio/audio.pyR"   t  s    c         C  s!   t   t j |  j  Wd  QXd  S(   N(   R}   R<   Rr   Rc   (   R   (    (    s   renpy/audio/audio.pyRr   x  s    c         C  s   t  r t j |  j  Sd  S(   N(   R~   R<   t
   read_videoRc   R   (   R   (    (    s   renpy/audio/audio.pyR   |  s    c         C  s   t  s
 d St j |  j  S(   Ni   (   R~   R<   t   video_readyRc   (   R   (    (    s   renpy/audio/audio.pyR     s    N(   R   R   R   R   RC   t   propertyRc   RI   RE   R_   R|   R   R   R   R   R8   R   R   R   Rb   R   R   R   R   R"   Rr   R   R   (    (    (    s   renpy/audio/audio.pyR'      s,   	^			5			!									(   t   AndroidVideoChannel(   t   IOSVideoChannelc
         C  s  |  d k r t  } n  t j j   j rC d |  k rC t d   n  t j r t j j r |  d k r t	 |  d | d | d | }
 nl t j
 r t j j r |  d k r t |  d | d | d | }
 n* t |  | | | | | | d | d |	 }
 | |
 _ t j |
  |
 t |  <d S(	   s  
    :doc: audio

    This registers a new audio channel named `name`. Audio can then be
    played on the channel by supplying the channel name to the play or
    queue statements.

    `mixer`
        The name of the mixer the channel uses. By default, Ren'Py
        knows about the "music", "sfx", and "voice" mixers. Using
        other names is possible, but may require changing the
        preferences screens.

    `loop`
        If true, sounds on this channel loop by default.

    `stop_on_mute`
        If true, music on the channel is stopped when the channel is muted.

    `tight`
        If true, sounds will loop even when fadeout is occurring. This should
        be set to True for a sound effects or seamless music channel, and False
        if the music fades out on its own.

    `file_prefix`
        A prefix that is prepended to the filenames of the sound files being
        played on this channel.

    `file_suffix`
        A suffix that is appended to the filenames of the sound files being
        played on this channel.

    `buffer_queue`
        Should we buffer the first second or so of a queued file? This should
        be True for audio, and False for movie playback.

    `movie`
        If true, this channel will be set up to play back videos.

    `framedrop`
        This controls what a video does when lagging. If true, frames will
        be dropped to keep up with realtime and the soundtrack. If false,
        Ren'Py will display frames late rather than dropping them.
    R>   t    s-   Can't register channel outside of init phase.R9   R4   R5   RA   N(   R8   R   RD   RE   t
   init_phaseRJ   t   androidRm   t   hw_videoR   t   iosR   R'   R*   t   all_channelsRp   t   channels(   R(   R*   R   R2   R   R4   R5   R6   R>   RA   t   c(    (    s   renpy/audio/audio.pyt   register_channel  s    .	!!!!*	c         C  s;   t  j j   j s! t d   n  t |   } | t | <d  S(   Ns*   Can't alias channel outside of init phase.(   R   RD   RE   R   RJ   t   get_channelR   (   R(   t   newnameR   (    (    s   renpy/audio/audio.pyt   alias_channel  s    c      
   C  s   t  j |  d   } | d  k r |  t j j k r d } x t r t d j |  |   } | j	   sg | St j j
 rw | S| d 7} q9 Wq d |  k r |  j   d } t j j | \ } } } t |  d t d | d | d | t  |  St d	 |    n  | S(
   Ni    s   {} {}i   R   R   R*   R4   R5   s   Audio channel %r is unknown.(   R   RG   R   R   Rm   t   auto_channelsR8   R   RK   R   t   skippingRY   R   R   RJ   (   R(   R   Rx   R   t   baseR*   R4   R5   (    (    s   renpy/audio/audio.pyR     s.    	c         C  s   | t  |   j _ d  S(   N(   R   RE   R!   (   R(   t   value(    (    s   renpy/audio/audio.pyt   set_force_stop  s    c          C  s}  t  j j s t a t a d  St d  k r t r d }  t  j rF d }  n  d t	 j
 k rk t t	 j
 d  }  n  y/ t j t  j j d |  t t  j j  t a Wq t  j j r   n  t a q Xn  g  } x0 t D]( } | j | k r | j | j  q q Wd } x@ | D]8 } t  j j j j | |  t  j j j j | t  qWt 0 t a t j d t  a t t _ t j    Wd  QXd  S(   Ni   i    t   RENPY_SOUND_BUFSIZEi   g      ?t   target(!   R   Rm   t   soundR   R~   t   mix_okR   R<   t
   emscriptent   ost   environR   t   initt   sound_sample_ratet
   equal_monoR8   Rn   R   R*   Rp   RD   R`   Ra   t
   setdefaultRd   t   periodic_conditiont   periodic_thread_quitt	   threadingt   Threadt   periodic_thread_maint   periodic_threadt   daemonR\   (   t   bufsizet   mixersR   t   default_volumeR[   (    (    s   renpy/audio/audio.pyR      s<    		%
	c          C  s   t  d  k	 r6 t  t a t j   Wd  QXt  j   n  t s@ d  Sx[ t D]S }  |  j	   |  j
 d  g  |  _ g  |  _ t |  _ t |  _ t |  _ t |  _ qG Wt j   d  a d  a d  S(   Ni    (   R   R   R   R8   R   t   notifyt   joinR~   R   R   R   R-   R   R   R.   t   playing_midiR/   R0   R<   t   quitR   (   R   (    (    s   renpy/audio/audio.pyR   T  s&    
					
c          C  s  t  s
 t Syg  }  t } xB t j j D]4 } t |  } |  j |  | j   r& t } q& q& Wt j	 j
 j sv t } n  | r t r t j j } n | r t r d } n d } | a | d k	 r x9 t D]. } | |  k r q n  | j | t j j  q Wn  x t D] } | j   qWt j   t } xF t D]> } | j rP| j rPt } Pn  | j r.| j r.t } q.q.W| rt j   x t D] } t | _ qWn  Wn t j j r  qn Xd S(   s	  
    The periodic sound callback. This is called at around 20hz, and is
    responsible for adjusting the volume of the playing music if
    necessary, and also for calling the periodic functions of midi and
    the various channels, which then may play music.
    g      ?N(   R~   R   R   Rm   t   emphasize_audio_channelsR   Rp   R   R8   RD   R`   t   emphasize_audiot   old_emphasizedt   emphasize_audio_volumeR   R   R   t   emphasize_audio_timeR|   R<   R0   R/   t   unpause_allRn   (   t   emphasize_channelst
   emphasizedRx   R   Rs   t   need_ss(    (    s   renpy/audio/audio.pyt   periodic_pass  sP    		

c        
   C  s   x t  r t 7 t s& t j d  n  t r0 d  St s< w n  t a Wd  QXt 0 y t   Wn t k
 ry t	 j
   a n XWd  QXq Wd  S(   Ng?(   R8   R   t   run_periodict   waitR   R   R}   R   RJ   t   syst   exc_infot   periodic_exc(    (    (    s   renpy/audio/audio.pyR     s    	c       	   C  s   t  j j s t   d  St j x t D] }  |  j   q% Wt d  k	 rs t } d  a t	 j
 | d | d | d  n  t a t j   Wd  QXd  S(   Ni    i   i   (   R   Rm   t   audio_periodic_threadR   R   R   RI   R   R   R   t   reraiseR8   R   R   (   R   t   exc(    (    s   renpy/audio/audio.pyR|     s    "c          C  s   t  s
 d St  y x t D] }  |  j   |  j } |  j | j k rL q n  | j } | j } |  j r | s |  j	   | k r |  j
 t j j  q n  | r |  j | d t d t d | n  | j |  _ q WWn t j j r   q n XWd QXt   d S(   s/   
    Called at least once per interaction.
    NR   R0   R   (   R~   R}   R   R   RE   R   R    R   R   R   R   R   Rm   t
   fade_musicR   R8   Rn   R|   (   R   t   ctxR   R   (    (    s   renpy/audio/audio.pyR     s*    
				"c          C  s;   t  / x' t D] }  |  j s |  j d  q q WWd QXd S(   sN   
    On rollback, we want to stop all the channels with non-empty sounds.
    i    N(   R}   R   R   R   (   R   (    (    s   renpy/audio/audio.pyt   rollback1  s    	c           C  s   t  a t   d S(   s&   
    Pause all playback channels.
    N(   R8   Rq   R|   (    (    (    s   renpy/audio/audio.pyt	   pause_all@  s    c           C  s   t  a t   d S(   s(   
    Unpause all playback channels.
    N(   R   Rq   R|   (    (    (    s   renpy/audio/audio.pyR   K  s    c         C  s   t  s
 d  St  j |  |  d  S(   N(   R<   t   sample_surfaces(   t   rgbt   rgba(    (    s   renpy/audio/audio.pyR   V  s    c           C  s   t  s
 d  St  j   d  S(   N(   R<   t   advance_time(    (    (    s   renpy/audio/audio.pyR   ]  s    (A   t
   __future__R    t   renpy.audioR   t   renpy.displayR   t   timet   pygame_sdl2R   RV   R   R   R   RG   t   disablet   renpy.audio.renpysoundR;   R<   R   R~   R   R   R   R	   t   objectR   t   pythont   RevertableObjectR   RB   t   RLockR}   R'   t   renpy.audio.androidhwR   t   renpy.audio.ioshwR   R   R   R8   R   R   R   R   R   R   R   R   R   t
   pcm_volumeR   R   R   R   t	   ConditionR   R   R|   R   R   Rq   R   R   R   R   (    (    (    s   renpy/audio/audio.pyt   <module>   sr   	
		6 $A		.		4	&	K			,				