快速语音示例

本快速语音示例读取用户提供的文本。

快速语音 示例演示了如何在 TextToSpeech 类型中在 Qt Quick 应用程序中读取文本和控制语音。

该示例使用 Qt Quick Controls 来提供对语音的音调、音量和速度的控制。它还允许用户选择引擎、语言和声音。

初始化 TextToSpeech

首先,我们初始化文本到语音对象 tts

    TextToSpeech {
        id: tts
        volume: volumeSlider.value
        pitch: pitchSlider.value
        rate: rateSlider.value

获取状态

使用条件语句来更新页脚中的标签 statusLabel

        onStateChanged: updateStateLabel(state)

        function updateStateLabel(state)
        {
            switch (state) {
                case TextToSpeech.Ready:
                    statusLabel.text = qsTr("Ready")
                    break
                case TextToSpeech.Speaking:
                    statusLabel.text = qsTr("Speaking")
                    break
                case TextToSpeech.Paused:
                    statusLabel.text = qsTr("Paused...")
                    break
                case TextToSpeech.Error:
                    statusLabel.text = qsTr("Error!")
                    break
            }

边读边高亮显示单词

使用 TextArea input 获取要输入的文本,使用 onSayingWord 信号作为触发器,并且可以知道要高亮显示单词的位置。

        onSayingWord: (word, id, start, length)=> {
            input.select(start, start + length)

在这里声明了 TextArea input

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 8
        id: inputForm

        TextArea {
            id: input
            wrapMode: TextEdit.WordWrap
            text: qsTr("Hello, world!")
            Layout.fillWidth: true
            Layout.minimumHeight: implicitHeight
            font.pointSize: 24
        }

控制语音

使用 Button 类型并通过 RowLayout 进行排列,配置以控制 TextToSpeech tts

说话按钮

创建了一个标记为 "说话" 的 Button。如果 tts 的状态属性为 PausedReady,则该按钮可用。

        RowLayout {
            Button {
                text: qsTr("Speak")
                enabled: [TextToSpeech.Paused, TextToSpeech.Ready].includes(tts.state)

当按钮被点击时,获取目标设备上的可用声音,并将 tts.voice 设置为 voicesComboBox 当前选定的声音。然后调用 TextToSpeech::say() 并传递 inputbox 中的文本。

                onClicked: {
//! [say0]
                    let voices = tts.availableVoices()
                    tts.voice = voices[voicesComboBox.currentIndex]
//! [say1]
                    tts.say(input.text)
                }

暂停、继续和停止按钮

这些按钮的实现与 Speak 按钮相似

            Button {
                text: qsTr("Pause")
                enabled: tts.state == TextToSpeech.Speaking
                onClicked: tts.pause()
                visible: tts.engineCapabilities & TextToSpeech.Capabilities.PauseResume
            }
//! [pause]
//! [resume]
            Button {
                text: qsTr("Resume")
                enabled: tts.state == TextToSpeech.Paused
                onClicked: tts.resume()
                visible: tts.engineCapabilities & TextToSpeech.Capabilities.PauseResume
            }
//! [resume]
            Button {
                text: qsTr("Stop")
                enabled: [TextToSpeech.Speaking, TextToSpeech.Paused].includes(tts.state)
                onClicked: tts.stop()
            }
        }

选择文本到语音选项

使用 GridLayout 排列用于选择引擎、区域设置、声音、音量、音调和速度选项的控件和标签。

选择引擎、区域设置和声音

使用了一组 ComboBox 组件来选择这些参数。

在发动机选择 ComboBox 中,使用 tts.availableEngines() 作为模式。

当激活 onActivated 时,会分配 tts.engine 当前 ComboBox 当前索引处的文本。

            Text {
                text: qsTr("Engine:")
            }
            ComboBox {
                id: enginesComboBox
                Layout.fillWidth: true
                model: tts.availableEngines()
                onActivated: {
                    tts.engine = textAt(currentIndex)
                    updateLocales()
                    updateVoices()

上述代码的最后两行显示了在此处还会更新可用的区域和声音,因为它们依赖于所选的发动机。这些函数在接下来的部分中进行说明。

localesComboBox 的实现方式与 engineComboBox 相同,但不会更新可用的发动机。

                }
            }
            Text {
                text: qsTr("Locale:")
            }
            ComboBox {
                id: localesComboBox
                Layout.fillWidth: true
                onActivated: {
                    let locales = tts.availableLocales()
                    tts.locale = locales[currentIndex]
                    updateVoices()
                }
            }
            Text {
                text: qsTr("Voice:")
            }
            ComboBox {
                id: voicesComboBox
                Layout.fillWidth: true
            }
选择音量、音高和

这些控件通过以下方式使用 滑块 实现

            Text {
                text: qsTr("Volume:")
            }
            Slider {
                id: volumeSlider
                from: 0
                to: 1.0
                stepSize: 0.2
                value: 0.8
                Layout.fillWidth: true
            }
            Text {
                text: qsTr("Pitch:")
            }
            Slider {
                id: pitchSlider
                from: -1.0
                to: 1.0
                stepSize: 0.5
                value: 0
                Layout.fillWidth: true
            }
            Text {
                text: qsTr("Rate:")
            }
            Slider {
                id: rateSlider
                from: -1.0
                to: 1.0
                stepSize: 0.5
                value: 0
                Layout.fillWidth: true
            }
        }
    }

更新可用选项

使用 Component.onCompleted 信号,在根 ApplicationWindow 实例化后执行以下操作。

  • enginesComboBox 的索引设置为 tts 中当前设置的发动机。
  • 更新可用的区域和声音。
  • 发出 tts 当前状态。
    Component.onCompleted: {
        enginesComboBox.currentIndex = tts.availableEngines().indexOf(tts.engine)
        // some engines initialize asynchronously
        if (tts.state == TextToSpeech.Ready) {
            engineReady()

全应用使用 updateLocales()updateVoice() 函数,实现方式如下

        } else {
            tts.stateChanged.connect(root.engineReady)
        }

        tts.updateStateLabel(tts.state)
    }

    function engineReady() {
        tts.stateChanged.disconnect(root.engineReady)
        if (tts.state != TextToSpeech.Ready) {
            tts.updateStateLabel(tts.state)
            return;
        }
        updateLocales()
        updateVoices()
    }

    function updateLocales() {
        let allLocales = tts.availableLocales().map((locale) => locale.nativeLanguageName)
        let currentLocaleIndex = allLocales.indexOf(tts.locale.nativeLanguageName)
        localesComboBox.model = allLocales
        localesComboBox.currentIndex = currentLocaleIndex
    }

    function updateVoices() {
        voicesComboBox.model = tts.availableVoices().map((voice) => voice.name)
        let indexOfVoice = tts.availableVoices().indexOf(tts.voice)
        voicesComboBox.currentIndex = indexOfVoice

运行示例

要从 Qt Creator 运行示例,打开 欢迎使用 模式,并在 示例 中选择示例。有关更多信息,请参阅构建和运行示例

示例项目 @ code.qt.io

© 2024 Qt 公司 Ltd。此处包含的文档贡献是其所有者的版权。此处提供的文档是根据自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款许可的。Qt 和相应的标志是芬兰及/或其他国家和地区的 The Qt Company Ltd. 的商标。所有其他商标均为其各自所有者的财产。