We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[Bug] Letter-by-letter pronunciation not possible
### Describe the bug

I'd like to force the TTS model to pronounce a word letter by letter, e.g. "ARD" should be pronounced "A R D" (/ˌeɪˌɑːɹdˈiː/). In systems with SSML support (#752) you could use `<speak><say-as interpret-as="verbatim">ard</say-as></speak>`, but another way would be fine as well.

Espeak supports this even for words not in its dictionary by adding periods between the characters: `espeak-ng --ipa -v en-us "A.R.D."` is read /ˌeɪˌɑːɹdˈiː/.

This doesn't work in Coqui because the input for Espeak is split at punctuation characters and each chunk `["A", "R", "D"]` is phonemized separately: https://github.com/coqui-ai/TTS/blob/bc0a532c7a7e165338da6711ea362cdbe9761820/TTS/tts/utils/text/phonemizers/base.py#L129

This results in the word, not the letter pronunciation of "a" being chosen (ɐ instead of eɪ). I could change `_phonemize_preprocess()` to pass the input to Espeak with punctuation included, but I'm not sure about the side effects. Is there a specific reason to do it this way?

### To Reproduce

```python
from TTS.api import TTS
p = TTS(model_name="tts_models/en/ljspeech/vits", gpu=False).synthesizer.tts_model.tokenizer.phonemizer
p.phonemize("A.R.D.")
```
Output: `'ˈɐ.ˈɑːɹ.d|ˈiː.'`

### Expected behavior

Expected output: `ˌeɪˌɑːɹdˈiː`

### Logs

_No response_

### Environment

```shell
{
    "CUDA": {
        "GPU": [],
        "available": false,
        "version": "11.7"
    },
    "Packages": {
        "PyTorch_debug": false,
        "PyTorch_version": "2.0.0+cu117",
        "TTS": "0.10.2",
        "numpy": "1.22.4"
    },
    "System": {
        "OS": "Linux",
        "architecture": [
            "64bit",
            "ELF"
        ],
        "processor": "x86_64",
        "python": "3.10.8",
        "version": "#42~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 18 17:40:00 UTC 2"
    }
}
```


### Additional context

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `TTS/tts/utils/text/phonemizers/espeak_wrapper.py`
Content:
```
1 import logging
2 import re
3 import subprocess
4 from typing import Dict, List
5 
6 from packaging.version import Version
7 
8 from TTS.tts.utils.text.phonemizers.base import BasePhonemizer
9 from TTS.tts.utils.text.punctuation import Punctuation
10 
11 
12 def is_tool(name):
13     from shutil import which
14 
15     return which(name) is not None
16 
17 
18 # Use a regex pattern to match the espeak version, because it may be
19 # symlinked to espeak-ng, which moves the version bits to another spot.
20 espeak_version_pattern = re.compile(r"text-to-speech:\s(?P<version>\d+\.\d+(\.\d+)?)")
21 
22 
23 def get_espeak_version():
24     output = subprocess.getoutput("espeak --version")
25     match = espeak_version_pattern.search(output)
26 
27     return match.group("version")
28 
29 
30 def get_espeakng_version():
31     output = subprocess.getoutput("espeak-ng --version")
32     return output.split()[3]
33 
34 
35 # priority: espeakng > espeak
36 if is_tool("espeak-ng"):
37     _DEF_ESPEAK_LIB = "espeak-ng"
38     _DEF_ESPEAK_VER = get_espeakng_version()
39 elif is_tool("espeak"):
40     _DEF_ESPEAK_LIB = "espeak"
41     _DEF_ESPEAK_VER = get_espeak_version()
42 else:
43     _DEF_ESPEAK_LIB = None
44     _DEF_ESPEAK_VER = None
45 
46 
47 def _espeak_exe(espeak_lib: str, args: List, sync=False) -> List[str]:
48     """Run espeak with the given arguments."""
49     cmd = [
50         espeak_lib,
51         "-q",
52         "-b",
53         "1",  # UTF8 text encoding
54     ]
55     cmd.extend(args)
56     logging.debug("espeakng: executing %s", repr(cmd))
57 
58     with subprocess.Popen(
59         cmd,
60         stdout=subprocess.PIPE,
61         stderr=subprocess.STDOUT,
62     ) as p:
63         res = iter(p.stdout.readline, b"")
64         if not sync:
65             p.stdout.close()
66             if p.stderr:
67                 p.stderr.close()
68             if p.stdin:
69                 p.stdin.close()
70             return res
71         res2 = []
72         for line in res:
73             res2.append(line)
74         p.stdout.close()
75         if p.stderr:
76             p.stderr.close()
77         if p.stdin:
78             p.stdin.close()
79         p.wait()
80     return res2
81 
82 
83 class ESpeak(BasePhonemizer):
84     """ESpeak wrapper calling `espeak` or `espeak-ng` from the command-line the perform G2P
85 
86     Args:
87         language (str):
88             Valid language code for the used backend.
89 
90         backend (str):
91             Name of the backend library to use. `espeak` or `espeak-ng`. If None, set automatically
92             prefering `espeak-ng` over `espeak`. Defaults to None.
93 
94         punctuations (str):
95             Characters to be treated as punctuation. Defaults to Punctuation.default_puncs().
96 
97         keep_puncs (bool):
98             If True, keep the punctuations after phonemization. Defaults to True.
99 
100     Example:
101 
102         >>> from TTS.tts.utils.text.phonemizers import ESpeak
103         >>> phonemizer = ESpeak("tr")
104         >>> phonemizer.phonemize("Bu Türkçe, bir örnektir.", separator="|")
105         'b|ʊ t|ˈø|r|k|tʃ|ɛ, b|ɪ|r œ|r|n|ˈɛ|c|t|ɪ|r.'
106 
107     """
108 
109     _ESPEAK_LIB = _DEF_ESPEAK_LIB
110     _ESPEAK_VER = _DEF_ESPEAK_VER
111 
112     def __init__(self, language: str, backend=None, punctuations=Punctuation.default_puncs(), keep_puncs=True):
113         if self._ESPEAK_LIB is None:
114             raise Exception(" [!] No espeak backend found. Install espeak-ng or espeak to your system.")
115         self.backend = self._ESPEAK_LIB
116 
117         # band-aid for backwards compatibility
118         if language == "en":
119             language = "en-us"
120         if language == "zh-cn":
121             language = "cmn"
122 
123         super().__init__(language, punctuations=punctuations, keep_puncs=keep_puncs)
124         if backend is not None:
125             self.backend = backend
126 
127     @property
128     def backend(self):
129         return self._ESPEAK_LIB
130 
131     @property
132     def backend_version(self):
133         return self._ESPEAK_VER
134 
135     @backend.setter
136     def backend(self, backend):
137         if backend not in ["espeak", "espeak-ng"]:
138             raise Exception("Unknown backend: %s" % backend)
139         self._ESPEAK_LIB = backend
140         self._ESPEAK_VER = get_espeakng_version() if backend == "espeak-ng" else get_espeak_version()
141 
142     def auto_set_espeak_lib(self) -> None:
143         if is_tool("espeak-ng"):
144             self._ESPEAK_LIB = "espeak-ng"
145             self._ESPEAK_VER = get_espeakng_version()
146         elif is_tool("espeak"):
147             self._ESPEAK_LIB = "espeak"
148             self._ESPEAK_VER = get_espeak_version()
149         else:
150             raise Exception("Cannot set backend automatically. espeak-ng or espeak not found")
151 
152     @staticmethod
153     def name():
154         return "espeak"
155 
156     def phonemize_espeak(self, text: str, separator: str = "|", tie=False) -> str:
157         """Convert input text to phonemes.
158 
159         Args:
160             text (str):
161                 Text to be converted to phonemes.
162 
163             tie (bool, optional) : When True use a '͡' character between
164                 consecutive characters of a single phoneme. Else separate phoneme
165                 with '_'. This option requires espeak>=1.49. Default to False.
166         """
167         # set arguments
168         args = ["-v", f"{self._language}"]
169         # espeak and espeak-ng parses `ipa` differently
170         if tie:
171             # use '͡' between phonemes
172             if self.backend == "espeak":
173                 args.append("--ipa=1")
174             else:
175                 args.append("--ipa=3")
176         else:
177             # split with '_'
178             if self.backend == "espeak":
179                 if Version(self.backend_version) >= Version("1.48.15"):
180                     args.append("--ipa=1")
181                 else:
182                     args.append("--ipa=3")
183             else:
184                 args.append("--ipa=1")
185         if tie:
186             args.append("--tie=%s" % tie)
187 
188         args.append('"' + text + '"')
189         # compute phonemes
190         phonemes = ""
191         for line in _espeak_exe(self._ESPEAK_LIB, args, sync=True):
192             logging.debug("line: %s", repr(line))
193             ph_decoded = line.decode("utf8").strip()
194             # espeak need to skip first two characters of the retuned text:
195             #   version 1.48.03: "_ p_ɹ_ˈaɪ_ɚ t_ə n_oʊ_v_ˈɛ_m_b_ɚ t_w_ˈɛ_n_t_i t_ˈuː\n"
196             #   version 1.48.15: " p_ɹ_ˈaɪ_ɚ t_ə n_oʊ_v_ˈɛ_m_b_ɚ t_w_ˈɛ_n_t_i t_ˈuː\n"
197             # espeak-ng need to skip the first character of the retuned text:
198             #   "_p_ɹ_ˈaɪ_ɚ t_ə n_oʊ_v_ˈɛ_m_b_ɚ t_w_ˈɛ_n_t_i t_ˈuː\n"
199 
200             # dealing with the conditions descrived above
201             ph_decoded = ph_decoded[:1].replace("_", "") + ph_decoded[1:]
202 
203             # espeak-ng backend can add language flags that need to be removed:
204             #   "sɛʁtˈɛ̃ mˈo kɔm (en)fˈʊtbɔːl(fr) ʒenˈɛʁ de- flˈaɡ də- lˈɑ̃ɡ."
205             # phonemize needs to remove the language flags of the returned text:
206             #   "sɛʁtˈɛ̃ mˈo kɔm fˈʊtbɔːl ʒenˈɛʁ de- flˈaɡ də- lˈɑ̃ɡ."
207             ph_decoded = re.sub(r"\(.+?\)", "", ph_decoded)
208 
209             phonemes += ph_decoded.strip()
210         return phonemes.replace("_", separator)
211 
212     def _phonemize(self, text, separator=None):
213         return self.phonemize_espeak(text, separator, tie=False)
214 
215     @staticmethod
216     def supported_languages() -> Dict:
217         """Get a dictionary of supported languages.
218 
219         Returns:
220             Dict: Dictionary of language codes.
221         """
222         if _DEF_ESPEAK_LIB is None:
223             return {}
224         args = ["--voices"]
225         langs = {}
226         count = 0
227         for line in _espeak_exe(_DEF_ESPEAK_LIB, args, sync=True):
228             line = line.decode("utf8").strip()
229             if count > 0:
230                 cols = line.split()
231                 lang_code = cols[1]
232                 lang_name = cols[3]
233                 langs[lang_code] = lang_name
234             logging.debug("line: %s", repr(line))
235             count += 1
236         return langs
237 
238     def version(self) -> str:
239         """Get the version of the used backend.
240 
241         Returns:
242             str: Version of the used backend.
243         """
244         args = ["--version"]
245         for line in _espeak_exe(self.backend, args, sync=True):
246             version = line.decode("utf8").strip().split()[2]
247             logging.debug("line: %s", repr(line))
248             return version
249 
250     @classmethod
251     def is_available(cls):
252         """Return true if ESpeak is available else false"""
253         return is_tool("espeak") or is_tool("espeak-ng")
254 
255 
256 if __name__ == "__main__":
257     e = ESpeak(language="en-us")
258     print(e.supported_languages())
259     print(e.version())
260     print(e.language)
261     print(e.name())
262     print(e.is_available())
263 
264     e = ESpeak(language="en-us", keep_puncs=False)
265     print("`" + e.phonemize("hello how are you today?") + "`")
266 
267     e = ESpeak(language="en-us", keep_puncs=True)
268     print("`" + e.phonemize("hello how are you today?") + "`")
269
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/TTS/tts/utils/text/phonemizers/espeak_wrapper.py b/TTS/tts/utils/text/phonemizers/espeak_wrapper.py
--- a/TTS/tts/utils/text/phonemizers/espeak_wrapper.py
+++ b/TTS/tts/utils/text/phonemizers/espeak_wrapper.py
@@ -185,20 +185,16 @@
         if tie:
             args.append("--tie=%s" % tie)
 
-        args.append('"' + text + '"')
+        args.append(text)
         # compute phonemes
         phonemes = ""
         for line in _espeak_exe(self._ESPEAK_LIB, args, sync=True):
             logging.debug("line: %s", repr(line))
             ph_decoded = line.decode("utf8").strip()
-            # espeak need to skip first two characters of the retuned text:
-            #   version 1.48.03: "_ p_ɹ_ˈaɪ_ɚ t_ə n_oʊ_v_ˈɛ_m_b_ɚ t_w_ˈɛ_n_t_i t_ˈuː\n"
+            # espeak:
             #   version 1.48.15: " p_ɹ_ˈaɪ_ɚ t_ə n_oʊ_v_ˈɛ_m_b_ɚ t_w_ˈɛ_n_t_i t_ˈuː\n"
-            # espeak-ng need to skip the first character of the retuned text:
-            #   "_p_ɹ_ˈaɪ_ɚ t_ə n_oʊ_v_ˈɛ_m_b_ɚ t_w_ˈɛ_n_t_i t_ˈuː\n"
-
-            # dealing with the conditions descrived above
-            ph_decoded = ph_decoded[:1].replace("_", "") + ph_decoded[1:]
+            # espeak-ng:
+            #   "p_ɹ_ˈaɪ_ɚ t_ə n_oʊ_v_ˈɛ_m_b_ɚ t_w_ˈɛ_n_t_i t_ˈuː\n"
 
             # espeak-ng backend can add language flags that need to be removed:
             #   "sɛʁtˈɛ̃ mˈo kɔm (en)fˈʊtbɔːl(fr) ʒenˈɛʁ de- flˈaɡ də- lˈɑ̃ɡ."

{"golden_diff": "diff --git a/TTS/tts/utils/text/phonemizers/espeak_wrapper.py b/TTS/tts/utils/text/phonemizers/espeak_wrapper.py\n--- a/TTS/tts/utils/text/phonemizers/espeak_wrapper.py\n+++ b/TTS/tts/utils/text/phonemizers/espeak_wrapper.py\n@@ -185,20 +185,16 @@\n         if tie:\n             args.append(\"--tie=%s\" % tie)\n \n-        args.append('\"' + text + '\"')\n+        args.append(text)\n         # compute phonemes\n         phonemes = \"\"\n         for line in _espeak_exe(self._ESPEAK_LIB, args, sync=True):\n             logging.debug(\"line: %s\", repr(line))\n             ph_decoded = line.decode(\"utf8\").strip()\n-            # espeak need to skip first two characters of the retuned text:\n-            #   version 1.48.03: \"_ p_\u0279_\u02c8a\u026a_\u025a t_\u0259 n_o\u028a_v_\u02c8\u025b_m_b_\u025a t_w_\u02c8\u025b_n_t_i t_\u02c8u\u02d0\\n\"\n+            # espeak:\n             #   version 1.48.15: \" p_\u0279_\u02c8a\u026a_\u025a t_\u0259 n_o\u028a_v_\u02c8\u025b_m_b_\u025a t_w_\u02c8\u025b_n_t_i t_\u02c8u\u02d0\\n\"\n-            # espeak-ng need to skip the first character of the retuned text:\n-            #   \"_p_\u0279_\u02c8a\u026a_\u025a t_\u0259 n_o\u028a_v_\u02c8\u025b_m_b_\u025a t_w_\u02c8\u025b_n_t_i t_\u02c8u\u02d0\\n\"\n-\n-            # dealing with the conditions descrived above\n-            ph_decoded = ph_decoded[:1].replace(\"_\", \"\") + ph_decoded[1:]\n+            # espeak-ng:\n+            #   \"p_\u0279_\u02c8a\u026a_\u025a t_\u0259 n_o\u028a_v_\u02c8\u025b_m_b_\u025a t_w_\u02c8\u025b_n_t_i t_\u02c8u\u02d0\\n\"\n \n             # espeak-ng backend can add language flags that need to be removed:\n             #   \"s\u025b\u0281t\u02c8\u025b\u0303 m\u02c8o k\u0254m (en)f\u02c8\u028atb\u0254\u02d0l(fr) \u0292en\u02c8\u025b\u0281 de- fl\u02c8a\u0261 d\u0259- l\u02c8\u0251\u0303\u0261.\"\n", "issue": "[Bug] Letter-by-letter pronunciation not possible\n### Describe the bug\n\nI'd like to force the TTS model to pronounce a word letter by letter, e.g. \"ARD\" should be pronounced \"A R D\" (/\u02cce\u026a\u02cc\u0251\u02d0\u0279d\u02c8i\u02d0/). In systems with SSML support (#752) you could use `<speak><say-as interpret-as=\"verbatim\">ard</say-as></speak>`, but another way would be fine as well.\r\n\r\nEspeak supports this even for words not in its dictionary by adding periods between the characters: `espeak-ng --ipa -v en-us \"A.R.D.\"` is read /\u02cce\u026a\u02cc\u0251\u02d0\u0279d\u02c8i\u02d0/.\r\n\r\nThis doesn't work in Coqui because the input for Espeak is split at punctuation characters and each chunk `[\"A\", \"R\", \"D\"]` is phonemized separately: https://github.com/coqui-ai/TTS/blob/bc0a532c7a7e165338da6711ea362cdbe9761820/TTS/tts/utils/text/phonemizers/base.py#L129\r\n\r\nThis results in the word, not the letter pronunciation of \"a\" being chosen (\u0250 instead of e\u026a). I could change `_phonemize_preprocess()` to pass the input to Espeak with punctuation included, but I'm not sure about the side effects. Is there a specific reason to do it this way?\n\n### To Reproduce\n\n```python\r\nfrom TTS.api import TTS\r\np = TTS(model_name=\"tts_models/en/ljspeech/vits\", gpu=False).synthesizer.tts_model.tokenizer.phonemizer\r\np.phonemize(\"A.R.D.\")\r\n```\r\nOutput: `'\u02c8\u0250.\u02c8\u0251\u02d0\u0279.d|\u02c8i\u02d0.'`\n\n### Expected behavior\n\nExpected output: `\u02cce\u026a\u02cc\u0251\u02d0\u0279d\u02c8i\u02d0`\n\n### Logs\n\n_No response_\n\n### Environment\n\n```shell\n{\r\n    \"CUDA\": {\r\n        \"GPU\": [],\r\n        \"available\": false,\r\n        \"version\": \"11.7\"\r\n    },\r\n    \"Packages\": {\r\n        \"PyTorch_debug\": false,\r\n        \"PyTorch_version\": \"2.0.0+cu117\",\r\n        \"TTS\": \"0.10.2\",\r\n        \"numpy\": \"1.22.4\"\r\n    },\r\n    \"System\": {\r\n        \"OS\": \"Linux\",\r\n        \"architecture\": [\r\n            \"64bit\",\r\n            \"ELF\"\r\n        ],\r\n        \"processor\": \"x86_64\",\r\n        \"python\": \"3.10.8\",\r\n        \"version\": \"#42~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 18 17:40:00 UTC 2\"\r\n    }\r\n}\n```\n\n\n### Additional context\n\n_No response_\n", "before_files": [{"content": "import logging\nimport re\nimport subprocess\nfrom typing import Dict, List\n\nfrom packaging.version import Version\n\nfrom TTS.tts.utils.text.phonemizers.base import BasePhonemizer\nfrom TTS.tts.utils.text.punctuation import Punctuation\n\n\ndef is_tool(name):\n    from shutil import which\n\n    return which(name) is not None\n\n\n# Use a regex pattern to match the espeak version, because it may be\n# symlinked to espeak-ng, which moves the version bits to another spot.\nespeak_version_pattern = re.compile(r\"text-to-speech:\\s(?P<version>\\d+\\.\\d+(\\.\\d+)?)\")\n\n\ndef get_espeak_version():\n    output = subprocess.getoutput(\"espeak --version\")\n    match = espeak_version_pattern.search(output)\n\n    return match.group(\"version\")\n\n\ndef get_espeakng_version():\n    output = subprocess.getoutput(\"espeak-ng --version\")\n    return output.split()[3]\n\n\n# priority: espeakng > espeak\nif is_tool(\"espeak-ng\"):\n    _DEF_ESPEAK_LIB = \"espeak-ng\"\n    _DEF_ESPEAK_VER = get_espeakng_version()\nelif is_tool(\"espeak\"):\n    _DEF_ESPEAK_LIB = \"espeak\"\n    _DEF_ESPEAK_VER = get_espeak_version()\nelse:\n    _DEF_ESPEAK_LIB = None\n    _DEF_ESPEAK_VER = None\n\n\ndef _espeak_exe(espeak_lib: str, args: List, sync=False) -> List[str]:\n    \"\"\"Run espeak with the given arguments.\"\"\"\n    cmd = [\n        espeak_lib,\n        \"-q\",\n        \"-b\",\n        \"1\",  # UTF8 text encoding\n    ]\n    cmd.extend(args)\n    logging.debug(\"espeakng: executing %s\", repr(cmd))\n\n    with subprocess.Popen(\n        cmd,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.STDOUT,\n    ) as p:\n        res = iter(p.stdout.readline, b\"\")\n        if not sync:\n            p.stdout.close()\n            if p.stderr:\n                p.stderr.close()\n            if p.stdin:\n                p.stdin.close()\n            return res\n        res2 = []\n        for line in res:\n            res2.append(line)\n        p.stdout.close()\n        if p.stderr:\n            p.stderr.close()\n        if p.stdin:\n            p.stdin.close()\n        p.wait()\n    return res2\n\n\nclass ESpeak(BasePhonemizer):\n    \"\"\"ESpeak wrapper calling `espeak` or `espeak-ng` from the command-line the perform G2P\n\n    Args:\n        language (str):\n            Valid language code for the used backend.\n\n        backend (str):\n            Name of the backend library to use. `espeak` or `espeak-ng`. If None, set automatically\n            prefering `espeak-ng` over `espeak`. Defaults to None.\n\n        punctuations (str):\n            Characters to be treated as punctuation. Defaults to Punctuation.default_puncs().\n\n        keep_puncs (bool):\n            If True, keep the punctuations after phonemization. Defaults to True.\n\n    Example:\n\n        >>> from TTS.tts.utils.text.phonemizers import ESpeak\n        >>> phonemizer = ESpeak(\"tr\")\n        >>> phonemizer.phonemize(\"Bu T\u00fcrk\u00e7e, bir \u00f6rnektir.\", separator=\"|\")\n        'b|\u028a t|\u02c8\u00f8|r|k|t\u0283|\u025b, b|\u026a|r \u0153|r|n|\u02c8\u025b|c|t|\u026a|r.'\n\n    \"\"\"\n\n    _ESPEAK_LIB = _DEF_ESPEAK_LIB\n    _ESPEAK_VER = _DEF_ESPEAK_VER\n\n    def __init__(self, language: str, backend=None, punctuations=Punctuation.default_puncs(), keep_puncs=True):\n        if self._ESPEAK_LIB is None:\n            raise Exception(\" [!] No espeak backend found. Install espeak-ng or espeak to your system.\")\n        self.backend = self._ESPEAK_LIB\n\n        # band-aid for backwards compatibility\n        if language == \"en\":\n            language = \"en-us\"\n        if language == \"zh-cn\":\n            language = \"cmn\"\n\n        super().__init__(language, punctuations=punctuations, keep_puncs=keep_puncs)\n        if backend is not None:\n            self.backend = backend\n\n    @property\n    def backend(self):\n        return self._ESPEAK_LIB\n\n    @property\n    def backend_version(self):\n        return self._ESPEAK_VER\n\n    @backend.setter\n    def backend(self, backend):\n        if backend not in [\"espeak\", \"espeak-ng\"]:\n            raise Exception(\"Unknown backend: %s\" % backend)\n        self._ESPEAK_LIB = backend\n        self._ESPEAK_VER = get_espeakng_version() if backend == \"espeak-ng\" else get_espeak_version()\n\n    def auto_set_espeak_lib(self) -> None:\n        if is_tool(\"espeak-ng\"):\n            self._ESPEAK_LIB = \"espeak-ng\"\n            self._ESPEAK_VER = get_espeakng_version()\n        elif is_tool(\"espeak\"):\n            self._ESPEAK_LIB = \"espeak\"\n            self._ESPEAK_VER = get_espeak_version()\n        else:\n            raise Exception(\"Cannot set backend automatically. espeak-ng or espeak not found\")\n\n    @staticmethod\n    def name():\n        return \"espeak\"\n\n    def phonemize_espeak(self, text: str, separator: str = \"|\", tie=False) -> str:\n        \"\"\"Convert input text to phonemes.\n\n        Args:\n            text (str):\n                Text to be converted to phonemes.\n\n            tie (bool, optional) : When True use a '\u0361' character between\n                consecutive characters of a single phoneme. Else separate phoneme\n                with '_'. This option requires espeak>=1.49. Default to False.\n        \"\"\"\n        # set arguments\n        args = [\"-v\", f\"{self._language}\"]\n        # espeak and espeak-ng parses `ipa` differently\n        if tie:\n            # use '\u0361' between phonemes\n            if self.backend == \"espeak\":\n                args.append(\"--ipa=1\")\n            else:\n                args.append(\"--ipa=3\")\n        else:\n            # split with '_'\n            if self.backend == \"espeak\":\n                if Version(self.backend_version) >= Version(\"1.48.15\"):\n                    args.append(\"--ipa=1\")\n                else:\n                    args.append(\"--ipa=3\")\n            else:\n                args.append(\"--ipa=1\")\n        if tie:\n            args.append(\"--tie=%s\" % tie)\n\n        args.append('\"' + text + '\"')\n        # compute phonemes\n        phonemes = \"\"\n        for line in _espeak_exe(self._ESPEAK_LIB, args, sync=True):\n            logging.debug(\"line: %s\", repr(line))\n            ph_decoded = line.decode(\"utf8\").strip()\n            # espeak need to skip first two characters of the retuned text:\n            #   version 1.48.03: \"_ p_\u0279_\u02c8a\u026a_\u025a t_\u0259 n_o\u028a_v_\u02c8\u025b_m_b_\u025a t_w_\u02c8\u025b_n_t_i t_\u02c8u\u02d0\\n\"\n            #   version 1.48.15: \" p_\u0279_\u02c8a\u026a_\u025a t_\u0259 n_o\u028a_v_\u02c8\u025b_m_b_\u025a t_w_\u02c8\u025b_n_t_i t_\u02c8u\u02d0\\n\"\n            # espeak-ng need to skip the first character of the retuned text:\n            #   \"_p_\u0279_\u02c8a\u026a_\u025a t_\u0259 n_o\u028a_v_\u02c8\u025b_m_b_\u025a t_w_\u02c8\u025b_n_t_i t_\u02c8u\u02d0\\n\"\n\n            # dealing with the conditions descrived above\n            ph_decoded = ph_decoded[:1].replace(\"_\", \"\") + ph_decoded[1:]\n\n            # espeak-ng backend can add language flags that need to be removed:\n            #   \"s\u025b\u0281t\u02c8\u025b\u0303 m\u02c8o k\u0254m (en)f\u02c8\u028atb\u0254\u02d0l(fr) \u0292en\u02c8\u025b\u0281 de- fl\u02c8a\u0261 d\u0259- l\u02c8\u0251\u0303\u0261.\"\n            # phonemize needs to remove the language flags of the returned text:\n            #   \"s\u025b\u0281t\u02c8\u025b\u0303 m\u02c8o k\u0254m f\u02c8\u028atb\u0254\u02d0l \u0292en\u02c8\u025b\u0281 de- fl\u02c8a\u0261 d\u0259- l\u02c8\u0251\u0303\u0261.\"\n            ph_decoded = re.sub(r\"\\(.+?\\)\", \"\", ph_decoded)\n\n            phonemes += ph_decoded.strip()\n        return phonemes.replace(\"_\", separator)\n\n    def _phonemize(self, text, separator=None):\n        return self.phonemize_espeak(text, separator, tie=False)\n\n    @staticmethod\n    def supported_languages() -> Dict:\n        \"\"\"Get a dictionary of supported languages.\n\n        Returns:\n            Dict: Dictionary of language codes.\n        \"\"\"\n        if _DEF_ESPEAK_LIB is None:\n            return {}\n        args = [\"--voices\"]\n        langs = {}\n        count = 0\n        for line in _espeak_exe(_DEF_ESPEAK_LIB, args, sync=True):\n            line = line.decode(\"utf8\").strip()\n            if count > 0:\n                cols = line.split()\n                lang_code = cols[1]\n                lang_name = cols[3]\n                langs[lang_code] = lang_name\n            logging.debug(\"line: %s\", repr(line))\n            count += 1\n        return langs\n\n    def version(self) -> str:\n        \"\"\"Get the version of the used backend.\n\n        Returns:\n            str: Version of the used backend.\n        \"\"\"\n        args = [\"--version\"]\n        for line in _espeak_exe(self.backend, args, sync=True):\n            version = line.decode(\"utf8\").strip().split()[2]\n            logging.debug(\"line: %s\", repr(line))\n            return version\n\n    @classmethod\n    def is_available(cls):\n        \"\"\"Return true if ESpeak is available else false\"\"\"\n        return is_tool(\"espeak\") or is_tool(\"espeak-ng\")\n\n\nif __name__ == \"__main__\":\n    e = ESpeak(language=\"en-us\")\n    print(e.supported_languages())\n    print(e.version())\n    print(e.language)\n    print(e.name())\n    print(e.is_available())\n\n    e = ESpeak(language=\"en-us\", keep_puncs=False)\n    print(\"`\" + e.phonemize(\"hello how are you today?\") + \"`\")\n\n    e = ESpeak(language=\"en-us\", keep_puncs=True)\n    print(\"`\" + e.phonemize(\"hello how are you today?\") + \"`\")\n", "path": "TTS/tts/utils/text/phonemizers/espeak_wrapper.py"}], "after_files": [{"content": "import logging\nimport re\nimport subprocess\nfrom typing import Dict, List\n\nfrom packaging.version import Version\n\nfrom TTS.tts.utils.text.phonemizers.base import BasePhonemizer\nfrom TTS.tts.utils.text.punctuation import Punctuation\n\n\ndef is_tool(name):\n    from shutil import which\n\n    return which(name) is not None\n\n\n# Use a regex pattern to match the espeak version, because it may be\n# symlinked to espeak-ng, which moves the version bits to another spot.\nespeak_version_pattern = re.compile(r\"text-to-speech:\\s(?P<version>\\d+\\.\\d+(\\.\\d+)?)\")\n\n\ndef get_espeak_version():\n    output = subprocess.getoutput(\"espeak --version\")\n    match = espeak_version_pattern.search(output)\n\n    return match.group(\"version\")\n\n\ndef get_espeakng_version():\n    output = subprocess.getoutput(\"espeak-ng --version\")\n    return output.split()[3]\n\n\n# priority: espeakng > espeak\nif is_tool(\"espeak-ng\"):\n    _DEF_ESPEAK_LIB = \"espeak-ng\"\n    _DEF_ESPEAK_VER = get_espeakng_version()\nelif is_tool(\"espeak\"):\n    _DEF_ESPEAK_LIB = \"espeak\"\n    _DEF_ESPEAK_VER = get_espeak_version()\nelse:\n    _DEF_ESPEAK_LIB = None\n    _DEF_ESPEAK_VER = None\n\n\ndef _espeak_exe(espeak_lib: str, args: List, sync=False) -> List[str]:\n    \"\"\"Run espeak with the given arguments.\"\"\"\n    cmd = [\n        espeak_lib,\n        \"-q\",\n        \"-b\",\n        \"1\",  # UTF8 text encoding\n    ]\n    cmd.extend(args)\n    logging.debug(\"espeakng: executing %s\", repr(cmd))\n\n    with subprocess.Popen(\n        cmd,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.STDOUT,\n    ) as p:\n        res = iter(p.stdout.readline, b\"\")\n        if not sync:\n            p.stdout.close()\n            if p.stderr:\n                p.stderr.close()\n            if p.stdin:\n                p.stdin.close()\n            return res\n        res2 = []\n        for line in res:\n            res2.append(line)\n        p.stdout.close()\n        if p.stderr:\n            p.stderr.close()\n        if p.stdin:\n            p.stdin.close()\n        p.wait()\n    return res2\n\n\nclass ESpeak(BasePhonemizer):\n    \"\"\"ESpeak wrapper calling `espeak` or `espeak-ng` from the command-line the perform G2P\n\n    Args:\n        language (str):\n            Valid language code for the used backend.\n\n        backend (str):\n            Name of the backend library to use. `espeak` or `espeak-ng`. If None, set automatically\n            prefering `espeak-ng` over `espeak`. Defaults to None.\n\n        punctuations (str):\n            Characters to be treated as punctuation. Defaults to Punctuation.default_puncs().\n\n        keep_puncs (bool):\n            If True, keep the punctuations after phonemization. Defaults to True.\n\n    Example:\n\n        >>> from TTS.tts.utils.text.phonemizers import ESpeak\n        >>> phonemizer = ESpeak(\"tr\")\n        >>> phonemizer.phonemize(\"Bu T\u00fcrk\u00e7e, bir \u00f6rnektir.\", separator=\"|\")\n        'b|\u028a t|\u02c8\u00f8|r|k|t\u0283|\u025b, b|\u026a|r \u0153|r|n|\u02c8\u025b|c|t|\u026a|r.'\n\n    \"\"\"\n\n    _ESPEAK_LIB = _DEF_ESPEAK_LIB\n    _ESPEAK_VER = _DEF_ESPEAK_VER\n\n    def __init__(self, language: str, backend=None, punctuations=Punctuation.default_puncs(), keep_puncs=True):\n        if self._ESPEAK_LIB is None:\n            raise Exception(\" [!] No espeak backend found. Install espeak-ng or espeak to your system.\")\n        self.backend = self._ESPEAK_LIB\n\n        # band-aid for backwards compatibility\n        if language == \"en\":\n            language = \"en-us\"\n        if language == \"zh-cn\":\n            language = \"cmn\"\n\n        super().__init__(language, punctuations=punctuations, keep_puncs=keep_puncs)\n        if backend is not None:\n            self.backend = backend\n\n    @property\n    def backend(self):\n        return self._ESPEAK_LIB\n\n    @property\n    def backend_version(self):\n        return self._ESPEAK_VER\n\n    @backend.setter\n    def backend(self, backend):\n        if backend not in [\"espeak\", \"espeak-ng\"]:\n            raise Exception(\"Unknown backend: %s\" % backend)\n        self._ESPEAK_LIB = backend\n        self._ESPEAK_VER = get_espeakng_version() if backend == \"espeak-ng\" else get_espeak_version()\n\n    def auto_set_espeak_lib(self) -> None:\n        if is_tool(\"espeak-ng\"):\n            self._ESPEAK_LIB = \"espeak-ng\"\n            self._ESPEAK_VER = get_espeakng_version()\n        elif is_tool(\"espeak\"):\n            self._ESPEAK_LIB = \"espeak\"\n            self._ESPEAK_VER = get_espeak_version()\n        else:\n            raise Exception(\"Cannot set backend automatically. espeak-ng or espeak not found\")\n\n    @staticmethod\n    def name():\n        return \"espeak\"\n\n    def phonemize_espeak(self, text: str, separator: str = \"|\", tie=False) -> str:\n        \"\"\"Convert input text to phonemes.\n\n        Args:\n            text (str):\n                Text to be converted to phonemes.\n\n            tie (bool, optional) : When True use a '\u0361' character between\n                consecutive characters of a single phoneme. Else separate phoneme\n                with '_'. This option requires espeak>=1.49. Default to False.\n        \"\"\"\n        # set arguments\n        args = [\"-v\", f\"{self._language}\"]\n        # espeak and espeak-ng parses `ipa` differently\n        if tie:\n            # use '\u0361' between phonemes\n            if self.backend == \"espeak\":\n                args.append(\"--ipa=1\")\n            else:\n                args.append(\"--ipa=3\")\n        else:\n            # split with '_'\n            if self.backend == \"espeak\":\n                if Version(self.backend_version) >= Version(\"1.48.15\"):\n                    args.append(\"--ipa=1\")\n                else:\n                    args.append(\"--ipa=3\")\n            else:\n                args.append(\"--ipa=1\")\n        if tie:\n            args.append(\"--tie=%s\" % tie)\n\n        args.append(text)\n        # compute phonemes\n        phonemes = \"\"\n        for line in _espeak_exe(self._ESPEAK_LIB, args, sync=True):\n            logging.debug(\"line: %s\", repr(line))\n            ph_decoded = line.decode(\"utf8\").strip()\n            # espeak:\n            #   version 1.48.15: \" p_\u0279_\u02c8a\u026a_\u025a t_\u0259 n_o\u028a_v_\u02c8\u025b_m_b_\u025a t_w_\u02c8\u025b_n_t_i t_\u02c8u\u02d0\\n\"\n            # espeak-ng:\n            #   \"p_\u0279_\u02c8a\u026a_\u025a t_\u0259 n_o\u028a_v_\u02c8\u025b_m_b_\u025a t_w_\u02c8\u025b_n_t_i t_\u02c8u\u02d0\\n\"\n\n            # espeak-ng backend can add language flags that need to be removed:\n            #   \"s\u025b\u0281t\u02c8\u025b\u0303 m\u02c8o k\u0254m (en)f\u02c8\u028atb\u0254\u02d0l(fr) \u0292en\u02c8\u025b\u0281 de- fl\u02c8a\u0261 d\u0259- l\u02c8\u0251\u0303\u0261.\"\n            # phonemize needs to remove the language flags of the returned text:\n            #   \"s\u025b\u0281t\u02c8\u025b\u0303 m\u02c8o k\u0254m f\u02c8\u028atb\u0254\u02d0l \u0292en\u02c8\u025b\u0281 de- fl\u02c8a\u0261 d\u0259- l\u02c8\u0251\u0303\u0261.\"\n            ph_decoded = re.sub(r\"\\(.+?\\)\", \"\", ph_decoded)\n\n            phonemes += ph_decoded.strip()\n        return phonemes.replace(\"_\", separator)\n\n    def _phonemize(self, text, separator=None):\n        return self.phonemize_espeak(text, separator, tie=False)\n\n    @staticmethod\n    def supported_languages() -> Dict:\n        \"\"\"Get a dictionary of supported languages.\n\n        Returns:\n            Dict: Dictionary of language codes.\n        \"\"\"\n        if _DEF_ESPEAK_LIB is None:\n            return {}\n        args = [\"--voices\"]\n        langs = {}\n        count = 0\n        for line in _espeak_exe(_DEF_ESPEAK_LIB, args, sync=True):\n            line = line.decode(\"utf8\").strip()\n            if count > 0:\n                cols = line.split()\n                lang_code = cols[1]\n                lang_name = cols[3]\n                langs[lang_code] = lang_name\n            logging.debug(\"line: %s\", repr(line))\n            count += 1\n        return langs\n\n    def version(self) -> str:\n        \"\"\"Get the version of the used backend.\n\n        Returns:\n            str: Version of the used backend.\n        \"\"\"\n        args = [\"--version\"]\n        for line in _espeak_exe(self.backend, args, sync=True):\n            version = line.decode(\"utf8\").strip().split()[2]\n            logging.debug(\"line: %s\", repr(line))\n            return version\n\n    @classmethod\n    def is_available(cls):\n        \"\"\"Return true if ESpeak is available else false\"\"\"\n        return is_tool(\"espeak\") or is_tool(\"espeak-ng\")\n\n\nif __name__ == \"__main__\":\n    e = ESpeak(language=\"en-us\")\n    print(e.supported_languages())\n    print(e.version())\n    print(e.language)\n    print(e.name())\n    print(e.is_available())\n\n    e = ESpeak(language=\"en-us\", keep_puncs=False)\n    print(\"`\" + e.phonemize(\"hello how are you today?\") + \"`\")\n\n    e = ESpeak(language=\"en-us\", keep_puncs=True)\n    print(\"`\" + e.phonemize(\"hello how are you today?\") + \"`\")\n", "path": "TTS/tts/utils/text/phonemizers/espeak_wrapper.py"}]}