当前位置:   article > 正文

Python语音合成小工具(PyQt5 + pyttsx3)_pyttsx3支持的语音包?

pyttsx3支持的语音包?

TTS简介

TTS(Text To Speech)是一种语音合成技术,可以让机器将输入文本以语音的方式播放出来,实现机器说话的效果。

TTS分成语音处理及语音合成,先由机器识别输入的文字,再根据语音库进行语音合成。现在有很多可供调用的TTS接口,比如百度智能云的语音合成接口。微软在Windows系统中也提供了TTS的接口,可以调用此接口实现离线的TTS语音合成功能。

本文将使用pyttsx3库作为示范,编写一个语音合成小工具。

pyttsx3官方文档:https://pyttsx3.readthedocs.io 

本文源码已上传至GitHub:

https://github.com/XMNHCAS/SpeechSynthesisTool


安装需要的包

安装PyQt5及其GUI设计工具

  1. # 安装PyQt5
  2. pip install PyQt5
  3. # 安装PyQt5设计器
  4. pip install PyQt5Designer

本文使用的编辑器是VSCode,不是PyCharm,使用PyQt5的方式可能存在差异,具体使用时可以根据实际情况进行配置。 

安装pyttsx3

pip install pyttsx3

UI界面 

可参考下图设计简单的GUI界面,由于本文主要为功能实例,故不考虑界面美观问题。

界面应有一个文本输入框,用以输入将要转化为语音的文本,同时需要一个播放按钮,用以触发语音播放的方法。语速、音量和语言可以按需选择。 

使用PyQt5的设计工具,可以根据以上配置的GUI界面生成以下UI(XML)代码:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ui version="4.0">
  3. <class>Form</class>
  4. <widget class="QWidget" name="Form">
  5. <property name="geometry">
  6. <rect>
  7. <x>0</x>
  8. <y>0</y>
  9. <width>313</width>
  10. <height>284</height>
  11. </rect>
  12. </property>
  13. <property name="windowTitle">
  14. <string>语音合成器</string>
  15. </property>
  16. <property name="windowIcon">
  17. <iconset>
  18. <normaloff>voice.ico</normaloff>voice.ico</iconset>
  19. </property>
  20. <widget class="QWidget" name="verticalLayoutWidget">
  21. <property name="geometry">
  22. <rect>
  23. <x>10</x>
  24. <y>10</y>
  25. <width>291</width>
  26. <height>261</height>
  27. </rect>
  28. </property>
  29. <layout class="QVBoxLayout" name="verticalLayout">
  30. <property name="spacing">
  31. <number>20</number>
  32. </property>
  33. <item>
  34. <layout class="QHBoxLayout" name="horizontalLayout_2">
  35. <item>
  36. <widget class="QLabel" name="label">
  37. <property name="text">
  38. <string>播报文本</string>
  39. </property>
  40. <property name="alignment">
  41. <set>Qt::AlignJustify|Qt::AlignTop</set>
  42. </property>
  43. </widget>
  44. </item>
  45. <item>
  46. <widget class="QTextEdit" name="tbx_text"/>
  47. </item>
  48. </layout>
  49. </item>
  50. <item>
  51. <layout class="QHBoxLayout" name="horizontalLayout_4">
  52. <item>
  53. <widget class="QLabel" name="label_3">
  54. <property name="text">
  55. <string>语速</string>
  56. </property>
  57. </widget>
  58. </item>
  59. <item>
  60. <widget class="QSlider" name="slider_rate">
  61. <property name="maximum">
  62. <number>300</number>
  63. </property>
  64. <property name="orientation">
  65. <enum>Qt::Horizontal</enum>
  66. </property>
  67. </widget>
  68. </item>
  69. <item>
  70. <widget class="QLabel" name="label_rate">
  71. <property name="minimumSize">
  72. <size>
  73. <width>30</width>
  74. <height>0</height>
  75. </size>
  76. </property>
  77. <property name="text">
  78. <string>0</string>
  79. </property>
  80. <property name="alignment">
  81. <set>Qt::AlignCenter</set>
  82. </property>
  83. </widget>
  84. </item>
  85. </layout>
  86. </item>
  87. <item>
  88. <layout class="QHBoxLayout" name="horizontalLayout_3">
  89. <item>
  90. <widget class="QLabel" name="label_2">
  91. <property name="text">
  92. <string>音量</string>
  93. </property>
  94. </widget>
  95. </item>
  96. <item>
  97. <widget class="QSlider" name="slider_volumn">
  98. <property name="maximum">
  99. <number>100</number>
  100. </property>
  101. <property name="orientation">
  102. <enum>Qt::Horizontal</enum>
  103. </property>
  104. </widget>
  105. </item>
  106. <item>
  107. <widget class="QLabel" name="label_volumn">
  108. <property name="minimumSize">
  109. <size>
  110. <width>30</width>
  111. <height>0</height>
  112. </size>
  113. </property>
  114. <property name="text">
  115. <string>0</string>
  116. </property>
  117. <property name="alignment">
  118. <set>Qt::AlignCenter</set>
  119. </property>
  120. </widget>
  121. </item>
  122. </layout>
  123. </item>
  124. <item>
  125. <layout class="QHBoxLayout" name="horizontalLayout">
  126. <item>
  127. <widget class="QLabel" name="label_4">
  128. <property name="text">
  129. <string>选择语言</string>
  130. </property>
  131. </widget>
  132. </item>
  133. <item>
  134. <widget class="QRadioButton" name="rbtn_zh">
  135. <property name="text">
  136. <string>中文</string>
  137. </property>
  138. <property name="checked">
  139. <bool>true</bool>
  140. </property>
  141. </widget>
  142. </item>
  143. <item>
  144. <widget class="QRadioButton" name="rbtn_en">
  145. <property name="text">
  146. <string>英文</string>
  147. </property>
  148. </widget>
  149. </item>
  150. </layout>
  151. </item>
  152. <item>
  153. <layout class="QHBoxLayout" name="horizontalLayout_5">
  154. <item>
  155. <widget class="QLabel" name="label_5">
  156. <property name="minimumSize">
  157. <size>
  158. <width>60</width>
  159. <height>0</height>
  160. </size>
  161. </property>
  162. <property name="text">
  163. <string/>
  164. </property>
  165. </widget>
  166. </item>
  167. <item>
  168. <widget class="QPushButton" name="btn_play">
  169. <property name="minimumSize">
  170. <size>
  171. <width>0</width>
  172. <height>30</height>
  173. </size>
  174. </property>
  175. <property name="text">
  176. <string>播放</string>
  177. </property>
  178. </widget>
  179. </item>
  180. </layout>
  181. </item>
  182. </layout>
  183. </widget>
  184. </widget>
  185. <resources/>
  186. <connections/>
  187. </ui>

最后再使用PyQt5的界面工具,可以根据以上UI的代码,生成以下的窗体类:

  1. # -*- coding: utf-8 -*-
  2. # Form implementation generated from reading ui file 'd:\Program\VSCode\Python\TTS_PyQT\tts_form.ui'
  3. #
  4. # Created by: PyQt5 UI code generator 5.15.7
  5. #
  6. # WARNING: Any manual changes made to this file will be lost when pyuic5 is
  7. # run again. Do not edit this file unless you know what you are doing.
  8. from PyQt5 import QtCore, QtGui, QtWidgets
  9. class Ui_Form(object):
  10. def setupUi(self, Form):
  11. Form.setObjectName("Form")
  12. Form.resize(313, 284)
  13. icon = QtGui.QIcon()
  14. icon.addPixmap(
  15. QtGui.QPixmap("./voice.ico"),
  16. QtGui.QIcon.Normal, QtGui.QIcon.Off)
  17. Form.setWindowIcon(icon)
  18. self.verticalLayoutWidget = QtWidgets.QWidget(Form)
  19. self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 291, 261))
  20. self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
  21. self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
  22. self.verticalLayout.setContentsMargins(0, 0, 0, 0)
  23. self.verticalLayout.setSpacing(20)
  24. self.verticalLayout.setObjectName("verticalLayout")
  25. self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
  26. self.horizontalLayout_2.setObjectName("horizontalLayout_2")
  27. self.label = QtWidgets.QLabel(self.verticalLayoutWidget)
  28. self.label.setAlignment(QtCore.Qt.AlignJustify | QtCore.Qt.AlignTop)
  29. self.label.setObjectName("label")
  30. self.horizontalLayout_2.addWidget(self.label)
  31. self.tbx_text = QtWidgets.QTextEdit(self.verticalLayoutWidget)
  32. self.tbx_text.setObjectName("tbx_text")
  33. self.horizontalLayout_2.addWidget(self.tbx_text)
  34. self.verticalLayout.addLayout(self.horizontalLayout_2)
  35. self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
  36. self.horizontalLayout_4.setObjectName("horizontalLayout_4")
  37. self.label_3 = QtWidgets.QLabel(self.verticalLayoutWidget)
  38. self.label_3.setObjectName("label_3")
  39. self.horizontalLayout_4.addWidget(self.label_3)
  40. self.slider_rate = QtWidgets.QSlider(self.verticalLayoutWidget)
  41. self.slider_rate.setMaximum(300)
  42. self.slider_rate.setOrientation(QtCore.Qt.Horizontal)
  43. self.slider_rate.setObjectName("slider_rate")
  44. self.horizontalLayout_4.addWidget(self.slider_rate)
  45. self.label_rate = QtWidgets.QLabel(self.verticalLayoutWidget)
  46. self.label_rate.setMinimumSize(QtCore.QSize(30, 0))
  47. self.label_rate.setAlignment(QtCore.Qt.AlignCenter)
  48. self.label_rate.setObjectName("label_rate")
  49. self.horizontalLayout_4.addWidget(self.label_rate)
  50. self.verticalLayout.addLayout(self.horizontalLayout_4)
  51. self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
  52. self.horizontalLayout_3.setObjectName("horizontalLayout_3")
  53. self.label_2 = QtWidgets.QLabel(self.verticalLayoutWidget)
  54. self.label_2.setObjectName("label_2")
  55. self.horizontalLayout_3.addWidget(self.label_2)
  56. self.slider_volumn = QtWidgets.QSlider(self.verticalLayoutWidget)
  57. self.slider_volumn.setMaximum(100)
  58. self.slider_volumn.setOrientation(QtCore.Qt.Horizontal)
  59. self.slider_volumn.setObjectName("slider_volumn")
  60. self.horizontalLayout_3.addWidget(self.slider_volumn)
  61. self.label_volumn = QtWidgets.QLabel(self.verticalLayoutWidget)
  62. self.label_volumn.setMinimumSize(QtCore.QSize(30, 0))
  63. self.label_volumn.setAlignment(QtCore.Qt.AlignCenter)
  64. self.label_volumn.setObjectName("label_volumn")
  65. self.horizontalLayout_3.addWidget(self.label_volumn)
  66. self.verticalLayout.addLayout(self.horizontalLayout_3)
  67. self.horizontalLayout = QtWidgets.QHBoxLayout()
  68. self.horizontalLayout.setObjectName("horizontalLayout")
  69. self.label_4 = QtWidgets.QLabel(self.verticalLayoutWidget)
  70. self.label_4.setObjectName("label_4")
  71. self.horizontalLayout.addWidget(self.label_4)
  72. self.rbtn_zh = QtWidgets.QRadioButton(self.verticalLayoutWidget)
  73. self.rbtn_zh.setChecked(True)
  74. self.rbtn_zh.setObjectName("rbtn_zh")
  75. self.horizontalLayout.addWidget(self.rbtn_zh)
  76. self.rbtn_en = QtWidgets.QRadioButton(self.verticalLayoutWidget)
  77. self.rbtn_en.setObjectName("rbtn_en")
  78. self.horizontalLayout.addWidget(self.rbtn_en)
  79. self.verticalLayout.addLayout(self.horizontalLayout)
  80. self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
  81. self.horizontalLayout_5.setObjectName("horizontalLayout_5")
  82. self.label_5 = QtWidgets.QLabel(self.verticalLayoutWidget)
  83. self.label_5.setMinimumSize(QtCore.QSize(60, 0))
  84. self.label_5.setText("")
  85. self.label_5.setObjectName("label_5")
  86. self.horizontalLayout_5.addWidget(self.label_5)
  87. self.btn_play = QtWidgets.QPushButton(self.verticalLayoutWidget)
  88. self.btn_play.setMinimumSize(QtCore.QSize(0, 30))
  89. self.btn_play.setObjectName("btn_play")
  90. self.horizontalLayout_5.addWidget(self.btn_play)
  91. self.verticalLayout.addLayout(self.horizontalLayout_5)
  92. self.retranslateUi(Form)
  93. QtCore.QMetaObject.connectSlotsByName(Form)
  94. def retranslateUi(self, Form):
  95. _translate = QtCore.QCoreApplication.translate
  96. Form.setWindowTitle(_translate("Form", "语音合成器"))
  97. self.label.setText(_translate("Form", "播报文本"))
  98. self.label_3.setText(_translate("Form", "语速"))
  99. self.label_rate.setText(_translate("Form", "0"))
  100. self.label_2.setText(_translate("Form", "音量"))
  101. self.label_volumn.setText(_translate("Form", "0"))
  102. self.label_4.setText(_translate("Form", "选择语言"))
  103. self.rbtn_zh.setText(_translate("Form", "中文"))
  104. self.rbtn_en.setText(_translate("Form", "英文"))
  105. self.btn_play.setText(_translate("Form", "播放"))

如果直接复制此代码,可能会出现图标丢失的问题。这个需要根据实际情况修改icon的配置,并添加要使用的ico图标文件。 


功能代码

语音工具类

首先我们需要初始化并获取语音合成用的语音引擎对象。

  1. # tts对象
  2. engine = pyttsx3.init()

我们可以通过该对象的setProperty方法,对语音合成的对象的属性进行修改:

属性名解释
rate以每分钟字数表示的整数语速
volume音量,取值范围为[0.0, 1.0]
voices语音的字符串标识符

语音工具类代码如下,代码含义可参考注释:

  1. import pyttsx3
  2. class VoiceEngine():
  3. '''
  4. tts 语音工具类
  5. '''
  6. def __init__(self):
  7. '''
  8. 初始化
  9. '''
  10. # tts对象
  11. self.__engine = pyttsx3.init()
  12. # 语速
  13. self.__rate = 150
  14. # 音量
  15. self.__volume = 100
  16. # 语音ID,0为中文,1为英文
  17. self.__voice = 0
  18. @property
  19. def Rate(self):
  20. '''
  21. 语速属性
  22. '''
  23. return self.__rate
  24. @Rate.setter
  25. def Rate(self, value):
  26. self.__rate = value
  27. @property
  28. def Volume(self):
  29. '''
  30. 音量属性
  31. '''
  32. return self.__volume
  33. @Volume.setter
  34. def Volume(self, value):
  35. self.__volume = value
  36. @property
  37. def VoiceID(self):
  38. '''
  39. 语音ID:0 -- 中文;1 -- 英文
  40. '''
  41. return self.__voice
  42. @VoiceID.setter
  43. def VoiceID(self, value):
  44. self.__voice = value
  45. def Say(self, text):
  46. '''
  47. 播放语音
  48. '''
  49. self.__engine.setProperty('rate', self.__rate)
  50. self.__engine.setProperty('volume', self.__volume)
  51. # 获取可用语音列表,并设置语音
  52. voices = self.__engine.getProperty('voices')
  53. self.__engine.setProperty('voice', voices[self.__voice].id)
  54. # 保存语音文件
  55. # self.__engine.save_to_file(text, 'test.mp3')
  56. self.__engine.say(text)
  57. self.__engine.runAndWait()
  58. self.__engine.stop()

窗体类

我们可以创建一个继承于我们刚刚创建的PyQt5的窗体类,并为窗体的拖拽事件和点击事件注册回调函数,同时创建一个语音工具类的实例,用以实现指定事件触发时需要执行的语音操作。

  1. import sys
  2. import _thread as th
  3. from PyQt5.QtWidgets import QMainWindow, QApplication
  4. from Ui_tts_form import Ui_Form
  5. class MainWindow(QMainWindow, Ui_Form):
  6. '''
  7. 窗体类
  8. '''
  9. def __init__(self, parent=None):
  10. '''
  11. 初始化窗体
  12. '''
  13. super(MainWindow, self).__init__(parent)
  14. self.setupUi(self)
  15. # 获取tts工具类实例
  16. self.engine = VoiceEngine()
  17. self.__isPlaying = False
  18. # 设置初始文本
  19. self.tbx_text.setText('床前明月光,疑似地上霜。\n举头望明月,低头思故乡。')
  20. # 进度条数据绑定到label中显示
  21. self.slider_rate.valueChanged.connect(self.setRateTextValue)
  22. self.slider_volumn.valueChanged.connect(self.setVolumnTextValue)
  23. # 设置进度条初始值
  24. self.slider_rate.setValue(self.engine.Rate)
  25. self.slider_volumn.setValue(self.engine.Volume)
  26. # RadioButton选择事件
  27. self.rbtn_zh.toggled.connect(self.onSelectVoice_zh)
  28. self.rbtn_en.toggled.connect(self.onSelectVoice_en)
  29. # 播放按钮点击事件
  30. self.btn_play.clicked.connect(self.onPlayButtonClick)
  31. def setRateTextValue(self):
  32. '''
  33. 修改语速label文本值
  34. '''
  35. value = self.slider_rate.value()
  36. self.label_rate.setText(str(value))
  37. self.engine.Rate = value
  38. def setVolumnTextValue(self):
  39. '''
  40. 修改音量label文本值
  41. '''
  42. value = self.slider_volumn.value()
  43. self.label_volumn.setText(str(value / 100))
  44. self.engine.Volume = value
  45. def onSelectVoice_zh(self):
  46. '''
  47. 修改中文的语音配置及默认播放文本
  48. '''
  49. self.tbx_text.setText('床前明月光,疑似地上霜。\n举头望明月,低头思故乡。')
  50. self.engine.VoiceID = 0
  51. def onSelectVoice_en(self):
  52. '''
  53. 修改英文的语音配置及默认的播放文本
  54. '''
  55. self.tbx_text.setText('Hello World')
  56. self.engine.VoiceID = 1
  57. def playVoice(self):
  58. '''
  59. 播放
  60. '''
  61. if self.__isPlaying is not True:
  62. self.__isPlaying = True
  63. text = self.tbx_text.toPlainText()
  64. self.engine.Say(text)
  65. self.__isPlaying = False
  66. def onPlayButtonClick(self):
  67. '''
  68. 播放按钮点击事件
  69. 开启线程新线程播放语音,避免窗体因为语音播放而假卡死
  70. '''
  71. th.start_new_thread(self.playVoice, ())

完整代码

  1. import sys
  2. import _thread as th
  3. from PyQt5.QtWidgets import QMainWindow, QApplication
  4. from Ui_tts_form import Ui_Form
  5. import pyttsx3
  6. class VoiceEngine():
  7. '''
  8. tts 语音工具类
  9. '''
  10. def __init__(self):
  11. '''
  12. 初始化
  13. '''
  14. # tts对象
  15. self.__engine = pyttsx3.init()
  16. # 语速
  17. self.__rate = 150
  18. # 音量
  19. self.__volume = 100
  20. # 语音ID,0为中文,1为英文
  21. self.__voice = 0
  22. @property
  23. def Rate(self):
  24. '''
  25. 语速属性
  26. '''
  27. return self.__rate
  28. @Rate.setter
  29. def Rate(self, value):
  30. self.__rate = value
  31. @property
  32. def Volume(self):
  33. '''
  34. 音量属性
  35. '''
  36. return self.__volume
  37. @Volume.setter
  38. def Volume(self, value):
  39. self.__volume = value
  40. @property
  41. def VoiceID(self):
  42. '''
  43. 语音ID:0 -- 中文;1 -- 英文
  44. '''
  45. return self.__voice
  46. @VoiceID.setter
  47. def VoiceID(self, value):
  48. self.__voice = value
  49. def Say(self, text):
  50. '''
  51. 播放语音
  52. '''
  53. self.__engine.setProperty('rate', self.__rate)
  54. self.__engine.setProperty('volume', self.__volume)
  55. voices = self.__engine.getProperty('voices')
  56. self.__engine.setProperty('voice', voices[self.__voice])
  57. # 保存语音文件
  58. # self.__engine.save_to_file(text, 'test.mp3')
  59. self.__engine.say(text)
  60. self.__engine.runAndWait()
  61. self.__engine.stop()
  62. class MainWindow(QMainWindow, Ui_Form):
  63. '''
  64. 窗体类
  65. '''
  66. def __init__(self, parent=None):
  67. '''
  68. 初始化窗体
  69. '''
  70. super(MainWindow, self).__init__(parent)
  71. self.setupUi(self)
  72. # 获取tts工具类实例
  73. self.engine = VoiceEngine()
  74. self.__isPlaying = False
  75. # 设置初始文本
  76. self.tbx_text.setText('床前明月光,疑似地上霜。\n举头望明月,低头思故乡。')
  77. # 进度条数据绑定到label中显示
  78. self.slider_rate.valueChanged.connect(self.setRateTextValue)
  79. self.slider_volumn.valueChanged.connect(self.setVolumnTextValue)
  80. # 设置进度条初始值
  81. self.slider_rate.setValue(self.engine.Rate)
  82. self.slider_volumn.setValue(self.engine.Volume)
  83. # RadioButton选择事件
  84. self.rbtn_zh.toggled.connect(self.onSelectVoice_zh)
  85. self.rbtn_en.toggled.connect(self.onSelectVoice_en)
  86. # 播放按钮点击事件
  87. self.btn_play.clicked.connect(self.onPlayButtonClick)
  88. def setRateTextValue(self):
  89. '''
  90. 修改语速label文本值
  91. '''
  92. value = self.slider_rate.value()
  93. self.label_rate.setText(str(value))
  94. self.engine.Rate = value
  95. def setVolumnTextValue(self):
  96. '''
  97. 修改音量label文本值
  98. '''
  99. value = self.slider_volumn.value()
  100. self.label_volumn.setText(str(value / 100))
  101. self.engine.Volume = value
  102. def onSelectVoice_zh(self):
  103. '''
  104. 修改中文的语音配置及默认播放文本
  105. '''
  106. self.tbx_text.setText('床前明月光,疑似地上霜。\n举头望明月,低头思故乡。')
  107. self.engine.VoiceID = 0
  108. def onSelectVoice_en(self):
  109. '''
  110. 修改英文的语音配置及默认的播放文本
  111. '''
  112. self.tbx_text.setText('Hello World')
  113. self.engine.VoiceID = 1
  114. def playVoice(self):
  115. '''
  116. 播放
  117. '''
  118. if self.__isPlaying is not True:
  119. self.__isPlaying = True
  120. text = self.tbx_text.toPlainText()
  121. self.engine.Say(text)
  122. self.__isPlaying = False
  123. def onPlayButtonClick(self):
  124. '''
  125. 修改语速label文本值
  126. '''
  127. th.start_new_thread(self.playVoice, ())
  128. if __name__ == "__main__":
  129. '''
  130. 主函数
  131. '''
  132. app = QApplication(sys.argv)
  133. form = MainWindow()
  134. form.show()
  135. sys.exit(app.exec_())

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/88115
推荐阅读
相关标签
  

闽ICP备14008679号