o
    i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   script_filefscript	__class__ X/home/ubuntu/.local/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

        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-   r0   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   )r0   r$   long_versionfestival_version_reversionr"   r"   r#   rF      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   rH   rI   rJ   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"   rP   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' rQ   ())setreplacer?   rR   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 rU   N)rZ   .0rP   r8   r"   r#   	<genexpr>       z.FestivalBackend._preprocess.<locals>.<genexpr>
c                 3   r[   r\   )rS   r]   r8   r"   r#   r_      r`   )join)r0   rH   cleaned_textr"   r8   r#   rK      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platformrY   r   formatr   r   r   TemporaryFile_run_festivalr*   remove)r   rH   datar%   scmcmdfstderrr"   r"   r#   rM      s6   



"zFestivalBackend._processrs   rt   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 + r:   r   z	Command "z" returned exit status z, output is:
N)r<   r=   shlexsplitr@   subr>   CalledProcessErrorseekr-   
returncoder   )rs   rt   outputerrr"   r"   r#   ro     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   rQ   rU   N)rY   )r^   phoner"   r"   r#   r_   /  s   " z4FestivalBackend._postprocess_syll.<locals>.<genexpr>r;   Nc                 s   s    | ]	}|d kr|V  qdS r\   r"   )r^   or"   r"   r#   r_   0  s    )r   rb   )r   rJ   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   )r^   r   r0   rJ   r?   r"   r#   r_   7  s
    
z4FestivalBackend._postprocess_word.<locals>.<genexpr>r;   N)syllablerb   )r0   r   rJ   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 outputrU   )r   r   parser   appendrb   )r0   rP   rJ   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 ))rU   z(nil nil nil))r   r]   r   r"   r#   
<listcomp>L  s
    z0FestivalBackend._postprocess.<locals>.<listcomp>ra   )ry   )r0   r   rJ   r?   r"   r   r#   rN   I  s   zFestivalBackend._postprocess)NFN)%__name__
__module____qualname____doc__r'   strr   r	   r
   boolr   r   staticmethodr%   classmethodr1   r   r   r9   rF   r   rG   r   intr   rO   rS   rZ   rK   rM   r   ro   r   r   r   rN   __classcell__r"   r"   r    r#   r   #   sV    
(

&	* $(r   )r   r*   r(   r@   rx   r6   r<   rk   rg   loggingr   r   typingr   r   r   r   r	   r
   phonemizer.backend.baser   phonemizer.backend.festivalr   phonemizer.separatorr   phonemizer.utilsr   r   r   r"   r"   r"   r#   <module>   s"    