From a27aa5dcda7e65de6e1bb04cfd8ea678242648d0 Mon Sep 17 00:00:00 2001 From: Philip Schell Date: Tue, 22 Oct 2013 12:11:15 +0000 Subject: WinterSpeak now has SAPI40a support ticket:476 and other minor fixes git-svn-id: http://svn.miranda-ng.org/main/trunk@6584 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/WinterSpeak/WinterSpeak_11.vcxproj | 16 +- plugins/WinterSpeak/WinterSpeak_11.vcxproj.filters | 15 ++ plugins/WinterSpeak/src/EventInformation.cpp | 2 +- plugins/WinterSpeak/src/ProtocolInformation.cpp | 8 +- plugins/WinterSpeak/src/SpeakAnnounce.cpp | 8 +- plugins/WinterSpeak/src/SpeechApi40a.cpp | 271 +++++++++++++++++++++ plugins/WinterSpeak/src/SpeechApi40a.h | 88 +++++++ plugins/WinterSpeak/src/SpeechApi40aLexicon.cpp | 51 ++++ plugins/WinterSpeak/src/SpeechApi40aLexicon.h | 28 +++ plugins/WinterSpeak/src/SpeechInterface.cpp | 9 +- plugins/WinterSpeak/src/UserInformation.cpp | 2 +- plugins/WinterSpeak/src/Version.h | 6 +- 12 files changed, 477 insertions(+), 27 deletions(-) create mode 100644 plugins/WinterSpeak/src/SpeechApi40a.cpp create mode 100644 plugins/WinterSpeak/src/SpeechApi40a.h create mode 100644 plugins/WinterSpeak/src/SpeechApi40aLexicon.cpp create mode 100644 plugins/WinterSpeak/src/SpeechApi40aLexicon.h (limited to 'plugins') diff --git a/plugins/WinterSpeak/WinterSpeak_11.vcxproj b/plugins/WinterSpeak/WinterSpeak_11.vcxproj index 0c404a89b2..66606908e9 100644 --- a/plugins/WinterSpeak/WinterSpeak_11.vcxproj +++ b/plugins/WinterSpeak/WinterSpeak_11.vcxproj @@ -20,7 +20,7 @@ WinterSpeak - {A44F96D0-A850-4A67-9570-0E9298A16E40} + {18195F68-A747-8643-050C-C5101DA658FD} @@ -81,7 +81,7 @@ Level3 true EditAndContinue - ..\..\include;%(AdditionalIncludeDirectories) + ..\..\include;C:\Program Files (x86)\Microsoft Speech SDK\Include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) EnableFastChecks Use @@ -99,7 +99,7 @@ $(ProfileDir)..\..\bin11\lib false false - comctl32.lib;%(AdditionalDependencies) + C:\Program Files (x86)\Microsoft Speech SDK\Lib\spchwrap.lib;comctl32.lib;%(AdditionalDependencies) @@ -108,7 +108,7 @@ false Disabled Level3 - ..\..\include;%(AdditionalIncludeDirectories) + ..\..\include;C:\Program Files (x86)\Microsoft Speech SDK\Include;%(AdditionalIncludeDirectories) _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) EnableFastChecks Use @@ -135,7 +135,7 @@ true Full Level3 - ..\..\include;%(AdditionalIncludeDirectories) + ..\..\include;C:\Program Files (x86)\Microsoft Speech SDK\Include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) Size Use @@ -164,7 +164,7 @@ true Full Level3 - ..\..\include;%(AdditionalIncludeDirectories) + ..\..\include;C:\Program Files (x86)\Microsoft Speech SDK\Include;%(AdditionalIncludeDirectories) NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) Size Use @@ -201,6 +201,8 @@ + + @@ -223,6 +225,8 @@ + + diff --git a/plugins/WinterSpeak/WinterSpeak_11.vcxproj.filters b/plugins/WinterSpeak/WinterSpeak_11.vcxproj.filters index ce06663320..43c1399f6e 100644 --- a/plugins/WinterSpeak/WinterSpeak_11.vcxproj.filters +++ b/plugins/WinterSpeak/WinterSpeak_11.vcxproj.filters @@ -34,6 +34,9 @@ {79aaf01a-24a8-425a-a166-75f9a925b5a4} + + {bc35ee8c-e94f-4d06-8e83-77d143ead7bb} + @@ -102,6 +105,12 @@ Source Files + + Source Files\text_to_speech\speech_api_40a + + + Source Files\text_to_speech\speech_api_40a + @@ -169,5 +178,11 @@ Source Files\text_to_speech + + Source Files\text_to_speech\speech_api_40a + + + Source Files\text_to_speech\speech_api_40a + \ No newline at end of file diff --git a/plugins/WinterSpeak/src/EventInformation.cpp b/plugins/WinterSpeak/src/EventInformation.cpp index 65923022d2..c277a7837a 100644 --- a/plugins/WinterSpeak/src/EventInformation.cpp +++ b/plugins/WinterSpeak/src/EventInformation.cpp @@ -67,7 +67,7 @@ std::wstring EventInformation::getMessage() { const std::wstring intro = TranslateW(L"%u says"); - return intro + L" " + mir_a2t_cp((char*)m_event_info.pBlob,CP_UTF8); + return intro + L" " + mir_a2t_cp((char*)m_event_info.pBlob, CP_UTF8); } //------------------------------------------------------------------------------ diff --git a/plugins/WinterSpeak/src/ProtocolInformation.cpp b/plugins/WinterSpeak/src/ProtocolInformation.cpp index 5fff2526af..19f7c9f70b 100644 --- a/plugins/WinterSpeak/src/ProtocolInformation.cpp +++ b/plugins/WinterSpeak/src/ProtocolInformation.cpp @@ -19,9 +19,7 @@ ProtocolInformation::~ProtocolInformation() m_instance = 0; // kill all the timers - for (ProtocolTimeoutQueue::const_iterator iter = m_protocol_timeout.begin(); - iter != m_protocol_timeout.end(); - ++iter) + for (ProtocolTimeoutQueue::const_iterator iter = m_protocol_timeout.begin(); iter != m_protocol_timeout.end(); ++iter) { KillTimer(NULL, (*iter).second); } @@ -59,9 +57,7 @@ bool ProtocolInformation::isDisabled(const char *protocol) const } // iterate through the list and see if the protocol has a timer callback - for (ProtocolTimeoutQueue::const_iterator iter = m_protocol_timeout.begin(); - iter != m_protocol_timeout.end(); - ++iter) + for (ProtocolTimeoutQueue::const_iterator iter = m_protocol_timeout.begin(); iter != m_protocol_timeout.end(); ++iter) { if (0 == (*iter).first.compare(protocol)) { diff --git a/plugins/WinterSpeak/src/SpeakAnnounce.cpp b/plugins/WinterSpeak/src/SpeakAnnounce.cpp index c95550b4af..43efb965d5 100644 --- a/plugins/WinterSpeak/src/SpeakAnnounce.cpp +++ b/plugins/WinterSpeak/src/SpeakAnnounce.cpp @@ -19,17 +19,13 @@ void SpeakAnnounce::statusChange(DBCONTACTWRITESETTING *write_setting, HANDLE us // if the user is myself (NULL) then return // if it's not a status change then return // check and update the user's status, if status didn't change the return - if ((NULL == user) - || (STATUS != write_setting->szSetting) - || (!m_user_info.updateStatus(user, write_setting->value.wVal))) + if ((NULL == user) || (STATUS != write_setting->szSetting) || (!m_user_info.updateStatus(user, write_setting->value.wVal))) { return; } // check if we just connected, and want to suppress status changes - if (!m_db.getStatusFlag(AnnounceDatabase::StatusFlag_SuppressConnect) - && m_protocol_info.isDisabled( - (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)user, 0))) + if (!m_db.getStatusFlag(AnnounceDatabase::StatusFlag_SuppressConnect) && m_protocol_info.isDisabled((char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)user, 0))) { return; } 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 +#include +#include +#include +#include +#include +#include +#include + +#include +//#include + +#include +#include + +//------------------------------------------------------------------------------ +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 SpeechApi40a::getVoices() const +{ + std::vector 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 diff --git a/plugins/WinterSpeak/src/SpeechApi40a.h b/plugins/WinterSpeak/src/SpeechApi40a.h new file mode 100644 index 0000000000..e9b524f954 --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechApi40a.h @@ -0,0 +1,88 @@ +#pragma once +#include "texttospeech.h" + +struct ITTSCentralW; +struct ITTSAttributesA; + +class SpeechApi40a : public TextToSpeech +{ + public: + SpeechApi40a(); + virtual ~SpeechApi40a(); + + //-------------------------------------------------------------------------- + // Description : is the api available for use + // Return : true - it is available + // false - it is not available + //-------------------------------------------------------------------------- + virtual bool isAvailable(); + + //-------------------------------------------------------------------------- + // Description : load/unload/reload the speech api + // Return : true - the action succeeded + // false - the action failed + //-------------------------------------------------------------------------- + virtual bool load(); + virtual bool unload(); + + //-------------------------------------------------------------------------- + // Description : check if the speech api is loaded + // Return : true - the speech_api is loaded + // false - its not loaded + //-------------------------------------------------------------------------- + virtual bool isLoaded() const; + + //-------------------------------------------------------------------------- + // Description : speak a sentence + // Parameters : sentence - the sentence to speak + // Returns : true - speak successful + // false - speak failed + //-------------------------------------------------------------------------- + virtual bool say(const std::wstring &sentence); + + //-------------------------------------------------------------------------- + // Description : set the voice settings + // Parameters : range from 0 to 100 + //-------------------------------------------------------------------------- + virtual bool setVolume(int volume); + virtual bool setPitch(int pitch); + virtual bool setRate(int rate); + + //-------------------------------------------------------------------------- + // Description : set the voice + //-------------------------------------------------------------------------- + virtual bool setVoice(const std::wstring &voice); + + //-------------------------------------------------------------------------- + // Description : get the available voices + //-------------------------------------------------------------------------- + virtual std::vector getVoices() const; + + //-------------------------------------------------------------------------- + // Description : open the lexicon dialog for this engine + // Parameters : window - handle to the parent window + // Return : true - dialog completely successfully + // false - dialog failed + //-------------------------------------------------------------------------- + virtual bool lexiconDialog(HWND window); + + //-------------------------------------------------------------------------- + // Description : get the description of the tts engine + //-------------------------------------------------------------------------- + static std::wstring getDescription(); + + private: + //-------------------------------------------------------------------------- + // Description : load the speech api with the specified voice + //-------------------------------------------------------------------------- + bool loadWithVoice(std::wstring &voice); + + ITTSCentralW *m_tts_central; + ITTSAttributesA *m_tts_attribs; + + TextToSpeech::State m_state; + std::wstring m_voice; + int m_volume; + int m_pitch; + int m_rate; +}; \ No newline at end of file diff --git a/plugins/WinterSpeak/src/SpeechApi40aLexicon.cpp b/plugins/WinterSpeak/src/SpeechApi40aLexicon.cpp new file mode 100644 index 0000000000..efb82b84e7 --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechApi40aLexicon.cpp @@ -0,0 +1,51 @@ +#include "Common.h" +#include "SpeechApi40aLexicon.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +//#include + + +//------------------------------------------------------------------------------ +SpeechApi40aLexicon::SpeechApi40aLexicon(HWND window, ITTSCentralW *tts_central) : m_window(window), m_tts_central(tts_central) +{ +} + +//------------------------------------------------------------------------------ +SpeechApi40aLexicon::~SpeechApi40aLexicon() +{ +} + +//------------------------------------------------------------------------------ +bool SpeechApi40aLexicon::display() +{ + if (!m_tts_central) + { + return false; + } + + ITTSDialogs *tts_dialogs = 0; + + m_tts_central->QueryInterface(IID_ITTSDialogs, (void**)&tts_dialogs); + + if (!tts_dialogs) + { + return false; + } + + if (NOERROR != tts_dialogs->LexiconDlg(m_window, NULL)) + { + return false; + } + + tts_dialogs->Release(); + return true; +} diff --git a/plugins/WinterSpeak/src/SpeechApi40aLexicon.h b/plugins/WinterSpeak/src/SpeechApi40aLexicon.h new file mode 100644 index 0000000000..73bee51cb9 --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechApi40aLexicon.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +struct ITTSCentralW; +class SpeechApi40aLexicon +{ + public: + //-------------------------------------------------------------------------- + // Description : Constuctor + // Parameters : window - handle to the parent window + // tts_central - pointer to the tts_central engine to use + //-------------------------------------------------------------------------- + SpeechApi40aLexicon(HWND window, ITTSCentralW *tts_central); + + ~SpeechApi40aLexicon(); + + //-------------------------------------------------------------------------- + // Description : display the lexicon dialog + // Return : true - display ok + // false - display failed + //-------------------------------------------------------------------------- + bool display(); + + private: + HWND m_window; + ITTSCentralW *m_tts_central; +}; \ No newline at end of file diff --git a/plugins/WinterSpeak/src/SpeechInterface.cpp b/plugins/WinterSpeak/src/SpeechInterface.cpp index 500165f356..261cf547ec 100644 --- a/plugins/WinterSpeak/src/SpeechInterface.cpp +++ b/plugins/WinterSpeak/src/SpeechInterface.cpp @@ -1,6 +1,7 @@ #include "Common.h" #include "SpeechInterface.h" #include "SpeechApi51.h" +#include "SpeechApi40a.h" SpeechInterface::SpeechInterface() @@ -17,11 +18,11 @@ TextToSpeech * SpeechInterface::createTts(std::wstring &engine) const { TextToSpeech *tts = 0; - /*if (SpeechApi40a::getDescription() == engine) + if (SpeechApi40a::getDescription() == engine) { tts = new SpeechApi40a(); } - else*/ + else if (SpeechApi51::getDescription() == engine) { tts = new SpeechApi51(); @@ -50,11 +51,11 @@ std::vector SpeechInterface::getAvailableEngines() { std::vector engines; - /*SpeechApi40a sapi40a; + SpeechApi40a sapi40a; if (sapi40a.isAvailable()) { engines.push_back(SpeechApi40a::getDescription()); - }*/ + } SpeechApi51 sapi51; if (sapi51.isAvailable()) diff --git a/plugins/WinterSpeak/src/UserInformation.cpp b/plugins/WinterSpeak/src/UserInformation.cpp index fa5db0b0e5..7163e9b23e 100644 --- a/plugins/WinterSpeak/src/UserInformation.cpp +++ b/plugins/WinterSpeak/src/UserInformation.cpp @@ -72,7 +72,7 @@ std::wstring UserInformation::nameString(HANDLE user) const { return L""; } - return TranslateW(mir_a2t(ret)); + return TranslateW(mir_a2t_cp(ret, CP_UTF8)); } //============================================================================== diff --git a/plugins/WinterSpeak/src/Version.h b/plugins/WinterSpeak/src/Version.h index 6dcfc0d27f..2c10081d2e 100644 --- a/plugins/WinterSpeak/src/Version.h +++ b/plugins/WinterSpeak/src/Version.h @@ -1,12 +1,12 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 9 #define __RELEASE_NUM 8 -#define __BUILD_NUM 0 +#define __BUILD_NUM 2 #define __FILEVERSION_STRING __MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM -#define __PLUGIN_NAME "Speak" -#define __FILENAME "speak.dll" +#define __PLUGIN_NAME "WinterSpeak" +#define __FILENAME "winterspeak.dll" #define __DESCRIPTION "Miranda interface to the Microsoft Speech API" #define __AUTHOR "Ryan Winter, BlubbFish" #define __AUTHOREMAIL "miranda@blubbfish.net" -- cgit v1.2.3