
pyttsx3 的 `save_to_file()` 方法在 macos(尤其是 apple silicon)上常因引擎初始化顺序或音频后端不兼容而卡死;正确做法是确保 `say()` 和 `save_to_file()` 调用共存,并始终调用 `runandwait()` 一次完成所有任务。
pyttsx3 是一个纯 Python 的离线文本转语音库,跨平台支持良好,但在 macOS(特别是搭载 Apple Silicon 的 Mac)上,其默认使用的 nsss(macOS 原生语音服务)后端对 save_to_file() 的支持存在限制:它本身并不原生支持直接导出为 MP3 或其他音频文件格式。save_to_file() 实际上依赖于底层 TTS 引擎的录音能力,而 nsss 引擎在 macOS 上仅支持实时语音播放,不支持后台录音写入文件——这正是脚本“无限挂起”的根本原因。
✅ 正确用法(关键原则):
save_to_file() 必须与 say() 配合使用(即同一 Engine 实例中先 say()、再 save_to_file()),且 runAndWait() 仅需调用一次,用于触发整个队列(含播放和录制)。单独调用 save_to_file() 而无 say(),会导致引擎等待一个永远不会发生的语音事件,从而阻塞。
以下是经过验证的可靠示例(适用于 macOS + Apple Silicon):
import pyttsx3
engine = pyttsx3.init()
# 可选:设置语速、音量、语音(如需中文请确认系统已安装对应语音)
engine.setProperty('rate', 150)
engine.setProperty('volume', 0.9)
# ⚠️ 关键:必须先调用 say()(哪怕只是占位内容),再调用 save_to_file()
engine.say(" ") # 占位发音(可为空格或静音短语),避免空队列
engine.save_to_file("Hello, this is a test.", "output.mp3")
# ✅ runAndWait() 执行全部排队操作:播放占位音 + 录制目标文本
engine.runAndWait()? 注意事项:
- save_to_file() 不会生成 MP3 文件——在 macOS 上,它实际输出的是 .aiff 格式(即使扩展名写 .mp3)。系统会自动保存为 AIFF(Apple 的无损音频格式),但文件扩展名仍为 .mp3。如需真正 MP3,需后续用 pydub + ffmpeg 转码:
pip install pydub # 确保已安装 ffmpeg:brew install ffmpeg
from pydub import AudioSegment audio = AudioSegment.from_file("output.mp3", format="aiff") # 实际是 AIFF audio.export("output.mp3", format="mp3") - Windows 用户可切换为 sapi5 引擎,Linux 用户可选用 espeak,二者对 save_to_file() 支持更稳定;
- macOS 用户若需稳定导出,推荐改用 gtts(Google Text-to-Speech,需联网)+ pygame 或 pydub 播放,或直接使用 pyttsx3 + subprocess 调用 say -o 命令行工具(原生支持 .aiff/.m4a 导出)。
? 总结:pyttsx3.save_to_file() 在 macOS 上并非“功能缺失”,而是设计依赖于引擎的录音上下文。务必遵循“say() 占位 + save_to_file() 写入 + runAndWait() 触发”三步模式,并理解其输出本质为 AIFF。绕过此限制的最佳实践,是在离线需求与格式要求间合理权衡,必要时引入轻量级音频处理工具链。










