o
    mia;                     @   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   [/home/kim/smarthome/.venv/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ctypesZwindllmsvcrtZcdllZ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   r.   )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)r1   r   r   r   r   set_data_pathv   r3   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

        ZPHONEMIZER_ESPEAK_LIBRARYzPHONEMIZER_ESPEAK_LIBRARY=z is not a readable filez	espeak-ngZespeakzfailed to find espeak library)r/   osenvironpathlibPathis_fileaccessR_OKRuntimeErrorresolver   r   r   r0   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   infor9   r:   decoder	   is_dirr>   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   rN   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   rP      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 )r6   z is not a readable directoryZPHONEMIZER_ESPEAK_DATA_PATHzPHONEMIZER_ESPEAK_DATA_PATH=Nr   )r4   r9   r:   rI   r7   r<   r=   r>   r?   r	   r8   hasattrrN   )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   _r@      )namer,   r*   )r   Z	to_ctypesr   Zlist_voicescontentsappendr7   fsdecoderU   rL   	languagesr*   )r   rU   Zvoicesindexavailable_voicesr%   r   r   r   r[      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*   )rC   r%   r   r   r   
<dictcomp>  s    z+EspeakWrapper.set_voice.<locals>.<dictcomp>Zmbrolazinvalid voice code ""Nutf8r   zfailed to load voice ")
r[   r,   r*   KeyErrorr>   r   Zset_voice_by_nameencode
_get_voicer
   )r   Z
voice_code	availabler%   Z
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   Zget_current_voicerU   r   Zfrom_ctypes)r   r%   r   r   r   ra   .  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)rT   0   r)   z,tie option only compatible with espeak>=1.49r^   rT         u   ͡   rS      r@   )r%   r>   r$   r   Zpointerc_char_pr`   ordrV   valuer   text_to_phonemesrW   rH   join)r   rc   rd   Ztext_ptr	text_modeZphonemes_moderesultZphonemesr   r   r   rn   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.

        )rT   1   z not compatible with espeak<=1.48Nre   r      rS   ri   r^   rT   zfailed to synthetize)r$   r>   r%   r   rk   r   ZfopenargtypesZc_void_prestypeZfcloseZc_intr#   truncaterU   r`   moder   Zset_phoneme_tracerl   
synthetizeZc_size_tlenZc_uintseekreadrH   rJ   )r   rc   Zfile_pstatusZ
phonemizedr   r   r   rx   m  s2   



zEspeakWrapper.synthetizer   )F)!__name__
__module____qualname____doc__r/   r4   r   propertyr   r#   r&   r   r-   classmethodstrr2   r5   r   rN   r   rB   r$   rP   r   r%   	functools	lru_cacher[   r+   ra   boolrn   rx   r   r   r   r   r      s@    


$

#

*4r   )r   r   Zctypes.utilr   r7   r9   r   r   r    typingr   r   Zphonemizer.backend.espeak.apir   Zphonemizer.backend.espeak.voicer   r   r   r   r   r   <module>   s   