o
    ia;                     @   s~   d 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ddlZddlZddl	m
Z
mZ ddlmZ ddlmZ G dd dZdS )zWrapper on espeak-ng library    N)TupleDict)	EspeakAPI)EspeakVoicec                   @   s  e Zd ZdZdZdZdd Zedd Zedd Z	d	d
 Z
defddZedefddZedefddZedd Zdd Zedeeeef fddZedd Zedd Zedd  Zejdd!d/d"d#Zd$d% Zd&d' Zd0d)ed*edefd+d,Zd)efd-d.Z dS )1EspeakWrappera  Wrapper on espeak shared library

    The aim of this wrapper is not to be exhaustive but to encapsulate the
    espeak functions required for phonemization. It relies on a espeak shared
    library (*.so on Linux, *.dylib on Mac and *.dll on Windows) that must be
    installed on the system.

    Use the function `EspeakWrapper.set_library()` before instanciation to
    customize the library to use.

    Raises
    ------
    RuntimeError if the espeak shared library cannot be loaded

    Nc                 C   s4   d | _ d | _d | _t|  | j| _d | _d | _d S N)	_version
_data_path_voicer   library	data_path_espeak_libc_
_tempfile_self r   U/home/ubuntu/.local/lib/python3.10/site-packages/phonemizer/backend/espeak/wrapper.py__init__5   s   
zEspeakWrapper.__init__c                 C   s8   | j d u rtjdkrtjjn	tjtj	d| _ | j S )Nwin32c)
r   sysplatformctypeswindllmsvcrtcdllLoadLibraryutilfind_libraryr   r   r   r   _libcC   s
   
zEspeakWrapper._libcc                 C   s,   | j d u rt | _ t| j | j j | j S r   )r   tempfileNamedTemporaryFileweakreffinalizecloser   r   r   r   	_tempfileK   s   

zEspeakWrapper._tempfilec                 C   s   | j | j| jdS )z/For pickling, when phonemizing on multiple jobs)versionr   voice)r   r	   r
   r   r   r   r   __getstate__T   s   zEspeakWrapper.__getstate__statec                 C   sh   |    |d | _|d | _|d | _| jr2d| jjv r)| | jjdd  dS | | jj dS dS )z1For unpickling, when phonemizing on multiple jobsr'   r   r(   mb   N)r   r   r	   r
   
identifier	set_voicelanguage)r   r*   r   r   r   __setstate__[   s   


zEspeakWrapper.__setstate__r   c                 C   
   || _ dS )a`  Sets the espeak backend to use `library`

        If this is not set, the backend uses the default espeak shared library
        from the system installation.

        Parameters
        ----------
        library (str or None) : the path to the espeak shared library to use as
          backend. Set `library` to None to restore the default.

        N)_ESPEAK_LIBRARYclsr   r   r   r   set_libraryg      
zEspeakWrapper.set_libraryr   c                 C   r1   )af  Sets the path for the data to be used by the espeak backend.

        If this is not set, the backend uses the default data path from the system installation.

        Parameters
        ----------
        data_path : str
            The path to the data to be used by the espeak backend. Set `data_path` to None
            to restore the default.

        N)_ESPEAK_DATA_PATH)r4   r   r   r   r   set_data_pathv   r6   zEspeakWrapper.set_data_pathc                 C   s|   | j r| j S dtjv r*ttjd }| rt|tjs&td| d|	 S t
jdp5t
jd}|s<td|S )  Returns the espeak library used as backend

        The following precedence rule applies for library lookup:

        1. As specified by BaseEspeakBackend.set_library()
        2. Or as specified by the environment variable
           PHONEMIZER_ESPEAK_LIBRARY
        3. Or the default espeak library found on the system

        Raises
        ------
        RuntimeError if the espeak library cannot be found or if the
          environment variable PHONEMIZER_ESPEAK_LIBRARY is set to a
          non-readable file

        PHONEMIZER_ESPEAK_LIBRARYzPHONEMIZER_ESPEAK_LIBRARY=z is not a readable filez	espeak-ngespeakzfailed to find espeak library)r2   osenvironpathlibPathis_fileaccessR_OKRuntimeErrorresolver   r   r   r3   r   r   r   r      s"   


zEspeakWrapper.libraryc                 C   sl   | j  \}}t| | _| j std|  	dd 
dd}tdd |	dD | _d	S )
z9Initializes version and dapa path from the espeak libraryz(failed to retrieve espeak data directory r   z-dev c                 s   s    | ]}t |V  qd S r   )int).0vr   r   r   	<genexpr>   s    z8EspeakWrapper._fetch_version_and_path.<locals>.<genexpr>.N)r   infor>   r?   decoder	   is_dirrC   stripsplitreplacetupler   )r   r'   r   r   r   r   _fetch_version_and_path   s   
z%EspeakWrapper._fetch_version_and_pathreturnc                 C   s   | j du r	|   | j S )z?The espeak version as a tuple of integers (major, minor, patch)N)r   rS   r   r   r   r   r'      s   
zEspeakWrapper.versionc                 C   s   | j jS )z-The espeak library as a pathlib.Path instance)r   library_pathr   r   r   r   rU      s   zEspeakWrapper.library_pathc                 C   s   | j r#t| j }| rt| j tjst| j  d| | _	n%dtj
v rHttj
d }| r;t|tjsCtd| d| | _	| j	du rVt| drV|   | j	S )r9   z is not a readable directoryPHONEMIZER_ESPEAK_DATA_PATHzPHONEMIZER_ESPEAK_DATA_PATH=Nr   )r7   r>   r?   rN   r<   rA   rB   rC   rD   r	   r=   hasattrrS   )r   r   r   r   r   r      s   


zEspeakWrapper.data_pathc                 C   s   | j S )zsThe configured voice as an EspeakVoice instance

        If `set_voice` has not been called, returns None

        )r
   r   r   r   r   r(      s   zEspeakWrapper.voice)maxsizec                 C   s   |r	t |d }| j|pd}d}g }|| rD|| j}|t t|j	ddt|j
dd t|jd |d7 }|| s|S )z>Voices available for phonemization, as a list of `EspeakVoice`)r/   Nr   _rE      )namer/   r-   )r   	to_ctypesr   list_voicescontentsappendr<   fsdecoder[   rQ   	languagesr-   )r   r[   voicesindexavailable_voicesr(   r   r   r   rd      s   

zEspeakWrapper.available_voicesc                 C   s   d|v rdd |  dD }ni }|   D ]}|j|vr"|j||j< qz|| }W n ty9   td| ddw | j|dd	krMtd
| d|  }|s[td
| d|| _	dS )a!  Setup the voice to use for phonemization

        Parameters
        ----------
        voice_code (str) : Must be a valid language code that is actually
          supported by espeak

        Raises
        ------
        RuntimeError if the required voice cannot be initialized

        r+   c                 S   s   i | ]}|j d d |j qS )r,   N)r-   )rH   r(   r   r   r   
<dictcomp>  s    z+EspeakWrapper.set_voice.<locals>.<dictcomp>mbrolazinvalid voice code ""Nutf8r   zfailed to load voice ")
rd   r/   r-   KeyErrorrC   r   set_voice_by_nameencode
_get_voicer
   )r   
voice_code	availabler(   
voice_namer   r   r   r.     s,   


zEspeakWrapper.set_voicec                 C   s   | j  }|jrt|S dS )znReturns the current voice used for phonemization

        If no voice has been set up, returns None.

        N)r   get_current_voicer[   r   from_ctypes)r   r(   r   r   r   rl   .  s   

zEspeakWrapper._get_voiceFtexttiec                 C   s   | j du r	td|r| jdkrtdtt|d}d}| jdkr)d}n|r4dtd	d
> B }ntdd
> dB }g }|jj	dur[| j
|||}|rU||  |jj	dusDd|S )u  Translates a text into phonemes, must call set_voice() first.

        This method is used by the Espeak backend. Wrapper on the
        espeak_TextToPhonemes function.

        Parameters
        ----------
        text (str) : the text to phonemize

        tie (bool, optional) : When True use a '͡' character between
          consecutive characters of a single phoneme. Else separate phoneme
          with '_'. This option requires espeak>=1.49. Default to False.

        Returns
        -------
        phonemes (str) : the phonemes for the text encoded in IPA, with '_' as
          phonemes separator (excepted if ``tie`` is True) and ' ' as word
          separator.

        Nno voice specified)rZ   0   r,   z,tie option only compatible with espeak>=1.49rh   rZ         u   ͡   rY      rE   )r(   rC   r'   r   pointerc_char_prk   ordr^   valuer   text_to_phonemesr_   rM   join)r   rr   rs   text_ptr	text_modephonemes_moderesultphonemesr   r   r   r~   9  s,   


zEspeakWrapper.text_to_phonemesc                 C   s  | j dk r	td| jdu rtdtjtjg| jj_tj| jj_	tjg| jj
_tj| jj
_	| jd | j| jj | jj }| jdtdd> B | | jt|d	tt|d
 td
}| j
| |dkrvtd| jd | j   }|S )a  Translates a text into phonemes, must call set_voice() first.

        Only compatible with espeak>=1.49. This method is used by the
        EspeakMbrola backend. Wrapper on the espeak_Synthesize function.

        Parameters
        ----------
        text (str) : the text to phonemize

        Returns
        -------
        phonemes (str) : the phonemes for the text encoded in SAMPA, with '_'
          as phonemes separator and no word separation.

        )rZ   1   z not compatible with espeak<=1.48Nrt   r      rY   rx   rh   rZ   zfailed to synthetize)r'   rC   r(   r   r{   r    fopenargtypesc_void_prestypefclosec_intr&   truncater[   rk   moder   set_phoneme_tracer|   
synthetizec_size_tlenc_uintseekreadrM   rO   )r   rr   file_pstatus
phonemizedr   r   r   r   m  s2   



zEspeakWrapper.synthetizer   )F)!__name__
__module____qualname____doc__r2   r7   r   propertyr    r&   r)   r   r0   classmethodstrr5   r8   r   rS   r   rG   r'   rU   r   r(   	functools	lru_cacherd   r.   rl   boolr~   r   r   r   r   r   r      s@    


$

#

*4r   )r   r   ctypes.utilr   r<   r>   r   r!   r#   typingr   r   phonemizer.backend.espeak.apir   phonemizer.backend.espeak.voicer   r   r   r   r   r   <module>   s   