qt 操作tts

更新时间:2023-09-17 10:16:01 阅读量: 幼儿教育 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

所使用的DLL: http://www.cppblog.com/Files/biao/TTSSpeaker.dll.zip ///////////////////////////////////////////////////////////////////////////////////////////////////// // TTSSpeaker.cpp: Qt

///////////////////////////////////////////////////////////////////////////////////////////////////// // 调用sapi.dll, 使用里面的三个函数来初始化, 释放资源, 发音函数

// 在VS中使用TTSSpeaker.cpp生成DLL文件. 因为如果在QtCreator中使用的话, 有可能自带的mingw的不完全, 而找不到

// 某些结构的定义而出错题.

#include \

#include

#ifdef _MANAGED #pragma managed(push, off) #endif

BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) {

return TRUE;

}

ISpVoice *pVoice; HRESULT hr;

extern \ __declspec(dllexport) bool initialize() {

pVoice = NULL;

if (FAILED(::CoInitialize(NULL))) {

return false; }

hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void**)&pVoice);

return true; }

extern \ __declspec(dllexport) void release() { if (SUCCEEDED(hr)) {

pVoice->Release(); pVoice = NULL; }

::CoUninitialize(); }

extern \ __declspec(dllexport) void speak(char *szU8) { if (SUCCEEDED(hr)) {

int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), NULL, 0); wchar_t* wszString = new wchar_t[wcsLen + 1];

::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), wszString, wcsLen); wszString[wcsLen] = '\\0';

hr = pVoice->Speak(wszString, 0, NULL); } }

#ifdef _MANAGED #pragma managed(pop) #endif

////////////////////////////////////////////////////////////////////////////////////////////////////// // Speaker.h: Qt

////////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef SPEAKER_H #define SPEAKER_H

#include #include #include

class Speaker; class TtsLoader; class TtsRemover; class SpeakThread;

// 对应sapi.dll里的三个TTS函数, 从DLL中得到的

typedef bool (*InitializeFunc)(); typedef void (*ReleaseFunc)();

typedef void (*SpeakFunc)(char *szU8);

/**

* 管理TTS的类, 对TTS进行加载, 释放TTS占用的资源, 调用TTS进行文本发音. */

class Speaker : public QObject {

Q_OBJECT public:

static Speaker& getInstance(); void setSpeakEnabled(bool enabled);

bool isSpeakEnabled() const; bool isTtsLoaded() const;

void speak(const QString &str); // 启动发音线程 void initializeTts(); // 启动TTS加载线程 void releaseTts(); // 启动释放TTS资源的线程

void terminateAllThreads();

protected:

void loadTts(); // 真正加载TTS的函数

void removeTts(); // 真正释放TTS占用资源的函数 void speakString(const QString &str); // 真正发音的函数

private slots:

void completeLoadTts(); // TTS加载线程结束的处理糟函数 void completeRemoveTts(); // 释放TTS资源线程结束的处理糟函数 private: Speaker(); ~Speaker();

Speaker(const Speaker &other);

Speaker& operator=(const Speaker &other);

// TTS 初始化, 释放资源, 发音函数

InitializeFunc initializeFunc; ReleaseFunc releaseFunc; SpeakFunc speakFunc;

bool ttsLoaded; // TTS 加载成功 bool speakEnabled; // 启用语音功能

friend class TtsLoader;

TtsLoader *ttsLoader; // TTS 加载线程 friend class TtsRemover; TtsRemover *ttsRemover; friend class SpeakThread;

SpeakThread *speakThread; // 发音线程

friend class std::auto_ptr; static std::auto_ptr instance; };

/////////////////////////////////////////////////////////////////////////////////// // 加载TTS的线程

// 如果不使用线程来加载, 在加载的时候就会感觉到卡

class TtsLoader : public QThread {

public:

TtsLoader(Speaker *speaker); virtual void run(); void stop();

private:

Speaker *speaker; volatile bool stopped; };

/////////////////////////////////////////////////////////////////////////////////// // 释放TTS资源的线程

class TtsRemover : public QThread {

public:

TtsRemover(Speaker *speaker); void stop();

protected:

virtual void run(); private:

Speaker *speaker; volatile bool stopped; };

/////////////////////////////////////////////////////////////////////////////////// // TTS发音线程,

class SpeakThread : public QThread {

public:

SpeakThread(Speaker *speaker); void stop();

void setSpeakingString(const QString &speakingString);

protected:

virtual void run(); private:

Speaker *speaker; volatile bool stopped; QString speakingString; };

#endif // SPEAKER_H

////////////////////////////////////////////////////////////////////////////////////////////////////// // Speaker.cpp: Qt

//////////////////////////////////////////////////////////////////////////////////////////////////////

#include \

#include

#include

std::auto_ptr Speaker::instance;

Speaker::Speaker() { ttsLoaded = false; speakEnabled = true;

// Threads

ttsLoader = 0; ttsRemover = 0; speakThread = 0;

// TTS functions

initializeFunc = 0; releaseFunc = 0; speakFunc = 0; }

Speaker::~Speaker() { terminateAllThreads();

delete ttsLoader; delete ttsRemover; delete speakThread;

//这里释放不用线程,而是直接释放 if (ttsLoaded) { removeTts(); } }

Speaker& Speaker::getInstance() { if (instance.get() == 0) {

instance.reset(new Speaker()); }

return *(instance.get()); }

void Speaker::setSpeakEnabled(bool enabled) {

speakEnabled = enabled; }

bool Speaker::isSpeakEnabled() const {

return speakEnabled; }

bool Speaker::isTtsLoaded() const {

return ttsLoaded; }

void Speaker::speak(const QString &str) {

if (ttsLoaded && speakEnabled && (0 != speakThread)) { if (speakThread->isRunning()) {

qDebug() << \; speakThread->stop(); }

qDebug() << \ << str;

speakString(\); // 不加这一句, 不知道为什么不行 speakThread->setSpeakingString(str); speakThread->start(); } }

void Speaker::speakString(const QString &str) {

if (speakFunc != 0) {

speakFunc(str.toUtf8().data()); } }

void Speaker::initializeTts() {

// If tts is loaded, don't need to load again.

if (ttsLoaded) { return; }

// 启动加载线程

// If ttsLoader is not euqal 0, that means ttsLoader is running. // Because after ttsLoader is finished, it will be removed.

if (ttsLoader == 0) {

ttsLoader = new TtsLoader(this);

connect(ttsLoader, SIGNAL(finished()), this, SLOT(completeLoadTts()));

ttsLoader->start(); } }

void Speaker::releaseTts() {

// If tts is not loaded, removing process is not needed.

if (!ttsLoaded) { return; }

if (0 == ttsRemover) {

ttsRemover = new TtsRemover(this);

connect(ttsRemover, SIGNAL(finished()), this, SLOT(completeRemoveTts()));

ttsRemover->start(); } }

void Speaker::loadTts() {

// 如果TTS引擎已经加载了, 就不需要再次加载 if (ttsLoaded) { return; }

QLibrary lib(\); if (lib.load()) {

initializeFunc = (InitializeFunc)lib.resolve(\);

releaseFunc = (ReleaseFunc)lib.resolve(\); speakFunc = (SpeakFunc)lib.resolve(\);

if (initializeFunc && releaseFunc && speakFunc) { initializeFunc(); ttsLoaded = true;

qDebug() << \;

// When tts is loaded, initialize the speak thread.

speakThread = new SpeakThread(this);

speak(\); // 加载完后说一下,准备好,因为第一次说都会很慢

} } else {

qDebug() << lib.errorString(); } }

void Speaker::removeTts() {

// If tts is not loaded, removing process is not needed.

if (!ttsLoaded) { return; }

releaseFunc();

ttsLoaded = false; initializeFunc = 0; releaseFunc = 0; speakFunc = 0;

qDebug() << \;

// After tts is removed, speak thread is also need to be removed.

if (speakThread != 0) { speakThread->terminate(); }

delete speakThread; speakThread = 0; } /**

* After the process that loads tts is completed, the load thread is not needed, then remove it. */

void Speaker::completeLoadTts() {

delete ttsLoader; ttsLoader = 0; } /**

* After the process that removes tts is completed, the remove thread is not needed, then remove it. */

void Speaker::completeRemoveTts() {

delete ttsRemover; ttsRemover = 0; } /**

* Terminated all threads. */

void Speaker::terminateAllThreads() {

if (ttsLoader != 0) { ttsLoader->terminate(); }

if (ttsRemover != 0) { ttsRemover->terminate(); }

if (speakThread != 0) { speakThread->terminate(); } }

/////////////////////////////////////////////////////////////////////////////////// TtsLoader::TtsLoader(Speaker *speaker) { this->speaker = speaker; stopped = false; }

void TtsLoader::run() {

if (!stopped) { speaker->loadTts(); }

stopped = false; // }

void TtsLoader::stop() {

stopped = true;

}

/////////////////////////////////////////////////////////////////////////////////// TtsRemover::TtsRemover(Speaker *speaker) { this->speaker = speaker; stopped = false; }

void TtsRemover::run() {

if (!stopped) {

speaker->removeTts(); }

stopped = false; }

void TtsRemover::stop() {

stopped = true; }

/////////////////////////////////////////////////////////////////////////////////// SpeakThread::SpeakThread(Speaker *speaker) { this->speaker = speaker; stopped = false; }

void SpeakThread::run() {

if (!stopped) {

speaker->speakString(speakingString); }

stopped = false; }

void SpeakThread::stop() {

stopped = true; }

void SpeakThread::setSpeakingString(const QString &speakingString) {

this->speakingString = speakingString; } /*

很奇怪的问题: 如果直接使用loadTts()和removeTts()函数来初始化和释放TTS的资源, 就不会存在内存泄漏问题. 但是如果使用线程来处理, 即调用initializeTts(), releaseTts(), 在线程中调用loadTts(), removeTts()来初始化和释放TTS的资源, 就会存在内存泄漏. 泄漏的内存大小为初始化一次TTS的内存, 没发现会叠加.

文本发音的使用过程: 由于使用的是单态模式, 所以在使用发音函数speak前, 初始化TTS一次就可以了, 而TTS的资源释放是自动释放的, 当然也可以手动释放.

1. Speaker::getInstance().initializeTts(); // 最好程序启动的时候调用. 2. Speaker::getInstance().speak(str);

.................可以在程序的任何地方直接调用.(如果TTS没有被加载, 或者不启用语音功能, 这时调用了不起任何作用)

[不需要自己手动释放TTS的资源, 因为使用了智能指针实现单态模式] */

本文来源:https://www.bwwdw.com/article/20wh.html

Top