Skip to content

Upgrade to RealtimeTTS breaks Piper engine on Windows #371

@Magnetilo22

Description

@Magnetilo22

Hi Kolja,

after upgrading RealtimeTTS from 5.7 to 6.0 on Windows Piper engine throws an error:

File "h:\source\RealtimeTTS\tests\piper_test.py", line 19, in
stream = TextToAudioStream(engine)
File "F:.conda\envs\RealtimeTTS\lib\site-packages\RealtimeTTS\text_to_stream.py", line 200, in init
self.load_engine(self.engines[self.engine_index])
File "F:.conda\envs\RealtimeTTS\lib\site-packages\RealtimeTTS\text_to_stream.py", line 215, in load_engine
format, channels, rate = self.engine.get_stream_info()
File "F:.conda\envs\RealtimeTTS\lib\site-packages\RealtimeTTS\engines\piper_engine.py", line 95, in get_stream_info
sample_rate = self._get_sample_rate_from_config()
File "F:.conda\envs\RealtimeTTS\lib\site-packages\RealtimeTTS\engines\piper_engine.py", line 83, in get_sample_rate_from_config
config = json.load(f)
File "F:.conda\envs\RealtimeTTS\lib\json_init
.py", line 293, in load
return loads(fp.read(),
File "F:.conda\envs\RealtimeTTS\lib\encodings\cp1252.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 1510: character maps to

By default, JSON standard dictates that files should be encoded in UTF-8. However, if you don't specify an encoding in Python's open() function, Python falls back to locale.getpreferredencoding(False). On Mac and Linux, this is usually UTF-8, so the code works fine. On Windows, it's often a local codepage (like cp1252), which cannot decode certain special characters or emojis, resulting in the crash.

Can be easily fixed:

 def _get_sample_rate_from_config(self) -> int:
        """
        Reads the sample rate from the Piper voice configuration file.
        
        Returns:
            int: Sample rate from config, or 16000 as fallback
        """
        if not self.voice or not self.voice.config_file:
            return 16000
        
        try:
            with open(self.voice.config_file, 'r', encoding='utf-8') as f:
                config = json.load(f)
                return config.get('audio', {}).get('sample_rate', 16000)
        except (FileNotFoundError, json.JSONDecodeError, KeyError):
            return 16000

Greetings
Magnetilo

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions