Qt 字符串合成语音并播放(QTextToSpeech)

概述

Qt 提供了一个非常方便的类用于将字符串转换成语音并且实现异步播放,该类就是QTextToSpeech,这对于做文本合成语音功能来说非常方便,该类的接口定义很简单。

类说明

QTextToSpeech是从Qt5.8推出的用于方便将文本转换成语音的类,使用say()开始合成文本。通过setLocale()指定语言。要在可用语音之间进行选择,可以使用setVoice()。
注意,语言和声音取决于每个平台上可用的合成器。可以通过静态函数availableEngines()来获取支持的文本到语音引擎插件的列表。

成员函数说明

QTextToSpeech::QTextToSpeech(QObject * parent = nullptr)
QTextToSpeech::QTextToSpeech(const QString &engine, QObject *parent = nullptr)

两个构造函数,其中第二个可以指定语音引擎,如果为空,则使用默认引擎。

QStringList QTextToSpeech::availableEngines()

获取支持的文本到语音引擎插件的列表。这是一个静态函数。

QVector<QLocale> QTextToSpeech::availableLocales() const

获取当前支持的语言环境向量。

QVector<QVoice> QTextToSpeech::availableVoices() const

获取当前语言环境可用的语音矢量。
注意:如果未设置区域,则使用系统区域设置。

void QTextToSpeech::pause()
void QTextToSpeech::resume()
void QTextToSpeech::stop()

这三个分别是暂停、恢复和停止接口。
注意:
pause()功能取决于平台和后端。它可能根本无法工作,也可能需要几秒钟才能生效,或者可能会立即暂停。一些合成器会寻找可以稍后恢复的中断,如句末。
由于Android平台的限制,pause()会停止当前所说的内容,而resume()会从头开始先前排队的句子。

void QTextToSpeech::say(const QString &text)

这是最关键的一个接口,开始合成文本。该功能将启动文本的异步阅读。当前状态可以使用状态属性。一旦合成完成,就会发出一个带有就绪状态的stateChanged()信号。

示例

Qt 自带了一个非常全面的语音示例,直接来看一下官方的示例代码。
先上一个程序主界面:

经测试,可以正常的播报中文和英文,并且该示例包含了所有的接口调用,包括音量、速率、引擎选择、语音选择、地区选择等等,非常全面,只是暂停功能会随着平台的不同而有着不同的表现,上面的接口说明已经提到过了。
下面来看看关键代码:

#include <QtWidgets/qmainwindow.h>

#include "ui_mainwindow.h"

#include <QTextToSpeech>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);

public slots:
    void speak();
    void stop();

    void setRate(int);
    void setPitch(int);
    void setVolume(int volume);

    void stateChanged(QTextToSpeech::State state);
    void engineSelected(int index);
    void languageSelected(int language);
    void voiceSelected(int index);

    void localeChanged(const QLocale &locale);

private:
    Ui::MainWindow ui;
    QTextToSpeech *m_speech;
    QVector<QVoice> m_voices;
};
#include "mainwindow.h"
#include <QLoggingCategory>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
    m_speech(0)
{
    ui.setupUi(this);
    QLoggingCategory::setFilterRules(QStringLiteral("qt.speech.tts=true \n qt.speech.tts.*=true"));

    // Populate engine selection list
    ui.engine->addItem("Default", QString("default"));
    foreach (QString engine, QTextToSpeech::availableEngines())
        ui.engine->addItem(engine, engine);
    ui.engine->setCurrentIndex(0);
    engineSelected(0);

    connect(ui.speakButton, &QPushButton::clicked, this, &MainWindow::speak);
    connect(ui.pitch, &QSlider::valueChanged, this, &MainWindow::setPitch);
    connect(ui.rate, &QSlider::valueChanged, this, &MainWindow::setRate);
    connect(ui.volume, &QSlider::valueChanged, this, &MainWindow::setVolume);
    connect(ui.engine, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::engineSelected);
}

void MainWindow::speak()
{
    m_speech->say(ui.plainTextEdit->toPlainText());
}
void MainWindow::stop()
{
    m_speech->stop();
}

void MainWindow::setRate(int rate)
{
    m_speech->setRate(rate / 10.0);
}

void MainWindow::setPitch(int pitch)
{
    m_speech->setPitch(pitch / 10.0);
}

void MainWindow::setVolume(int volume)
{
    m_speech->setVolume(volume / 100.0);
}

void MainWindow::stateChanged(QTextToSpeech::State state)
{
    if (state == QTextToSpeech::Speaking) {
        ui.statusbar->showMessage("Speech started...");
    } else if (state == QTextToSpeech::Ready)
        ui.statusbar->showMessage("Speech stopped...", 2000);
    else if (state == QTextToSpeech::Paused)
        ui.statusbar->showMessage("Speech paused...");
    else
        ui.statusbar->showMessage("Speech error!");

    ui.pauseButton->setEnabled(state == QTextToSpeech::Speaking);
    ui.resumeButton->setEnabled(state == QTextToSpeech::Paused);
    ui.stopButton->setEnabled(state == QTextToSpeech::Speaking || state == QTextToSpeech::Paused);
}

void MainWindow::engineSelected(int index)
{
    QString engineName = ui.engine->itemData(index).toString();
    delete m_speech;
    if (engineName == "default")
        m_speech = new QTextToSpeech(this);
    else
        m_speech = new QTextToSpeech(engineName, this);
    disconnect(ui.language, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::languageSelected);
    ui.language->clear();
    // Populate the languages combobox before connecting its signal.
    QVector<QLocale> locales = m_speech->availableLocales();
    QLocale current = m_speech->locale();
    foreach (const QLocale &locale, locales) {
        QString name(QString("%1 (%2)")
                     .arg(QLocale::languageToString(locale.language()))
                     .arg(QLocale::countryToString(locale.country())));
        QVariant localeVariant(locale);
        ui.language->addItem(name, localeVariant);
        if (locale.name() == current.name())
            current = locale;
    }
    setRate(ui.rate->value());
    setPitch(ui.pitch->value());
    setVolume(ui.volume->value());
    connect(ui.stopButton, &QPushButton::clicked, m_speech, &QTextToSpeech::stop);
    connect(ui.pauseButton, &QPushButton::clicked, m_speech, &QTextToSpeech::pause);
    connect(ui.resumeButton, &QPushButton::clicked, m_speech, &QTextToSpeech::resume);

    connect(m_speech, &QTextToSpeech::stateChanged, this, &MainWindow::stateChanged);
    connect(m_speech, &QTextToSpeech::localeChanged, this, &MainWindow::localeChanged);

    connect(ui.language, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::languageSelected);
    localeChanged(current);
}

void MainWindow::languageSelected(int language)
{
    QLocale locale = ui.language->itemData(language).toLocale();
    m_speech->setLocale(locale);
}

void MainWindow::voiceSelected(int index)
{
    m_speech->setVoice(m_voices.at(index));
}

void MainWindow::localeChanged(const QLocale &locale)
{
    QVariant localeVariant(locale);
    ui.language->setCurrentIndex(ui.language->findData(localeVariant));

    disconnect(ui.voice, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::voiceSelected);
    ui.voice->clear();

    m_voices = m_speech->availableVoices();
    QVoice currentVoice = m_speech->voice();
    foreach (const QVoice &voice, m_voices) {
        ui.voice->addItem(QString("%1 - %2 - %3").arg(voice.name())
                          .arg(QVoice::genderName(voice.gender()))
                          .arg(QVoice::ageName(voice.age())));
        if (voice.name() == currentVoice.name())
            ui.voice->setCurrentIndex(ui.voice->count() - 1);
    }
    connect(ui.voice, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::voiceSelected);
}

OK,代码就不细说了,都很简单。详情请查看 Qt 示例以及官方文档。

猜你喜欢

转载自blog.csdn.net/luoyayun361/article/details/80728112