o
    mi0                     @   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
 ddlmZ ddlmZmZmZmZmZmZ ddlmZ ddlmZ ddlmZ dd	lmZmZ G d
d deZdS )#Festival backend for the phonemizer    N)Logger)Path)OptionalDictListIOUnionPattern)BaseBackend)lispy)	Separator)get_package_resourceversion_as_tuplec                       s  e Zd ZdZdZ			d6dedeeeef  de	dee
 f fdd	Zed
d ZedefddZedefddZedd Zedd Zedeeef fddZdee dedede	dee f
ddZededefdd Zedefd!d"Zedee fd#d$Zdefd%d&Zed'ed(edefd)d*Zed+ee dede	defd,d-Z ed.eee  dede	defd/d0Z!edede	defd1d2Z"ed3edede	dee fd4d5Z#  Z$S )7FestivalBackendr   NFlanguagepunctuation_markspreserve_punctuationloggerc                    st   t  j||||d | jd|   td}t|d}| | _W d    n1 s,w   Y  | jd| d S )N)r   r   r   zfestival executable is %szfestival/phonemize.scmrz	loaded %s)	super__init__r   debug
executabler   openread_script)selfr   r   r   r   Zscript_fileZfscript	__class__ ^/home/kim/smarthome/.venv/lib/python3.10/site-packages/phonemizer/backend/festival/festival.pyr   *   s   zFestivalBackend.__init__c                   C   s   dS )Nfestivalr    r    r    r    r!   name<   s   zFestivalBackend.namer   c                 C   sN   |du r	d| _ dS t|}| rt|tjs t| d| | _ dS )a  Sets the festival backend to use `executable`

        If this is not set, the backend uses the default festival executable
        from the system installation.

        Parameters
        ----------
        executable (str) : the path to the festival executable to use as
            backend. Set `executable` to None to restore the default.

        Raises
        ------
        RuntimeError if `executable` is not an executable file.

        N is not an executable file)	_FESTIVAL_EXECUTABLEpathlibr   is_fileosaccessX_OKRuntimeErrorresolveclsr   r    r    r!   set_executable@   s   
zFestivalBackend.set_executablereturnc                 C   sx   | j r| j S dtjv r+ttjd }| rtj|tjds'td| d|	 S t
d}|s6tdt|	 S )av  Returns the absolute path to the festival executable used as backend

        The following precedence rule applies for executable lookup:

        1. As specified by FestivalBackend.set_executable()
        2. Or as specified by the environment variable
           PHONEMIZER_FESTIVAL_EXECUTABLE
        3. Or the default 'festival' binary found on the system with ``shutil.which('festival')``


        Raises
        ------
        RuntimeError
            if the festival executable cannot be found or if the
            environment variable PHONEMIZER_FESTIVAL_EXECUTABLE is set to a
            non-executable file

        ZPHONEMIZER_FESTIVAL_EXECUTABLE)modezPHONEMIZER_FESTIVAL_EXECUTABLE=r$   r"   z"failed to find festival executable)r%   r(   environr&   r   r'   r)   r*   r+   r,   shutilwhichr-   r    r    r!   r   \   s(   


zFestivalBackend.executablec                 C   s$   z|    W dS  ty   Y dS w )z=True if the festival executable is available, False otherwiseFT)r   r+   r.   r    r    r!   is_available   s   
zFestivalBackend.is_availablec                 C   s`   |   }t|dgd }d}zt||d}W t
|S  ty/   t	d| dw )zFestival version as a tupe of integers (major, minor, patch)

        Raises
        ------
        RuntimeError if FestivalBackend.is_available() is False or if the
            version cannot be extracted for some reason.

        z	--versionlatin1z.* ([0-9\.]+[0-9]):   z%cannot extract festival version from N)r   
subprocesscheck_outputdecodestriprematchgroupAttributeErrorr+   r   )r.   r"   Zlong_versionZfestival_version_reversionr    r    r!   rA      s"   
zFestivalBackend.versionc                   C   s   ddiS )zA dictionnary of language codes -> name supported by festival

        Actually only en-us (American English) is supported.

        zen-usz
english-usr    r    r    r    r!   supported_languages   s   z#FestivalBackend.supported_languagestextoffset	separatorr<   c                 C   s6   |  |}t|dkrg S | |}| |||}|S )a  Return a phonemized version of `text` with festival

        This function is a wrapper on festival, a text to speech
        program, allowing simple phonemization of some English
        text. The US phoneset we use is the default one in festival,
        as described at http://www.festvox.org/bsv/c4711.html

        Any opening and closing parenthesis in `text` are removed, as
        they interfer with the Scheme expression syntax. Moreover
        double quotes are replaced by simple quotes because double
        quotes denotes utterances boundaries in festival.

        Parsing a ill-formed Scheme expression during post-processing
        (typically with unbalanced parenthesis) raises an IndexError.

        r   )_preprocesslen_process_postprocess)r   rC   rD   rE   r<   r    r    r!   _phonemize_aux   s   

zFestivalBackend._phonemize_auxlinec                 C   s   d|  d S )z4Return the string `line` surrounded by double quotes"r    rK   r    r    r!   _double_quoted   s   zFestivalBackend._double_quotedc                 C   s4   t | t dkr
d} | dddddd S )z+Remove 'forbidden' characters from the line' rL   ())setreplacer<   rM   r    r    r!   _cleaned   s    zFestivalBackend._cleanedc                    s*    fdd|D }d  fdd|D S )a  Returns the contents of `text` formatted for festival input

        This function adds double quotes to begining and end of each
        line in text, if not already presents. The returned result is
        a multiline string. Empty lines in inputs are ignored.

        c                 3   "    | ]}|d kr  |V  qdS rP   N)rU   .0rK   r5   r    r!   	<genexpr>       z.FestivalBackend._preprocess.<locals>.<genexpr>
c                 3   rV   rW   )rN   rX   r5   r    r!   rZ      r[   )join)r.   rC   Zcleaned_textr    r5   r!   rF      s   
	zFestivalBackend._preprocessc                 C   s  t jddd}z|| |  |j}tjdkr |dd}t jdddp}z`|| j	| |  | 
  d|j }| jrJ| jd| t d*}| ||W  d	   W t|j W  d	   W t|j W  d	   S 1 s|w   Y  W t|j nt|j w W d	   n1 sw   Y  W t|j nt|j w W d	   d	S 1 sw   Y  d	S )
a  Return the raw phonemization of `text`

        This function delegates to festival the text analysis and
        syllabic structure extraction.

        Return a string containing the "SylStructure" relation tree of
        the text, as a scheme expression.

        zw+F)deletewin32\z\\z -b z
running %sN)tempfileNamedTemporaryFilewritecloser#   sysplatformrT   r   formatr   r   r   TemporaryFile_run_festivalr(   remove)r   rC   datar#   scmcmdfstderrr    r    r!   rH      s6   



"zFestivalBackend._processrm   rn   c                 C   sv   zt jtj| dd|d}tdd|dW S  t jy: } z|d t	d|  d	|j
 d
|  dd}~ww )zRuns the festival command for phonemization

        Returns the raw phonemized output (need to be postprocesses). Raises a
        RuntimeError if festival fails.

        F)posix)stderrz + r7   r   z	Command "z" returned exit status z, output is:
N)r9   r:   shlexsplitr=   subr;   CalledProcessErrorseekr+   
returncoder   )rm   rn   outputerrr    r    r!   ri     s    
zFestivalBackend._run_festivalsyllc                 C   s@   |j }dd | dd D }|dd |D }|r|S || S )z3Parse a syllable from festival to phonemized outputc                 s   s$    | ]}|d  d   ddV  qdS )r   rL   rP   N)rT   )rY   phoner    r    r!   rZ   /  s   " z4FestivalBackend._postprocess_syll.<locals>.<genexpr>r8   Nc                 s   s    | ]	}|d kr|V  qdS rW   r    )rY   or    r    r!   rZ   0  s    )r{   r]   )rz   rE   r<   sepoutr    r    r!   _postprocess_syll+  s   z!FestivalBackend._postprocess_syllwordc                    s:   j }| fdd|dd D }r|S || S )z/Parse a word from festival to phonemized outputc                 3   s    | ]
}  |V  qd S )N)r   )rY   rz   r.   rE   r<   r    r!   rZ   7  s
    
z4FestivalBackend._postprocess_word.<locals>.<genexpr>r8   N)Zsyllabler]   )r.   r   rE   r<   r}   r~   r    r   r!   _postprocess_word3  s
   
z!FestivalBackend._postprocess_wordc                 C   sT   |j }g }t|D ]}| |||}|dkr|| q
||}|r&|S || S )z/Parse a line from festival to phonemized outputrP   )r   r   parser   appendr]   )r.   rK   rE   r<   r}   r~   r   r    r    r!   _postprocess_line<  s   

z!FestivalBackend._postprocess_linetreec                    s    fdd| dD S )z8Conversion from festival syllable tree to desired formatc                    s"   g | ]}|d vr  |qS ))rP   z(nil nil nil))r   rX   r   r    r!   
<listcomp>L  s
    z0FestivalBackend._postprocess.<locals>.<listcomp>r\   )rs   )r.   r   rE   r<   r    r   r!   rI   I  s   zFestivalBackend._postprocess)NFN)%__name__
__module____qualname____doc__r%   strr   r	   r
   boolr   r   staticmethodr#   classmethodr/   r   r   r6   rA   r   rB   r   intr   rJ   rN   rU   rF   rH   r   ri   r   r   r   rI   __classcell__r    r    r   r!   r   #   sV    
(

&	* $(r   )r   r(   r&   r=   rr   r3   r9   re   ra   loggingr   r   typingr   r   r   r   r	   r
   Zphonemizer.backend.baser   Zphonemizer.backend.festivalr   Zphonemizer.separatorr   Zphonemizer.utilsr   r   r   r    r    r    r!   <module>   s"    