<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
TTS(Text To Speech)是一種語音合成技術,可以讓機器將輸入文字以語音的方式播放出來,實現機器說話的效果。
TTS分成語音處理及語音合成,先由機器識別輸入的文字,再根據語音庫進行語音合成。現在有很多可供呼叫的TTS介面,比如百度智慧雲的語音合成介面。微軟在Windows系統中也提供了TTS的介面,可以呼叫此介面實現離線的TTS語音合成功能。
本文將使用pyttsx3庫作為示範,編寫一個語音合成小工具。
pyttsx3官方檔案:https://pyttsx3.readthedocs.io
本文原始碼已上傳至GitHub:
https://github.com/XMNHCAS/SpeechSynthesisTool
安裝PyQt5及其GUI設計工具
# 安裝PyQt5 pip install PyQt5 # 安裝PyQt5設計器 pip install PyQt5Designer
本文使用的編輯器是VSCode,不是PyCharm,使用PyQt5的方式可能存在差異,具體使用時可以根據實際情況進行設定。
安裝pyttsx3
pip install pyttsx3
可參考下圖設計簡單的GUI介面,由於本文主要為功能範例,故不考慮介面美觀問題。
介面應有一個文字輸入框,用以輸入將要轉化為語音的文字,同時需要一個播放按鈕,用以觸發語音播放的方法。語速、音量和語言可以按需選擇。
使用PyQt5的設計工具,可以根據以上設定的GUI介面生成以下UI(XML)程式碼:
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>Form</class> <widget class="QWidget" name="Form"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>313</width> <height>284</height> </rect> </property> <property name="windowTitle"> <string>語音合成器</string> </property> <property name="windowIcon"> <iconset> <normaloff>voice.ico</normaloff>voice.ico</iconset> </property> <widget class="QWidget" name="verticalLayoutWidget"> <property name="geometry"> <rect> <x>10</x> <y>10</y> <width>291</width> <height>261</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout"> <property name="spacing"> <number>20</number> </property> <item> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QLabel" name="label"> <property name="text"> <string>播報文字</string> </property> <property name="alignment"> <set>Qt::AlignJustify|Qt::AlignTop</set> </property> </widget> </item> <item> <widget class="QTextEdit" name="tbx_text"/> </item> </layout> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout_4"> <item> <widget class="QLabel" name="label_3"> <property name="text"> <string>語速</string> </property> </widget> </item> <item> <widget class="QSlider" name="slider_rate"> <property name="maximum"> <number>300</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> <item> <widget class="QLabel" name="label_rate"> <property name="minimumSize"> <size> <width>30</width> <height>0</height> </size> </property> <property name="text"> <string>0</string> </property> <property name="alignment"> <set>Qt::AlignCenter</set> </property> </widget> </item> </layout> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> <widget class="QLabel" name="label_2"> <property name="text"> <string>音量</string> </property> </widget> </item> <item> <widget class="QSlider" name="slider_volumn"> <property name="maximum"> <number>100</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> <item> <widget class="QLabel" name="label_volumn"> <property name="minimumSize"> <size> <width>30</width> <height>0</height> </size> </property> <property name="text"> <string>0</string> </property> <property name="alignment"> <set>Qt::AlignCenter</set> </property> </widget> </item> </layout> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QLabel" name="label_4"> <property name="text"> <string>選擇語言</string> </property> </widget> </item> <item> <widget class="QRadioButton" name="rbtn_zh"> <property name="text"> <string>中文</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item> <widget class="QRadioButton" name="rbtn_en"> <property name="text"> <string>英文</string> </property> </widget> </item> </layout> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout_5"> <item> <widget class="QLabel" name="label_5"> <property name="minimumSize"> <size> <width>60</width> <height>0</height> </size> </property> <property name="text"> <string/> </property> </widget> </item> <item> <widget class="QPushButton" name="btn_play"> <property name="minimumSize"> <size> <width>0</width> <height>30</height> </size> </property> <property name="text"> <string>播放</string> </property> </widget> </item> </layout> </item> </layout> </widget> </widget> <resources/> <connections/> </ui>
最後再使用PyQt5的介面工具,可以根據以上UI的程式碼,生成以下的表單類:
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'd:ProgramVSCodePythonTTS_PyQTtts_form.ui' # # Created by: PyQt5 UI code generator 5.15.7 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") Form.resize(313, 284) icon = QtGui.QIcon() icon.addPixmap( QtGui.QPixmap("./voice.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off) Form.setWindowIcon(icon) self.verticalLayoutWidget = QtWidgets.QWidget(Form) self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 291, 261)) self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(20) self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.label = QtWidgets.QLabel(self.verticalLayoutWidget) self.label.setAlignment(QtCore.Qt.AlignJustify | QtCore.Qt.AlignTop) self.label.setObjectName("label") self.horizontalLayout_2.addWidget(self.label) self.tbx_text = QtWidgets.QTextEdit(self.verticalLayoutWidget) self.tbx_text.setObjectName("tbx_text") self.horizontalLayout_2.addWidget(self.tbx_text) self.verticalLayout.addLayout(self.horizontalLayout_2) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.label_3 = QtWidgets.QLabel(self.verticalLayoutWidget) self.label_3.setObjectName("label_3") self.horizontalLayout_4.addWidget(self.label_3) self.slider_rate = QtWidgets.QSlider(self.verticalLayoutWidget) self.slider_rate.setMaximum(300) self.slider_rate.setOrientation(QtCore.Qt.Horizontal) self.slider_rate.setObjectName("slider_rate") self.horizontalLayout_4.addWidget(self.slider_rate) self.label_rate = QtWidgets.QLabel(self.verticalLayoutWidget) self.label_rate.setMinimumSize(QtCore.QSize(30, 0)) self.label_rate.setAlignment(QtCore.Qt.AlignCenter) self.label_rate.setObjectName("label_rate") self.horizontalLayout_4.addWidget(self.label_rate) self.verticalLayout.addLayout(self.horizontalLayout_4) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.label_2 = QtWidgets.QLabel(self.verticalLayoutWidget) self.label_2.setObjectName("label_2") self.horizontalLayout_3.addWidget(self.label_2) self.slider_volumn = QtWidgets.QSlider(self.verticalLayoutWidget) self.slider_volumn.setMaximum(100) self.slider_volumn.setOrientation(QtCore.Qt.Horizontal) self.slider_volumn.setObjectName("slider_volumn") self.horizontalLayout_3.addWidget(self.slider_volumn) self.label_volumn = QtWidgets.QLabel(self.verticalLayoutWidget) self.label_volumn.setMinimumSize(QtCore.QSize(30, 0)) self.label_volumn.setAlignment(QtCore.Qt.AlignCenter) self.label_volumn.setObjectName("label_volumn") self.horizontalLayout_3.addWidget(self.label_volumn) self.verticalLayout.addLayout(self.horizontalLayout_3) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.label_4 = QtWidgets.QLabel(self.verticalLayoutWidget) self.label_4.setObjectName("label_4") self.horizontalLayout.addWidget(self.label_4) self.rbtn_zh = QtWidgets.QRadioButton(self.verticalLayoutWidget) self.rbtn_zh.setChecked(True) self.rbtn_zh.setObjectName("rbtn_zh") self.horizontalLayout.addWidget(self.rbtn_zh) self.rbtn_en = QtWidgets.QRadioButton(self.verticalLayoutWidget) self.rbtn_en.setObjectName("rbtn_en") self.horizontalLayout.addWidget(self.rbtn_en) self.verticalLayout.addLayout(self.horizontalLayout) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") self.label_5 = QtWidgets.QLabel(self.verticalLayoutWidget) self.label_5.setMinimumSize(QtCore.QSize(60, 0)) self.label_5.setText("") self.label_5.setObjectName("label_5") self.horizontalLayout_5.addWidget(self.label_5) self.btn_play = QtWidgets.QPushButton(self.verticalLayoutWidget) self.btn_play.setMinimumSize(QtCore.QSize(0, 30)) self.btn_play.setObjectName("btn_play") self.horizontalLayout_5.addWidget(self.btn_play) self.verticalLayout.addLayout(self.horizontalLayout_5) self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "語音合成器")) self.label.setText(_translate("Form", "播報文字")) self.label_3.setText(_translate("Form", "語速")) self.label_rate.setText(_translate("Form", "0")) self.label_2.setText(_translate("Form", "音量")) self.label_volumn.setText(_translate("Form", "0")) self.label_4.setText(_translate("Form", "選擇語言")) self.rbtn_zh.setText(_translate("Form", "中文")) self.rbtn_en.setText(_translate("Form", "英文")) self.btn_play.setText(_translate("Form", "播放"))
如果直接複製此程式碼,可能會出現圖示丟失的問題。這個需要根據實際情況修改icon的設定,並新增要使用的ico圖示檔案。
首先我們需要初始化並獲取語音合成用的語音引擎物件。
# tts物件 engine = pyttsx3.init()
我們可以通過該物件的setProperty方法,對語音合成的物件的屬性進行修改:
屬性名 | 解釋 |
rate | 以每分鐘字數表示的整數語速 |
volume | 音量,取值範圍為[0.0, 1.0] |
voices | 語音的字串識別符號 |
語音工具類程式碼如下,程式碼含義可參考註釋:
import pyttsx3 class VoiceEngine(): ''' tts 語音工具類 ''' def __init__(self): ''' 初始化 ''' # tts物件 self.__engine = pyttsx3.init() # 語速 self.__rate = 150 # 音量 self.__volume = 100 # 語音ID,0為中文,1為英文 self.__voice = 0 @property def Rate(self): ''' 語速屬性 ''' return self.__rate @Rate.setter def Rate(self, value): self.__rate = value @property def Volume(self): ''' 音量屬性 ''' return self.__volume @Volume.setter def Volume(self, value): self.__volume = value @property def VoiceID(self): ''' 語音ID:0 -- 中文;1 -- 英文 ''' return self.__voice @VoiceID.setter def VoiceID(self, value): self.__voice = value def Say(self, text): ''' 播放語音 ''' self.__engine.setProperty('rate', self.__rate) self.__engine.setProperty('volume', self.__volume) # 獲取可用語音列表,並設定語音 voices = self.__engine.getProperty('voices') self.__engine.setProperty('voice', voices[self.__voice].id) # 儲存語音檔案 # self.__engine.save_to_file(text, 'test.mp3') self.__engine.say(text) self.__engine.runAndWait() self.__engine.stop()
我們可以建立一個繼承於我們剛剛建立的PyQt5的表單類,併為表單的拖拽事件和點選事件註冊回撥函數,同時建立一個語音工具類的範例,用以實現指定事件觸發時需要執行的語音操作。
import sys import _thread as th from PyQt5.QtWidgets import QMainWindow, QApplication from Ui_tts_form import Ui_Form class MainWindow(QMainWindow, Ui_Form): ''' 表單類 ''' def __init__(self, parent=None): ''' 初始化表單 ''' super(MainWindow, self).__init__(parent) self.setupUi(self) # 獲取tts工具類範例 self.engine = VoiceEngine() self.__isPlaying = False # 設定初始文字 self.tbx_text.setText('床前明月光,疑似地上霜。n舉頭望明月,低頭思故鄉。') # 進度條資料繫結到label中顯示 self.slider_rate.valueChanged.connect(self.setRateTextValue) self.slider_volumn.valueChanged.connect(self.setVolumnTextValue) # 設定進度條初始值 self.slider_rate.setValue(self.engine.Rate) self.slider_volumn.setValue(self.engine.Volume) # RadioButton選擇事件 self.rbtn_zh.toggled.connect(self.onSelectVoice_zh) self.rbtn_en.toggled.connect(self.onSelectVoice_en) # 播放按鈕點選事件 self.btn_play.clicked.connect(self.onPlayButtonClick) def setRateTextValue(self): ''' 修改語速label文字值 ''' value = self.slider_rate.value() self.label_rate.setText(str(value)) self.engine.Rate = value def setVolumnTextValue(self): ''' 修改音量label文字值 ''' value = self.slider_volumn.value() self.label_volumn.setText(str(value / 100)) self.engine.Volume = value def onSelectVoice_zh(self): ''' 修改中文的語音設定及預設播放文字 ''' self.tbx_text.setText('床前明月光,疑似地上霜。n舉頭望明月,低頭思故鄉。') self.engine.VoiceID = 0 def onSelectVoice_en(self): ''' 修改英文的語音設定及預設的播放文字 ''' self.tbx_text.setText('Hello World') self.engine.VoiceID = 1 def playVoice(self): ''' 播放 ''' if self.__isPlaying is not True: self.__isPlaying = True text = self.tbx_text.toPlainText() self.engine.Say(text) self.__isPlaying = False def onPlayButtonClick(self): ''' 播放按鈕點選事件 開啟執行緒新執行緒播放語音,避免表單因為語音播放而假卡死 ''' th.start_new_thread(self.playVoice, ())
import sys import _thread as th from PyQt5.QtWidgets import QMainWindow, QApplication from Ui_tts_form import Ui_Form import pyttsx3 class VoiceEngine(): ''' tts 語音工具類 ''' def __init__(self): ''' 初始化 ''' # tts物件 self.__engine = pyttsx3.init() # 語速 self.__rate = 150 # 音量 self.__volume = 100 # 語音ID,0為中文,1為英文 self.__voice = 0 @property def Rate(self): ''' 語速屬性 ''' return self.__rate @Rate.setter def Rate(self, value): self.__rate = value @property def Volume(self): ''' 音量屬性 ''' return self.__volume @Volume.setter def Volume(self, value): self.__volume = value @property def VoiceID(self): ''' 語音ID:0 -- 中文;1 -- 英文 ''' return self.__voice @VoiceID.setter def VoiceID(self, value): self.__voice = value def Say(self, text): ''' 播放語音 ''' self.__engine.setProperty('rate', self.__rate) self.__engine.setProperty('volume', self.__volume) voices = self.__engine.getProperty('voices') self.__engine.setProperty('voice', voices[self.__voice]) # 儲存語音檔案 # self.__engine.save_to_file(text, 'test.mp3') self.__engine.say(text) self.__engine.runAndWait() self.__engine.stop() class MainWindow(QMainWindow, Ui_Form): ''' 表單類 ''' def __init__(self, parent=None): ''' 初始化表單 ''' super(MainWindow, self).__init__(parent) self.setupUi(self) # 獲取tts工具類範例 self.engine = VoiceEngine() self.__isPlaying = False # 設定初始文字 self.tbx_text.setText('床前明月光,疑似地上霜。n舉頭望明月,低頭思故鄉。') # 進度條資料繫結到label中顯示 self.slider_rate.valueChanged.connect(self.setRateTextValue) self.slider_volumn.valueChanged.connect(self.setVolumnTextValue) # 設定進度條初始值 self.slider_rate.setValue(self.engine.Rate) self.slider_volumn.setValue(self.engine.Volume) # RadioButton選擇事件 self.rbtn_zh.toggled.connect(self.onSelectVoice_zh) self.rbtn_en.toggled.connect(self.onSelectVoice_en) # 播放按鈕點選事件 self.btn_play.clicked.connect(self.onPlayButtonClick) def setRateTextValue(self): ''' 修改語速label文字值 ''' value = self.slider_rate.value() self.label_rate.setText(str(value)) self.engine.Rate = value def setVolumnTextValue(self): ''' 修改音量label文字值 ''' value = self.slider_volumn.value() self.label_volumn.setText(str(value / 100)) self.engine.Volume = value def onSelectVoice_zh(self): ''' 修改中文的語音設定及預設播放文字 ''' self.tbx_text.setText('床前明月光,疑似地上霜。n舉頭望明月,低頭思故鄉。') self.engine.VoiceID = 0 def onSelectVoice_en(self): ''' 修改英文的語音設定及預設的播放文字 ''' self.tbx_text.setText('Hello World') self.engine.VoiceID = 1 def playVoice(self): ''' 播放 ''' if self.__isPlaying is not True: self.__isPlaying = True text = self.tbx_text.toPlainText() self.engine.Say(text) self.__isPlaying = False def onPlayButtonClick(self): ''' 修改語速label文字值 ''' th.start_new_thread(self.playVoice, ()) if __name__ == "__main__": ''' 主函數 ''' app = QApplication(sys.argv) form = MainWindow() form.show() sys.exit(app.exec_())
到此這篇關於基於Python實現語音合成小工具的文章就介紹到這了,更多相關Python語音合成內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45