diff options
Diffstat (limited to 'plugins/WinterSpeak/src/SpeechApi40a.cpp')
-rw-r--r-- | plugins/WinterSpeak/src/SpeechApi40a.cpp | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/plugins/WinterSpeak/src/SpeechApi40a.cpp b/plugins/WinterSpeak/src/SpeechApi40a.cpp new file mode 100644 index 0000000000..ab15e3e6bc --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechApi40a.cpp @@ -0,0 +1,271 @@ +#include "Common.h"
+#include "SpeechApi40a.h"
+
+#include "SpeechApi40aLexicon.h"
+
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+#include <MMSystem.h>
+#include <InitGuid.h>
+#include <ObjBase.h>
+#include <ObjError.h>
+#include <Ole2Ver.h>
+
+#include <speech.h>
+//#include <spchwrap.h>
+
+#include <sstream>
+#include <memory>
+
+//------------------------------------------------------------------------------
+SpeechApi40a::SpeechApi40a() : m_tts_central(0), m_tts_attribs(0), m_state(TextToSpeech::State_Unloaded), m_voice(_T("")), m_volume(50), m_pitch(50), m_rate(50)
+{
+}
+
+//------------------------------------------------------------------------------
+SpeechApi40a::~SpeechApi40a()
+{
+ unload();
+ CoUninitialize();
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::isAvailable()
+{
+ CoInitialize(NULL);
+
+ PITTSENUM pITTSEnum;
+ bool ret = true;
+
+ // create the enumerator
+ if (FAILED(CoCreateInstance(CLSID_TTSEnumerator, NULL, CLSCTX_ALL, IID_ITTSEnum, (void**)&pITTSEnum)))
+ {
+ ret = false;
+ }
+ else
+ {
+ pITTSEnum->Release();
+ }
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::load()
+{
+ if (isLoaded())
+ {
+ return true;
+ }
+
+ return loadWithVoice(std::wstring(m_voice));
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::unload()
+{
+ if (m_tts_attribs)
+ {
+ m_tts_attribs->Release();
+ m_tts_attribs = 0;
+ }
+
+ if (m_tts_central)
+ {
+ m_tts_central->Release();
+ m_tts_central = 0;
+ }
+
+ m_state = TextToSpeech::State_Unloaded;
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::isLoaded() const
+{
+ return (TextToSpeech::State_Loaded == m_state);
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::say(const std::wstring &sentence)
+{
+ std::string text = mir_t2a_cp(sentence.c_str(), CP_UTF8);
+ bool ret = true;
+
+ if (!isLoaded())
+ {
+ ret = false;
+ }
+ else
+ {
+ SDATA data;
+ data.dwSize = (DWORD)text.size();
+ data.pData = (char *)text.c_str();
+ m_tts_central->TextData(CHARSET_TEXT, 0, data, NULL, IID_ITTSBufNotifySinkA);
+ }
+
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::setVolume(int volume)
+{
+ m_volume = volume;
+
+ if (!isLoaded())
+ {
+ return true;
+ }
+
+ DWORD new_vol = volume / 100.0 * 0xffff;
+ new_vol |= new_vol << 16;
+
+ if (FAILED(m_tts_attribs->VolumeSet(new_vol)))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::setPitch(int pitch)
+{
+ m_pitch = pitch;
+
+ // valid range is 50 to 350
+ if (isLoaded() && FAILED(m_tts_attribs->PitchSet(pitch * 3.0 + 50)))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::setRate(int rate)
+{
+ m_rate = rate;
+
+ // valid range is 50 to 350
+ if (isLoaded() && FAILED(m_tts_attribs->SpeedSet(rate * 3.0 + 50)))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::setVoice(const std::wstring &voice)
+{
+ m_voice = voice;
+
+ if (!isLoaded())
+ {
+ return true;
+ }
+
+ unload();
+ return load();
+}
+
+//------------------------------------------------------------------------------
+std::vector<std::wstring> SpeechApi40a::getVoices() const
+{
+ std::vector<std::wstring> ret;
+
+ PITTSENUM pITTSEnum = NULL;
+ TTSMODEINFO inf;
+
+ CoInitialize(NULL);
+
+ if (FAILED(CoCreateInstance(CLSID_TTSEnumerator, NULL, CLSCTX_ALL, IID_ITTSEnum, (void**)&pITTSEnum)))
+ {
+ return ret;
+ }
+
+ while (!pITTSEnum->Next(1, &inf, NULL))
+ {
+ ret.push_back(inf.szModeName);
+ }
+
+ pITTSEnum->Release();
+
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+bool SpeechApi40a::lexiconDialog(HWND window)
+{
+ // open the dialog
+ SpeechApi40aLexicon dialog(window, m_tts_central);
+
+ if (!dialog.display())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+std::wstring SpeechApi40a::getDescription()
+{
+ return _T("Microsoft SAPI v4.0");
+}
+
+//------------------------------------------------------------------------------
+// private:
+//------------------------------------------------------------------------------
+bool SpeechApi40a::loadWithVoice(std::wstring &voice)
+{
+ CoInitialize(NULL);
+
+ PITTSENUM pITTSEnum;
+ TTSMODEINFO inf;
+ LPUNKNOWN pAudioDest;
+
+ // create the enumerator
+ if (FAILED(CoCreateInstance(CLSID_TTSEnumerator, NULL, CLSCTX_ALL, IID_ITTSEnum, (void**)&pITTSEnum)))
+ {
+ return false;
+ }
+
+ // iterate through the voices until we find the right one
+ while (!pITTSEnum->Next(1, &inf, NULL))
+ {
+ if (inf.szModeName == voice)
+ {
+ break;
+ }
+ }
+
+ if (FAILED(CoCreateInstance(CLSID_MMAudioDest, NULL, CLSCTX_ALL, IID_IAudioMultiMediaDevice, (void**)&pAudioDest)))
+ {
+ pITTSEnum->Release();
+ return false;
+ }
+
+ // select that voice
+ if (FAILED(pITTSEnum->Select(inf.gModeID, &m_tts_central, pAudioDest)))
+ {
+ pITTSEnum->Release();
+ return NULL;
+ }
+
+ m_tts_central->QueryInterface(IID_ITTSAttributes, (LPVOID *)&m_tts_attribs);
+
+ pITTSEnum->Release();
+
+ // we made it
+ m_state = TextToSpeech::State_Loaded;
+
+ // configure the new voice
+ setVolume(m_volume);
+ setRate(m_rate);
+ setPitch(m_pitch);
+
+ return true;
+}
\ No newline at end of file |