最近研究了下调用微软TTS引擎进行朗读的相关资料,发现其实很简单,特发文与众位博友共享。
首先看看微软MSDN官方文档是如何调用TTS的
#include <stdafx.h> #include <sapi.h> int main(int argc, char* argv[]) { ISpVoice * pVoice = NULL; if (FAILED(::CoInitialize(NULL))) return FALSE; HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice;); if( SUCCEEDED( hr ) ) { hr = pVoice->Speak(L"Hello world", 0, NULL); pVoice->Release(); pVoice = NULL; } ::CoUninitialize(); return TRUE; }
可以发现其实很简单,就是初始化COM后,创建ISpVoice的实例调用Speak方法即可,如果想更加深入的了解这方面的知识,可以查阅MSDN,http://msdn.microsoft.com/en-us/library/ee125082(v=VS.85).aspx
Qt上使用COM非常简单,ActivityQt是Qt上用了和COM打交道,由于是调用COM,我们使用QAxObject即可满足要求。
首先设计一个接口
#include <QObject> class ITTS : public QObject { Q_OBJECT public: ITTS(void); virtual ~ITTS(void); virtual bool initSpeech() = 0; virtual bool speak(QString & txt) = 0; virtual void pause() = 0; virtual void resume() = 0; virtual void stop() = 0; //rate range : -10 - 10 virtual int rate() = 0; virtual void setRate(int rate) = 0; //volume range : 0 - 100 virtual int volume() = 0; virtual void setVolume(int value) = 0; virtual bool isSpeaking() = 0; signals: void speakComplete(); };
虽然我们是再Win7上使用,由于以后可能还有开发XP上的、Linux上的TTS,所以我们定义一个接口,在我们的调用类中只需要定义一个接口的指针就可以,然后根据实际的环境在初始化中初始化不同环境上的TTS实例,这个我们以后再来演示
根据Win7上的TTS,我们来创建Win7TTS类,继承于我们上面定义的ITTS
class Win7TTS : public ITTS { Q_OBJECT public: Win7TTS(void); virtual ~Win7TTS(void); virtual bool initSpeech(); virtual bool speak(QString & txt); virtual void pause(); virtual void resume(); virtual void stop(); //rate range : -10 - 10 virtual int rate(); virtual void setRate(int rate); //volume range : 0 - 100 virtual int volume(); virtual void setVolume(int value) ; virtual bool isSpeaking(); private slots: void dealevent(QString name, int arc , void* argv); private: QAxObject _voice; bool _binit; bool _bReading; };
_voice 就是我们用来创建ISpVoice Com对象的成员
void) : _binit(0), _bReading(0) { } Win7TTS::~Win7TTS(void) { } bool Win7TTS::initSpeech() { if(_binit) return true; _binit = this->_voice.setControl("96749377-3391-11D2-9EE3-00C04F797396"); if(_binit) { connect(&this->_voice,SIGNAL(signal(QString, int, void*)), this, SLOT(dealevent(QString, int, void*))); } return _binit; } bool Win7TTS::speak(QString & txt) { if(!_binit) return false; int result = this->_voice.dynamicCall("Speak(QString, SpeechVoiceSpeakFlags)", txt ,1).toInt(); _bReading = true; return result; } void Win7TTS::pause() { if(!_binit) return; _bReading = false; this->_voice.dynamicCall("Pause()"); } void Win7TTS::resume() { if(!_binit) return; _bReading = true; this->_voice.dynamicCall("Resume()"); } void Win7TTS::stop() { if(!_binit) return; _bReading = false; int result = this->_voice.dynamicCall("Speak(QString, SpeechVoiceSpeakFlags)", "" ,2).toInt(); } bool Win7TTS::isSpeaking() { return _bReading; } //rate range : -10 - 10 int Win7TTS::rate() { if(!_binit) return -99999; return this->_voice.property("Rate").toInt(); } void Win7TTS::setRate(int rate) { if(!_binit) return; this->_voice.dynamicCall("SetRate(int)", rate); } //volume range : 0 - 100 int Win7TTS::volume() { if(!_binit) return -99999; return this->_voice.property("Volume").toInt(); } void Win7TTS::setVolume(int value) { if(!_binit) return; this->_voice.dynamicCall("SetVolume(int)", value); } void Win7TTS::dealevent(QString name, int arc , void* argv) { if(name == "EndStream(int,QVariant)") { _bReading = false; emit speakComplete(); } }
TTS的框架已经搭好了,现在让我们试试TTS的魅力吧,稍后上传一个TTS的SAMPLE,可以下载下来玩玩!