aboutsummaryrefslogtreecommitdiff
path: root/backends/text-to-speech
diff options
context:
space:
mode:
authorsluicebox2019-11-06 00:47:40 -0800
committersluicebox2019-11-06 11:00:37 -0800
commitfc9786231cd25a7d9fc39130560d0b8bc10d7eab (patch)
tree5e36b3caf45e62a5f5c5e1a5a80d91f827e2efb5 /backends/text-to-speech
parent0d3367cea2537f6ef32061478308e864eb4f5b08 (diff)
downloadscummvm-rg350-fc9786231cd25a7d9fc39130560d0b8bc10d7eab.tar.gz
scummvm-rg350-fc9786231cd25a7d9fc39130560d0b8bc10d7eab.tar.bz2
scummvm-rg350-fc9786231cd25a7d9fc39130560d0b8bc10d7eab.zip
TTS: Improve Windows audio, remove sphelper-scummvm.h
- Remove sphelper-scummvm.h - Use default audio quality instead of lowest - Add HRESULT tests - Fix new[]/free() mismatches - Fix voice description memory leak
Diffstat (limited to 'backends/text-to-speech')
-rw-r--r--backends/text-to-speech/windows/sphelper-scummvm.h2296
-rw-r--r--backends/text-to-speech/windows/windows-text-to-speech.cpp70
2 files changed, 42 insertions, 2324 deletions
diff --git a/backends/text-to-speech/windows/sphelper-scummvm.h b/backends/text-to-speech/windows/sphelper-scummvm.h
deleted file mode 100644
index 3fc7772d98..0000000000
--- a/backends/text-to-speech/windows/sphelper-scummvm.h
+++ /dev/null
@@ -1,2296 +0,0 @@
-// To get sphelper.h working with MinGW, several changes had to be made
-//
-// SUMMARY OF CHANGES:
-// 1. Unneeded functions got deleted
-// SpCreateObjectFromToken
-// SpCreateObjectFromTokenId
-// SpCreateDefaultObjectFromCategoryId
-// SpCreateBestObject
-// SpCreatePhoneConverter
-// SpBindToFile
-// CreatePhraseFromWordArray
-// CreatePhraseFromText
-//
-// 2. Unneeded includes got deleted
-// crtdbg.h
-// SPDebug.h
-// atlbase.h
-// sapiddk.h
-//
-// 3. Include got added
-// cwtype
-//
-// 4. Calls to SPDBG_ASSERT() got deleted
-// 5. CComPtr<> were replaced by plain C style pointers and code that works with
-// these was adjusted accordingly
-//
-// More small changes were made throughout the whole file. The best way to
-// see all changes is probably to diff this and the original file.
-/*******************************************************************************
-* SPHelper.h *
-*------------*
-* Description:
-* This is the header file for core helper functions implementation.
-*-------------------------------------------------------------------------------
-* Copyright (c) Microsoft Corporation. All rights reserved.
-*******************************************************************************/
-#ifndef SPHelper_h
-#define SPHelper_h
-
-#include <iostream>
-#ifndef _INC_MALLOC
-#include <malloc.h>
-#endif
-
-#ifndef __sapi_h__
-#include <sapi.h>
-#endif
-
-#ifndef SPError_h
-#include <sperror.h>
-#endif
-
-#ifndef _INC_LIMITS
-#include <limits.h>
-#endif
-
-#ifndef _INC_MMSYSTEM
-#include <mmsystem.h>
-#endif
-
-#ifndef __comcat_h__
-#include <comcat.h>
-#endif
-
-#ifndef _INC_MMREG
-#include <mmreg.h>
-#endif
-
-#include <cwctype>
-//=== Constants ==============================================================
-#define sp_countof(x) ((sizeof(x) / sizeof(*(x))))
-
-/*** CSpDynamicString helper class
-*
-*/
-class CSpDynamicString
-{
-public:
-
- WCHAR * m_psz;
- CSpDynamicString()
- {
- m_psz = NULL;
- }
- CSpDynamicString(ULONG cchReserve)
- {
- m_psz = (WCHAR *)::CoTaskMemAlloc(cchReserve * sizeof(WCHAR));
- }
- WCHAR * operator=(const CSpDynamicString& src)
- {
- if (m_psz != src.m_psz)
- {
- ::CoTaskMemFree(m_psz);
- m_psz = src.Copy();
- }
- return m_psz;
- }
- WCHAR * operator=(const WCHAR * pSrc)
- {
- Clear();
- if (pSrc)
- {
- ULONG cbNeeded = (wcslen(pSrc) + 1) * sizeof(WCHAR);
- m_psz = (WCHAR *)::CoTaskMemAlloc(cbNeeded);
- if (m_psz)
- {
- memcpy(m_psz, pSrc, cbNeeded);
- }
- }
- return m_psz;
- }
-
- WCHAR * operator=(const char * pSrc)
- {
- Clear();
- if (pSrc)
- {
- ULONG cbNeeded = (lstrlenA(pSrc) + 1) * sizeof(WCHAR);
- m_psz = (WCHAR *)::CoTaskMemAlloc(cbNeeded);
- if (m_psz)
- {
- ::MultiByteToWideChar(CP_ACP, 0, pSrc, -1, m_psz, cbNeeded/sizeof(WCHAR));
- }
- }
- return m_psz;
- }
-
- WCHAR * operator=(REFGUID rguid)
- {
- Clear();
- ::StringFromCLSID(rguid, &m_psz);
- return m_psz;
- }
-
-
- /*explicit*/ CSpDynamicString(const WCHAR * pSrc)
- {
- m_psz = NULL;
- operator=(pSrc);
- }
- /*explicit*/ CSpDynamicString(const char * pSrc)
- {
- m_psz = NULL;
- operator=(pSrc);
- }
- /*explicit*/ CSpDynamicString(const CSpDynamicString& src)
- {
- m_psz = src.Copy();
- }
- /*explicit*/ CSpDynamicString(REFGUID rguid)
- {
- ::StringFromCLSID(rguid, &m_psz);
- }
-
-
- ~CSpDynamicString()
- {
- ::CoTaskMemFree(m_psz);
- }
- unsigned int Length() const
- {
- return (m_psz == NULL)? 0 : wcslen(m_psz);
- }
-
- operator WCHAR * () const
- {
- return m_psz;
- }
- //The assert on operator& usually indicates a bug. If this is really
- //what is needed, however, take the address of the m_psz member explicitly.
- WCHAR ** operator&()
- {
- return &m_psz;
- }
-
- WCHAR * Append(const WCHAR * pszSrc)
- {
- if (pszSrc)
- {
- ULONG lenSrc = wcslen(pszSrc);
- if (lenSrc)
- {
- ULONG lenMe = Length();
- WCHAR *pszNew = (WCHAR *)::CoTaskMemAlloc((lenMe + lenSrc + 1) * sizeof(WCHAR));
- if (pszNew)
- {
- if (m_psz) // Could append to an empty string so check...
- {
- if (lenMe)
- {
- memcpy(pszNew, m_psz, lenMe * sizeof(WCHAR));
- }
- ::CoTaskMemFree(m_psz);
- }
- memcpy(pszNew + lenMe, pszSrc, (lenSrc + 1) * sizeof(WCHAR));
- m_psz = pszNew;
- }
- else
- {
- }
- }
- }
- return m_psz;
- }
-
- WCHAR * Append(const WCHAR * pszSrc, const ULONG lenSrc)
- {
- if (pszSrc && lenSrc)
- {
- ULONG lenMe = Length();
- WCHAR *pszNew = (WCHAR *)::CoTaskMemAlloc((lenMe + lenSrc + 1) * sizeof(WCHAR));
- if (pszNew)
- {
- if (m_psz) // Could append to an empty string so check...
- {
- if (lenMe)
- {
- memcpy(pszNew, m_psz, lenMe * sizeof(WCHAR));
- }
- ::CoTaskMemFree(m_psz);
- }
- memcpy(pszNew + lenMe, pszSrc, lenSrc * sizeof(WCHAR));
- *(pszNew + lenMe + lenSrc) = L'\0';
- m_psz = pszNew;
- }
- else
- {
- }
- }
- return m_psz;
- }
-
- WCHAR * Append2(const WCHAR * pszSrc1, const WCHAR * pszSrc2)
- {
- ULONG lenSrc1 = pszSrc1 ? wcslen(pszSrc1) : 0;
- ULONG lenSrc2 = pszSrc2 ? wcslen(pszSrc2) : 0;
-
- if (lenSrc1 || lenSrc2)
- {
- ULONG lenMe = Length();
- WCHAR *pszNew = (WCHAR *)::CoTaskMemAlloc((lenMe + lenSrc1 + lenSrc2 + 1) * sizeof(WCHAR));
- if (pszNew)
- {
- if (m_psz) // Could append to an empty string so check...
- {
- if (lenMe)
- {
- memcpy(pszNew, m_psz, lenMe * sizeof(WCHAR));
- }
- ::CoTaskMemFree(m_psz);
- }
- // In both of these cases, we copy the trailing NULL so that we're sure it gets
- // there (if lenSrc2 is 0 then we better copy it from pszSrc1).
- if (lenSrc1)
- {
- memcpy(pszNew + lenMe, pszSrc1, (lenSrc1 + 1) * sizeof(WCHAR));
- }
- if (lenSrc2)
- {
- memcpy(pszNew + lenMe + lenSrc1, pszSrc2, (lenSrc2 + 1) * sizeof(WCHAR));
- }
- m_psz = pszNew;
- }
- else
- {
- }
- }
- return m_psz;
- }
- WCHAR * Copy() const
- {
- if (m_psz)
- {
- CSpDynamicString szNew(m_psz);
- return szNew.Detach();
- }
- return NULL;
- }
- CHAR * CopyToChar() const
- {
- if (m_psz)
- {
- CHAR* psz;
- ULONG cbNeeded = ::WideCharToMultiByte(CP_ACP, 0, m_psz, -1, NULL, NULL, NULL, NULL);
- psz = (CHAR *)::CoTaskMemAlloc(cbNeeded);
- if (psz)
- {
- ::WideCharToMultiByte(CP_ACP, 0, m_psz, -1, psz, cbNeeded/sizeof(CHAR), NULL, NULL);
- }
- return psz;
- }
- return NULL;
- }
- void Attach(WCHAR * pszSrc)
- {
- m_psz = pszSrc;
- }
- WCHAR * Detach()
- {
- WCHAR * s = m_psz;
- m_psz = NULL;
- return s;
- }
- void Clear()
- {
- ::CoTaskMemFree(m_psz);
- m_psz = NULL;
- }
- bool operator!() const
- {
- return (m_psz == NULL);
- }
- HRESULT CopyToBSTR(BSTR * pbstr)
- {
- if (m_psz)
- {
- *pbstr = ::SysAllocString(m_psz);
- if (*pbstr == NULL)
- {
- return E_OUTOFMEMORY;
- }
- }
- else
- {
- *pbstr = NULL;
- }
- return S_OK;
- }
- void TrimToSize(ULONG ulNumChars)
- {
- if (m_psz && ulNumChars < Length())
- {
- m_psz[ulNumChars] = 0;
- }
- }
- WCHAR * Compact()
- {
- if (m_psz)
- {
- ULONG cch = wcslen(m_psz);
- m_psz = (WCHAR *)::CoTaskMemRealloc(m_psz, (cch + 1) * sizeof(WCHAR));
- }
- return m_psz;
- }
- WCHAR * ClearAndGrowTo(ULONG cch)
- {
- if (m_psz)
- {
- Clear();
- }
- m_psz = (WCHAR *)::CoTaskMemAlloc(cch * sizeof(WCHAR));
- return m_psz;
- }
- WCHAR * LTrim()
- {
- if (m_psz)
- {
- WCHAR * pszRead = m_psz;
- while (iswspace(*pszRead))
- {
- pszRead++;
- }
- if (pszRead != m_psz)
- {
- WCHAR * pszWrite = m_psz;
- while (*pszRead)
- {
- *pszWrite++ = *pszRead++;
- }
- *pszWrite = '\0';
- }
- }
- return m_psz;
- }
- WCHAR * RTrim()
- {
- if (m_psz)
- {
- WCHAR * pszTail = m_psz + wcslen(m_psz);
- WCHAR * pszZeroTerm = pszTail;
- while (pszZeroTerm > m_psz && iswspace(pszZeroTerm[-1]))
- {
- pszZeroTerm--;
- }
- if (pszZeroTerm != pszTail)
- {
- *pszZeroTerm = '\0';
- }
- }
- return m_psz;
- }
- WCHAR * TrimBoth()
- {
- RTrim();
- return LTrim();
- }
-};
-
-
-
-//
-// Simple inline function converts a ulong to a hex string.
-//
-inline void SpHexFromUlong(WCHAR * psz, ULONG ul)
-{
- const static WCHAR szHexChars[] = L"0123456789ABCDEF";
- if (ul == 0)
- {
- psz[0] = L'0';
- psz[1] = 0;
- }
- else
- {
- ULONG ulChars = 1;
- psz[0] = 0;
- while (ul)
- {
- memmove(psz + 1, psz, ulChars * sizeof(WCHAR));
- psz[0] = szHexChars[ul % 16];
- ul /= 16;
- ulChars++;
- }
- }
-}
-
-
-//=== Token helpers
-
-inline HRESULT SpGetTokenFromId(
- const WCHAR * pszTokenId,
- ISpObjectToken ** ppToken,
- BOOL fCreateIfNotExist = FALSE)
-{
-
- LPUNKNOWN pUnkOuter = nullptr;
- HRESULT hr = ::CoCreateInstance(CLSID_SpObjectToken, pUnkOuter, CLSCTX_ALL, IID_ISpObjectToken,reinterpret_cast<void **>(ppToken));
-
- if (SUCCEEDED(hr))
- {
- (*ppToken)->SetId(NULL, pszTokenId, fCreateIfNotExist);
- }
-
- return hr;
-}
-
-inline HRESULT SpGetCategoryFromId(
- const WCHAR * pszCategoryId,
- ISpObjectTokenCategory ** ppCategory,
- BOOL fCreateIfNotExist = FALSE)
-{
- LPUNKNOWN pUnkOuter = nullptr;
- HRESULT hr = ::CoCreateInstance(CLSID_SpObjectTokenCategory, pUnkOuter, CLSCTX_ALL, IID_ISpObjectTokenCategory, reinterpret_cast<void **>(ppCategory));
-
- if (SUCCEEDED(hr))
- {
- hr = (*ppCategory)->SetId(pszCategoryId, fCreateIfNotExist);
- }
-
- return hr;
-}
-
-inline HRESULT SpGetDefaultTokenIdFromCategoryId(
- const WCHAR * pszCategoryId,
- WCHAR ** ppszTokenId)
-{
- HRESULT hr;
-
- ISpObjectTokenCategory *cpCategory;
- hr = SpGetCategoryFromId(pszCategoryId, &cpCategory);
-
- if (SUCCEEDED(hr))
- {
- hr = cpCategory->GetDefaultTokenId(ppszTokenId);
- }
-
- return hr;
-}
-
-inline HRESULT SpSetDefaultTokenIdForCategoryId(
- const WCHAR * pszCategoryId,
- const WCHAR * pszTokenId)
-{
- HRESULT hr;
-
- ISpObjectTokenCategory *cpCategory;
- hr = SpGetCategoryFromId(pszCategoryId, &cpCategory);
-
- if (SUCCEEDED(hr))
- {
- hr = cpCategory->SetDefaultTokenId(pszTokenId);
- }
-
- return hr;
-}
-
-inline HRESULT SpGetDefaultTokenFromCategoryId(
- const WCHAR * pszCategoryId,
- ISpObjectToken ** ppToken,
- BOOL fCreateCategoryIfNotExist = TRUE)
-{
- HRESULT hr;
-
- ISpObjectTokenCategory *cpCategory;
- hr = SpGetCategoryFromId(pszCategoryId, &cpCategory, fCreateCategoryIfNotExist);
-
- if (SUCCEEDED(hr))
- {
- WCHAR * pszTokenId;
- hr = cpCategory->GetDefaultTokenId(&pszTokenId);
- if (SUCCEEDED(hr))
- {
- hr = SpGetTokenFromId(pszTokenId, ppToken);
- ::CoTaskMemFree(pszTokenId);
- }
- }
-
- return hr;
-}
-
-inline HRESULT SpSetDefaultTokenForCategoryId(
- const WCHAR * pszCategoryId,
- ISpObjectToken * pToken)
-{
- HRESULT hr;
-
- WCHAR * pszTokenId;
- hr = pToken->GetId(&pszTokenId);
-
- if (SUCCEEDED(hr))
- {
- hr = SpSetDefaultTokenIdForCategoryId(pszCategoryId, pszTokenId);
- ::CoTaskMemFree(pszTokenId);
- }
-
- return hr;
-}
-
-inline HRESULT SpSetCommonTokenData(
- ISpObjectToken * pToken,
- const CLSID * pclsid,
- const WCHAR * pszLangIndependentName,
- LANGID langid,
- const WCHAR * pszLangDependentName,
- ISpDataKey ** ppDataKeyAttribs)
-{
- HRESULT hr = S_OK;
-
- // Set the new token's CLSID (if specified)
- if (SUCCEEDED(hr) && pclsid)
- {
- CSpDynamicString dstrClsid;
- hr = StringFromCLSID(*pclsid, &dstrClsid);
-
- if (SUCCEEDED(hr))
- {
- hr = pToken->SetStringValue(SPTOKENVALUE_CLSID, dstrClsid);
- }
- }
-
- // Set the token's lang independent name
- if (SUCCEEDED(hr) && pszLangIndependentName)
- {
- hr = pToken->SetStringValue(NULL, pszLangIndependentName);
- }
-
- // Set the token's lang dependent name
- if (SUCCEEDED(hr) && pszLangDependentName)
- {
- WCHAR szLangId[10];
- SpHexFromUlong(szLangId, langid);
-
- hr = pToken->SetStringValue(szLangId, pszLangDependentName);
- }
-
- // Open the attributes key if requested
- if (SUCCEEDED(hr) && ppDataKeyAttribs)
- {
- hr = pToken->CreateKey(L"Attributes", ppDataKeyAttribs);
- }
-
- return hr;
-}
-
-inline HRESULT SpCreateNewToken(
- const WCHAR * pszTokenId,
- ISpObjectToken ** ppToken)
-{
- HRESULT hr;
-
- // Forcefully create the token
- hr = SpGetTokenFromId(pszTokenId, ppToken, TRUE);
-
- return hr;
-}
-
-inline HRESULT SpCreateNewToken(
- const WCHAR * pszCategoryId,
- const WCHAR * pszTokenKeyName,
- ISpObjectToken ** ppToken)
-{
- HRESULT hr;
-
- // Forcefully create the category
- ISpObjectTokenCategory *cpCategory;
- hr = SpGetCategoryFromId(pszCategoryId, &cpCategory, TRUE);
-
- // Come up with a token key name if one wasn't specified
- CSpDynamicString dstrTokenKeyName;
- if (SUCCEEDED(hr))
- {
- if (pszTokenKeyName == NULL)
- {
- GUID guidTokenKeyName;
- hr = CoCreateGuid(&guidTokenKeyName);
-
- if (SUCCEEDED(hr))
- {
- hr = StringFromCLSID(guidTokenKeyName, &dstrTokenKeyName);
- }
-
- if (SUCCEEDED(hr))
- {
- pszTokenKeyName = dstrTokenKeyName;
- }
- }
- }
-
- // Build the token id
- CSpDynamicString dstrTokenId;
- if (SUCCEEDED(hr))
- {
- dstrTokenId = pszCategoryId;
- dstrTokenId.Append2(L"\\Tokens\\", pszTokenKeyName);
- }
-
- // Forcefully create the token
- if (SUCCEEDED(hr))
- {
- hr = SpGetTokenFromId(dstrTokenId, ppToken, TRUE);
- }
-
- return hr;
-}
-
-inline HRESULT SpCreateNewTokenEx(
- const WCHAR * pszCategoryId,
- const WCHAR * pszTokenKeyName,
- const CLSID * pclsid,
- const WCHAR * pszLangIndependentName,
- LANGID langid,
- const WCHAR * pszLangDependentName,
- ISpObjectToken ** ppToken,
- ISpDataKey ** ppDataKeyAttribs)
-{
- HRESULT hr;
-
- // Create the new token
- hr = SpCreateNewToken(pszCategoryId, pszTokenKeyName, ppToken);
-
- // Now set the extra data
- if (SUCCEEDED(hr))
- {
- hr = SpSetCommonTokenData(
- *ppToken,
- pclsid,
- pszLangIndependentName,
- langid,
- pszLangDependentName,
- ppDataKeyAttribs);
- }
-
- return hr;
-}
-
-inline HRESULT SpCreateNewTokenEx(
- const WCHAR * pszTokenId,
- const CLSID * pclsid,
- const WCHAR * pszLangIndependentName,
- LANGID langid,
- const WCHAR * pszLangDependentName,
- ISpObjectToken ** ppToken,
- ISpDataKey ** ppDataKeyAttribs)
-{
- HRESULT hr;
-
- // Create the new token
- hr = SpCreateNewToken(pszTokenId, ppToken);
-
- // Now set the extra data
- if (SUCCEEDED(hr))
- {
- hr = SpSetCommonTokenData(
- *ppToken,
- pclsid,
- pszLangIndependentName,
- langid,
- pszLangDependentName,
- ppDataKeyAttribs);
- }
-
- return hr;
-}
-
-inline HRESULT SpEnumTokens(
- const WCHAR * pszCategoryId,
- const WCHAR * pszReqAttribs,
- const WCHAR * pszOptAttribs,
- IEnumSpObjectTokens ** ppEnum)
-{
- HRESULT hr = S_OK;
-
- ISpObjectTokenCategory *cpCategory;
- hr = SpGetCategoryFromId(pszCategoryId, &cpCategory);
-
- if (SUCCEEDED(hr))
- {
- hr = cpCategory->EnumTokens(
- pszReqAttribs,
- pszOptAttribs,
- ppEnum);
- }
-
- return hr;
-}
-
-inline HRESULT SpFindBestToken(
- const WCHAR * pszCategoryId,
- const WCHAR * pszReqAttribs,
- const WCHAR * pszOptAttribs,
- ISpObjectToken **ppObjectToken)
-{
- HRESULT hr = S_OK;
-
- const WCHAR *pszVendorPreferred = L"VendorPreferred";
- const unsigned long LenVendorPreferred = wcslen(pszVendorPreferred);
-
- // append VendorPreferred to the end of pszOptAttribs to force this preference
- ULONG ulLen = pszOptAttribs ? wcslen(pszOptAttribs) + LenVendorPreferred + 1 : LenVendorPreferred;
- WCHAR *pszOptAttribsVendorPref = (WCHAR*)_alloca((ulLen+1)*sizeof(WCHAR));
- if (pszOptAttribsVendorPref)
- {
- if (pszOptAttribs)
- {
- wcscpy(pszOptAttribsVendorPref, pszOptAttribs);
- wcscat(pszOptAttribsVendorPref, L";");
- wcscat(pszOptAttribsVendorPref, pszVendorPreferred);
- }
- else
- {
- wcscpy(pszOptAttribsVendorPref, pszVendorPreferred);
- }
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
-
- IEnumSpObjectTokens *cpEnum;
- if (SUCCEEDED(hr))
- {
- hr = SpEnumTokens(pszCategoryId, pszReqAttribs, pszOptAttribsVendorPref, &cpEnum);
- }
-
- if (SUCCEEDED(hr))
- {
- hr = cpEnum->Next(1, ppObjectToken, NULL);
- if (hr == S_FALSE)
- {
- *ppObjectToken = NULL;
- hr = SPERR_NOT_FOUND;
- }
- }
-
- if (hr != SPERR_NOT_FOUND)
- {
- }
-
- return hr;
-}
-
-
-/****************************************************************************
-* SpHrFromWin32 *
-*---------------*
-* Description:
-* This inline function works around a basic problem with the macro
-* HRESULT_FROM_WIN32. The macro forces the expresion in ( ) to be evaluated
-* two times. By using this inline function, the expression will only be
-* evaluated once.
-*
-* Returns:
-* HRESULT of converted Win32 error code
-*
-*****************************************************************************/
-
-inline HRESULT SpHrFromWin32(DWORD dwErr)
-{
- return HRESULT_FROM_WIN32(dwErr);
-}
-
-
-/****************************************************************************
-* SpHrFromLastWin32Error *
-*------------------------*
-* Description:
-* This simple inline function is used to return a converted HRESULT
-* from the Win32 function ::GetLastError. Note that using HRESULT_FROM_WIN32
-* will evaluate the error code twice so we don't want to use:
-*
-* HRESULT_FROM_WIN32(::GetLastError())
-*
-* since that will call GetLastError twice.
-* On Win98 and WinMe ::GetLastError() returns 0 for some functions (see MSDN).
-* We therefore check for that and return E_FAIL. This function should only be
-* called in an error case since it will always return an error code!
-*
-* Returns:
-* HRESULT for ::GetLastError()
-*
-*****************************************************************************/
-
-inline HRESULT SpHrFromLastWin32Error()
-{
- DWORD dw = ::GetLastError();
- return (dw == 0) ? E_FAIL : SpHrFromWin32(dw);
-}
-
-
-/****************************************************************************
-* SpGetUserDefaultUILanguage *
-*----------------------------*
-* Description:
-* Returns the default user interface language, using a method
-* appropriate to the platform (Windows 9x, Windows NT, or Windows 2000)
-*
-* Returns:
-* Default UI language
-*
-*****************************************************************************/
-
-inline LANGID SpGetUserDefaultUILanguage(void)
-{
- HRESULT hr = S_OK;
- LANGID wUILang = 0;
-
- OSVERSIONINFO Osv ;
- Osv.dwOSVersionInfoSize = sizeof(Osv) ;
- if(!GetVersionEx(&Osv))
- {
- hr = SpHrFromLastWin32Error();
- }
- // Get the UI language by one of three methods, depending on the system
- else if(Osv.dwPlatformId != VER_PLATFORM_WIN32_NT)
- {
- // Case 1: Running on Windows 9x. Get the system UI language from registry:
- CHAR szData[32];
- DWORD dwSize = sizeof(szData) ;
- HKEY hKey;
-
- long lRet = RegOpenKeyEx(
- HKEY_USERS,
- ".Default\\Control Panel\\desktop\\ResourceLocale",
- 0,
- KEY_READ,
- &hKey);
-
-#ifdef _WIN32_WCE_BUG_10655
- if (lRet == ERROR_INVALID_PARAMETER)
- {
- lRet = ERROR_FILE_NOT_FOUND;
- }
-#endif // _WIN32_WCE_BUG_10655
-
- hr = SpHrFromWin32(lRet);
-
- if (SUCCEEDED(hr))
- {
- lRet = RegQueryValueEx(
- hKey,
- "",
- NULL,
- NULL,
- (BYTE *)szData,
- &dwSize);
-
-#ifdef _WIN32_WCE_BUG_10655
- if(lRet == ERROR_INVALID_PARAMETER)
- {
- lRet = ERROR_FILE_NOT_FOUND;
- }
-#endif //_WIN32_WCE_BUG_10655
-
- hr = SpHrFromWin32(lRet);
- ::RegCloseKey(hKey) ;
- }
- if (SUCCEEDED(hr))
- {
- // Convert string to number
- wUILang = (LANGID) strtol(szData, NULL, 16) ;
- }
- }
- else if (Osv.dwMajorVersion >= 5.0)
- {
- // Case 2: Running on Windows 2000 or later. Use GetUserDefaultUILanguage to find
- // the user's prefered UI language
-
-
- HMODULE hMKernel32 = ::LoadLibraryW(L"kernel32.dll") ;
- if (hMKernel32 == NULL)
- {
- hr = SpHrFromLastWin32Error();
- }
- else
- {
-
- LANGID (WINAPI *pfnGetUserDefaultUILanguage) () =
- (LANGID (WINAPI *)(void))
-#ifdef _WIN32_WCE
- GetProcAddress(hMKernel32, L"GetUserDefaultUILanguage") ;
-#else
- GetProcAddress(hMKernel32, "GetUserDefaultUILanguage") ;
-#endif
-
- if(NULL != pfnGetUserDefaultUILanguage)
- {
- wUILang = pfnGetUserDefaultUILanguage() ;
- }
- else
- { // GetProcAddress failed
- hr = SpHrFromLastWin32Error();
- }
- ::FreeLibrary(hMKernel32);
- }
- }
- else {
- // Case 3: Running on Windows NT 4.0 or earlier. Get UI language
- // from locale of .default user in registry:
- // HKEY_USERS\.DEFAULT\Control Panel\International\Locale
-
- WCHAR szData[32] ;
- DWORD dwSize = sizeof(szData) ;
- HKEY hKey ;
-
- LONG lRet = RegOpenKeyEx(HKEY_USERS,
- ".DEFAULT\\Control Panel\\International",
- 0,
- KEY_READ,
- &hKey);
-#ifdef _WIN32_WCE_BUG_10655
- if(lRet == ERROR_INVALID_PARAMETER)
- {
- lRet = ERROR_FILE_NOT_FOUND;
- }
-#endif //_WIN32_WCE_BUG_10655
-
- hr = SpHrFromWin32(lRet);
-
- if (SUCCEEDED(hr))
- {
- lRet = RegQueryValueEx(
- hKey,
- "Locale",
- NULL,
- NULL,
- (BYTE *)szData,
- &dwSize);
-
-#ifdef _WIN32_WCE_BUG_10655
- if(lRet == ERROR_INVALID_PARAMETER)
- {
- lRet = ERROR_FILE_NOT_FOUND;
- }
-#endif //_WIN32_WCE_BUG_10655
-
- hr = SpHrFromWin32(lRet);
- ::RegCloseKey(hKey);
- }
-
- if (SUCCEEDED(hr))
- {
- // Convert string to number
- wUILang = (LANGID) wcstol(szData, NULL, 16) ;
-
- if(0x0401 == wUILang || // Arabic
- 0x040d == wUILang || // Hebrew
- 0x041e == wUILang // Thai
- )
- {
- // Special case these to the English UI.
- // These versions of Windows NT 4.0 were enabled only, i.e., the
- // UI was English. However, the registry setting
- // HKEY_USERS\.DEFAULT\Control Panel\International\Locale was set
- // to the respective locale for application compatibility.
- wUILang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) ;
- }
- }
- }
-
- return (wUILang ? wUILang : ::GetUserDefaultLangID()); // In failure case, try our best!
-}
-
-
-inline HRESULT SpGetDescription(ISpObjectToken * pObjToken, WCHAR ** ppszDescription, LANGID Language = SpGetUserDefaultUILanguage())
-{
- WCHAR szLangId[10];
- SpHexFromUlong(szLangId, Language);
- HRESULT hr = pObjToken->GetStringValue(szLangId, ppszDescription);
- if (hr == SPERR_NOT_FOUND)
- {
- hr = pObjToken->GetStringValue(NULL, ppszDescription);
- }
- return hr;
-}
-
-
-inline HRESULT SpSetDescription(ISpObjectToken * pObjToken, const WCHAR * pszDescription, LANGID Language = SpGetUserDefaultUILanguage(), BOOL fSetLangIndependentId = TRUE)
-{
- WCHAR szLangId[10];
- SpHexFromUlong(szLangId, Language);
- HRESULT hr = pObjToken->SetStringValue(szLangId, pszDescription);
- if (SUCCEEDED(hr) && fSetLangIndependentId)
- {
- hr = pObjToken->SetStringValue(NULL, pszDescription);
- }
- return hr;
-}
-
-/****************************************************************************
-* SpConvertStreamFormatEnum *
-*---------------------------*
-* Description:
-* This method converts the specified stream format into a wave format
-* structure.
-*
-*****************************************************************************/
-inline HRESULT SpConvertStreamFormatEnum(SPSTREAMFORMAT eFormat, GUID * pFormatId, WAVEFORMATEX ** ppCoMemWaveFormatEx)
-{
- HRESULT hr = S_OK;
-
- if(pFormatId==NULL || ::IsBadWritePtr(pFormatId, sizeof(*pFormatId))
- || ppCoMemWaveFormatEx==NULL || ::IsBadWritePtr(ppCoMemWaveFormatEx, sizeof(*ppCoMemWaveFormatEx)))
- {
- return E_INVALIDARG;
- }
-
- const GUID * pFmtGuid = &GUID_NULL; // Assume failure case
- if( eFormat >= SPSF_8kHz8BitMono && eFormat <= SPSF_48kHz16BitStereo )
- {
- WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc(sizeof(WAVEFORMATEX));
- *ppCoMemWaveFormatEx = pwfex;
- if (pwfex)
- {
- DWORD dwIndex = eFormat - SPSF_8kHz8BitMono;
- BOOL bIsStereo = dwIndex & 0x1;
- BOOL bIs16 = dwIndex & 0x2;
- DWORD dwKHZ = (dwIndex & 0x3c) >> 2;
- static const DWORD adwKHZ[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 };
- pwfex->wFormatTag = WAVE_FORMAT_PCM;
- pwfex->nChannels = pwfex->nBlockAlign = (WORD)(bIsStereo ? 2 : 1);
- pwfex->nSamplesPerSec = adwKHZ[dwKHZ];
- pwfex->wBitsPerSample = 8;
- if (bIs16)
- {
- pwfex->wBitsPerSample *= 2;
- pwfex->nBlockAlign *= 2;
- }
- pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nBlockAlign;
- pwfex->cbSize = 0;
- pFmtGuid = &SPDFID_WaveFormatEx;
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
- }
- else if( eFormat == SPSF_TrueSpeech_8kHz1BitMono )
- {
- int NumBytes = sizeof( WAVEFORMATEX ) + 32;
- WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( NumBytes );
- *ppCoMemWaveFormatEx = pwfex;
- if( pwfex )
- {
- memset( pwfex, 0, NumBytes );
- pwfex->wFormatTag = WAVE_FORMAT_DSPGROUP_TRUESPEECH;
- pwfex->nChannels = 1;
- pwfex->nSamplesPerSec = 8000;
- pwfex->nAvgBytesPerSec = 1067;
- pwfex->nBlockAlign = 32;
- pwfex->wBitsPerSample = 1;
- pwfex->cbSize = 32;
- BYTE* pExtra = ((BYTE*)pwfex) + sizeof( WAVEFORMATEX );
- pExtra[0] = 1;
- pExtra[2] = 0xF0;
- pFmtGuid = &SPDFID_WaveFormatEx;
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
- }
- else if( (eFormat >= SPSF_CCITT_ALaw_8kHzMono ) &&
- (eFormat <= SPSF_CCITT_ALaw_44kHzStereo ) )
- {
- WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( sizeof(WAVEFORMATEX) );
- *ppCoMemWaveFormatEx = pwfex;
- if( pwfex )
- {
- memset( pwfex, 0, sizeof(WAVEFORMATEX) );
- DWORD dwIndex = eFormat - SPSF_CCITT_ALaw_8kHzMono;
- DWORD dwKHZ = dwIndex / 2;
- static const DWORD adwKHZ[] = { 8000, 11025, 22050, 44100 };
- BOOL bIsStereo = dwIndex & 0x1;
- pwfex->wFormatTag = WAVE_FORMAT_ALAW;
- pwfex->nChannels = pwfex->nBlockAlign = (WORD)(bIsStereo ? 2 : 1);
- pwfex->nSamplesPerSec = adwKHZ[dwKHZ];
- pwfex->wBitsPerSample = 8;
- pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nBlockAlign;
- pwfex->cbSize = 0;
- pFmtGuid = &SPDFID_WaveFormatEx;
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
- }
- else if( (eFormat >= SPSF_CCITT_uLaw_8kHzMono ) &&
- (eFormat <= SPSF_CCITT_uLaw_44kHzStereo ) )
- {
- WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( sizeof(WAVEFORMATEX) );
- *ppCoMemWaveFormatEx = pwfex;
- if( pwfex )
- {
- memset( pwfex, 0, sizeof(WAVEFORMATEX) );
- DWORD dwIndex = eFormat - SPSF_CCITT_uLaw_8kHzMono;
- DWORD dwKHZ = dwIndex / 2;
- static const DWORD adwKHZ[] = { 8000, 11025, 22050, 44100 };
- BOOL bIsStereo = dwIndex & 0x1;
- pwfex->wFormatTag = WAVE_FORMAT_MULAW;
- pwfex->nChannels = pwfex->nBlockAlign = (WORD)(bIsStereo ? 2 : 1);
- pwfex->nSamplesPerSec = adwKHZ[dwKHZ];
- pwfex->wBitsPerSample = 8;
- pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nBlockAlign;
- pwfex->cbSize = 0;
- pFmtGuid = &SPDFID_WaveFormatEx;
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
- }
- else if( (eFormat >= SPSF_ADPCM_8kHzMono ) &&
- (eFormat <= SPSF_ADPCM_44kHzStereo ) )
- {
- int NumBytes = sizeof( WAVEFORMATEX ) + 32;
- WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( NumBytes );
- *ppCoMemWaveFormatEx = pwfex;
- if( pwfex )
- {
- //--- Some of these values seem odd. We used what the codec told us.
- static const DWORD adwKHZ[] = { 8000, 11025, 22050, 44100 };
- static const DWORD BytesPerSec[] = { 4096, 8192, 5644, 11289, 11155, 22311, 22179, 44359 };
- static const DWORD BlockAlign[] = { 256, 256, 512, 1024 };
- static const BYTE Extra811[32] =
- {
- 0xF4, 0x01, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xC0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0x00, 0x00,
- 0xCC, 0x01, 0x30, 0xFF, 0x88, 0x01, 0x18, 0xFF
- };
-
- static const BYTE Extra22[32] =
- {
- 0xF4, 0x03, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xC0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0x00, 0x00,
- 0xCC, 0x01, 0x30, 0xFF, 0x88, 0x01, 0x18, 0xFF
- };
-
- static const BYTE Extra44[32] =
- {
- 0xF4, 0x07, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xC0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0x00, 0x00,
- 0xCC, 0x01, 0x30, 0xFF, 0x88, 0x01, 0x18, 0xFF
- };
-
- static const BYTE* Extra[4] = { Extra811, Extra811, Extra22, Extra44 };
- memset( pwfex, 0, NumBytes );
- DWORD dwIndex = eFormat - SPSF_ADPCM_8kHzMono;
- DWORD dwKHZ = dwIndex / 2;
- BOOL bIsStereo = dwIndex & 0x1;
- pwfex->wFormatTag = WAVE_FORMAT_ADPCM;
- pwfex->nChannels = (WORD)(bIsStereo ? 2 : 1);
- pwfex->nSamplesPerSec = adwKHZ[dwKHZ];
- pwfex->nAvgBytesPerSec = BytesPerSec[dwIndex];
- pwfex->nBlockAlign = (WORD)(BlockAlign[dwKHZ] * pwfex->nChannels);
- pwfex->wBitsPerSample = 4;
- pwfex->cbSize = 32;
- BYTE* pExtra = ((BYTE*)pwfex) + sizeof( WAVEFORMATEX );
- memcpy( pExtra, Extra[dwKHZ], 32 );
- pFmtGuid = &SPDFID_WaveFormatEx;
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
- }
- else if( (eFormat >= SPSF_GSM610_8kHzMono ) &&
- (eFormat <= SPSF_GSM610_44kHzMono ) )
- {
- int NumBytes = sizeof( WAVEFORMATEX ) + 2;
- WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( NumBytes );
- *ppCoMemWaveFormatEx = pwfex;
- if( pwfex )
- {
- //--- Some of these values seem odd. We used what the codec told us.
- static const DWORD adwKHZ[] = { 8000, 11025, 22050, 44100 };
- static const DWORD BytesPerSec[] = { 1625, 2239, 4478, 8957 };
- memset( pwfex, 0, NumBytes );
- DWORD dwIndex = eFormat - SPSF_GSM610_8kHzMono;
- pwfex->wFormatTag = WAVE_FORMAT_GSM610;
- pwfex->nChannels = 1;
- pwfex->nSamplesPerSec = adwKHZ[dwIndex];
- pwfex->nAvgBytesPerSec = BytesPerSec[dwIndex];
- pwfex->nBlockAlign = 65;
- pwfex->wBitsPerSample = 0;
- pwfex->cbSize = 2;
- BYTE* pExtra = ((BYTE*)pwfex) + sizeof( WAVEFORMATEX );
- pExtra[0] = 0x40;
- pExtra[1] = 0x01;
- pFmtGuid = &SPDFID_WaveFormatEx;
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
- }
- else
- {
- *ppCoMemWaveFormatEx = NULL;
- switch (eFormat)
- {
- case SPSF_NoAssignedFormat:
- break;
- case SPSF_Text:
- pFmtGuid = &SPDFID_Text;
- break;
- default:
- hr = E_INVALIDARG;
- break;
- }
- }
- *pFormatId = *pFmtGuid;
- return hr;
-}
-
-class CSpStreamFormat
-{
-public:
- GUID m_guidFormatId;
- WAVEFORMATEX * m_pCoMemWaveFormatEx;
-
-
- static HRESULT CoMemCopyWFEX(const WAVEFORMATEX * pSrc, WAVEFORMATEX ** ppCoMemWFEX)
- {
- ULONG cb = sizeof(WAVEFORMATEX) + pSrc->cbSize;
- *ppCoMemWFEX = (WAVEFORMATEX *)::CoTaskMemAlloc(cb);
- if (*ppCoMemWFEX)
- {
- memcpy(*ppCoMemWFEX, pSrc, cb);
- return S_OK;
- }
- else
- {
- return E_OUTOFMEMORY;
- }
- }
-
-
- CSpStreamFormat()
- {
- m_guidFormatId = GUID_NULL;
- m_pCoMemWaveFormatEx = NULL;
- }
-
- CSpStreamFormat(SPSTREAMFORMAT eFormat, HRESULT * phr)
- {
- *phr = SpConvertStreamFormatEnum(eFormat, &m_guidFormatId, &m_pCoMemWaveFormatEx);
- }
-
- CSpStreamFormat(const WAVEFORMATEX * pWaveFormatEx, HRESULT * phr)
- {
- *phr = CoMemCopyWFEX(pWaveFormatEx, &m_pCoMemWaveFormatEx);
- m_guidFormatId = SUCCEEDED(*phr) ? SPDFID_WaveFormatEx : GUID_NULL;
- }
-
- ~CSpStreamFormat()
- {
- ::CoTaskMemFree(m_pCoMemWaveFormatEx);
- }
-
- void Clear()
- {
- ::CoTaskMemFree(m_pCoMemWaveFormatEx);
- m_pCoMemWaveFormatEx = NULL;
- memset(&m_guidFormatId, 0, sizeof(m_guidFormatId));
- }
-
- const GUID & FormatId() const
- {
- return m_guidFormatId;
- }
-
- const WAVEFORMATEX * WaveFormatExPtr() const
- {
- return m_pCoMemWaveFormatEx;
- }
-
-
- HRESULT AssignFormat(SPSTREAMFORMAT eFormat)
- {
- ::CoTaskMemFree(m_pCoMemWaveFormatEx);
- return SpConvertStreamFormatEnum(eFormat, &m_guidFormatId, &m_pCoMemWaveFormatEx);
- }
-
- HRESULT AssignFormat(ISpStreamFormat * pStream)
- {
- ::CoTaskMemFree(m_pCoMemWaveFormatEx);
- m_pCoMemWaveFormatEx = NULL;
- return pStream->GetFormat(&m_guidFormatId, &m_pCoMemWaveFormatEx);
- }
-
- HRESULT AssignFormat(const WAVEFORMATEX * pWaveFormatEx)
- {
- ::CoTaskMemFree(m_pCoMemWaveFormatEx);
- HRESULT hr = CoMemCopyWFEX(pWaveFormatEx, &m_pCoMemWaveFormatEx);
- m_guidFormatId = SUCCEEDED(hr) ? SPDFID_WaveFormatEx : GUID_NULL;
- return hr;
- }
-
- HRESULT AssignFormat(REFGUID rguidFormatId, const WAVEFORMATEX * pWaveFormatEx)
- {
- HRESULT hr = S_OK;
-
- m_guidFormatId = rguidFormatId;
- ::CoTaskMemFree(m_pCoMemWaveFormatEx);
- m_pCoMemWaveFormatEx = NULL;
-
- if (rguidFormatId == SPDFID_WaveFormatEx)
- {
- if (::IsBadReadPtr(pWaveFormatEx, sizeof(*pWaveFormatEx)))
- {
- hr = E_INVALIDARG;
- }
- else
- {
- hr = CoMemCopyWFEX(pWaveFormatEx, &m_pCoMemWaveFormatEx);
- }
-
- if (FAILED(hr))
- {
- m_guidFormatId = GUID_NULL;
- }
- }
-
- return hr;
- }
-
-
- BOOL IsEqual(REFGUID rguidFormatId, const WAVEFORMATEX * pwfex) const
- {
- if (rguidFormatId == m_guidFormatId)
- {
- if (m_pCoMemWaveFormatEx)
- {
- if (pwfex &&
- pwfex->cbSize == m_pCoMemWaveFormatEx->cbSize &&
- memcmp(m_pCoMemWaveFormatEx, pwfex, sizeof(WAVEFORMATEX) + pwfex->cbSize) == 0)
- {
- return TRUE;
- }
- }
- else
- {
- return (pwfex == NULL);
- }
- }
- return FALSE;
- }
-
-
-
- HRESULT ParamValidateAssignFormat(REFGUID rguidFormatId, const WAVEFORMATEX * pWaveFormatEx, BOOL fRequireWaveFormat = FALSE)
- {
- if ((pWaveFormatEx && (::IsBadReadPtr(pWaveFormatEx, sizeof(*pWaveFormatEx)) || rguidFormatId != SPDFID_WaveFormatEx)) ||
- (fRequireWaveFormat && pWaveFormatEx == NULL))
- {
- return E_INVALIDARG;
- }
- return AssignFormat(rguidFormatId, pWaveFormatEx);
- }
-
- SPSTREAMFORMAT ComputeFormatEnum()
- {
- if (m_guidFormatId == GUID_NULL)
- {
- return SPSF_NoAssignedFormat;
- }
- if (m_guidFormatId == SPDFID_Text)
- {
- return SPSF_Text;
- }
- if (m_guidFormatId != SPDFID_WaveFormatEx)
- {
- return SPSF_NonStandardFormat;
- }
- //
- // It is a WAVEFORMATEX. Now determine which type it is and convert.
- //
- DWORD dwIndex = 0;
- switch (m_pCoMemWaveFormatEx->wFormatTag)
- {
- case WAVE_FORMAT_PCM:
- {
- switch (m_pCoMemWaveFormatEx->nChannels)
- {
- case 1:
- break;
- case 2:
- dwIndex |= 1;
- break;
- default:
- return SPSF_ExtendedAudioFormat;
- }
-
- switch (m_pCoMemWaveFormatEx->wBitsPerSample)
- {
- case 8:
- break;
- case 16:
- dwIndex |= 2;
- break;
- default:
- return SPSF_ExtendedAudioFormat;
- }
-
- switch (m_pCoMemWaveFormatEx->nSamplesPerSec)
- {
- case 48000:
- dwIndex += 4; // Fall through
- case 44100:
- dwIndex += 4; // Fall through
- case 32000:
- dwIndex += 4; // Fall through
- case 24000:
- dwIndex += 4; // Fall through
- case 22050:
- dwIndex += 4; // Fall through
- case 16000:
- dwIndex += 4; // Fall through
- case 12000:
- dwIndex += 4; // Fall through
- case 11025:
- dwIndex += 4; // Fall through
- case 8000:
- break;
- default:
- return SPSF_ExtendedAudioFormat;
- }
-
- return static_cast<SPSTREAMFORMAT>(SPSF_8kHz8BitMono + dwIndex);
- }
-
- case WAVE_FORMAT_DSPGROUP_TRUESPEECH:
- {
- return SPSF_TrueSpeech_8kHz1BitMono;
- }
-
- case WAVE_FORMAT_ALAW: // fall through
- case WAVE_FORMAT_MULAW:
- case WAVE_FORMAT_ADPCM:
- {
- switch (m_pCoMemWaveFormatEx->nChannels)
- {
- case 1:
- break;
- case 2:
- dwIndex |= 1;
- break;
- default:
- return SPSF_ExtendedAudioFormat;
- }
-
- if(m_pCoMemWaveFormatEx->wFormatTag == WAVE_FORMAT_ADPCM)
- {
- if(m_pCoMemWaveFormatEx->wBitsPerSample != 4)
- {
- return SPSF_ExtendedAudioFormat;
- }
- }
- else if(m_pCoMemWaveFormatEx->wBitsPerSample != 8)
- {
- return SPSF_ExtendedAudioFormat;
- }
-
- switch (m_pCoMemWaveFormatEx->nSamplesPerSec)
- {
- case 44100:
- dwIndex += 2; // Fall through
- case 22050:
- dwIndex += 2; // Fall through
- case 11025:
- dwIndex += 2; // Fall through
- case 8000:
- break;
- default:
- return SPSF_ExtendedAudioFormat;
- }
-
- switch( m_pCoMemWaveFormatEx->wFormatTag )
- {
- case WAVE_FORMAT_ALAW:
- return static_cast<SPSTREAMFORMAT>(SPSF_CCITT_ALaw_8kHzMono + dwIndex);
- case WAVE_FORMAT_MULAW:
- return static_cast<SPSTREAMFORMAT>(SPSF_CCITT_uLaw_8kHzMono + dwIndex);
- case WAVE_FORMAT_ADPCM:
- return static_cast<SPSTREAMFORMAT>(SPSF_ADPCM_8kHzMono + dwIndex);
- }
- }
-
- case WAVE_FORMAT_GSM610:
- {
- if( m_pCoMemWaveFormatEx->nChannels != 1 )
- {
- return SPSF_ExtendedAudioFormat;
- }
-
- switch (m_pCoMemWaveFormatEx->nSamplesPerSec)
- {
- case 44100:
- dwIndex = 3;
- break;
- case 22050:
- dwIndex = 2;
- break;
- case 11025:
- dwIndex = 1;
- break;
- case 8000:
- dwIndex = 0;
- break;
- default:
- return SPSF_ExtendedAudioFormat;
- }
-
- return static_cast<SPSTREAMFORMAT>(SPSF_GSM610_8kHzMono + dwIndex);
- }
-
- default:
- return SPSF_ExtendedAudioFormat;
- break;
- }
- }
-
- void DetachTo(CSpStreamFormat & Other)
- {
- ::CoTaskMemFree(Other.m_pCoMemWaveFormatEx);
- Other.m_guidFormatId = m_guidFormatId;
- Other.m_pCoMemWaveFormatEx = m_pCoMemWaveFormatEx;
- m_pCoMemWaveFormatEx = NULL;
- memset(&m_guidFormatId, 0, sizeof(m_guidFormatId));
- }
-
- void DetachTo(GUID * pFormatId, WAVEFORMATEX ** ppCoMemWaveFormatEx)
- {
- *pFormatId = m_guidFormatId;
- *ppCoMemWaveFormatEx = m_pCoMemWaveFormatEx;
- m_pCoMemWaveFormatEx = NULL;
- memset(&m_guidFormatId, 0, sizeof(m_guidFormatId));
- }
-
- HRESULT CopyTo(GUID * pFormatId, WAVEFORMATEX ** ppCoMemWFEX) const
- {
- HRESULT hr = S_OK;
- *pFormatId = m_guidFormatId;
- if (m_pCoMemWaveFormatEx)
- {
- hr = CoMemCopyWFEX(m_pCoMemWaveFormatEx, ppCoMemWFEX);
- if (FAILED(hr))
- {
- memset(pFormatId, 0, sizeof(*pFormatId));
- }
- }
- else
- {
- *ppCoMemWFEX = NULL;
- }
- return hr;
- }
-
- HRESULT CopyTo(CSpStreamFormat & Other) const
- {
- ::CoTaskMemFree(Other.m_pCoMemWaveFormatEx);
- return CopyTo(&Other.m_guidFormatId, &Other.m_pCoMemWaveFormatEx);
- }
-
- HRESULT AssignFormat(const CSpStreamFormat & Src)
- {
- return Src.CopyTo(*this);
- }
-
-
- HRESULT ParamValidateCopyTo(GUID * pFormatId, WAVEFORMATEX ** ppCoMemWFEX) const
- {
- if (::IsBadWritePtr(pFormatId, sizeof(*pFormatId)) ||
- ::IsBadWritePtr(ppCoMemWFEX, sizeof(*ppCoMemWFEX)))
- {
- return E_POINTER;
- }
- return CopyTo(pFormatId, ppCoMemWFEX);
- }
-
- BOOL operator==(const CSpStreamFormat & Other) const
- {
- return IsEqual(Other.m_guidFormatId, Other.m_pCoMemWaveFormatEx);
- }
- BOOL operator!=(const CSpStreamFormat & Other) const
- {
- return !IsEqual(Other.m_guidFormatId, Other.m_pCoMemWaveFormatEx);
- }
-
- ULONG SerializeSize() const
- {
- ULONG cb = sizeof(ULONG) + sizeof(m_guidFormatId);
- if (m_pCoMemWaveFormatEx)
- {
- cb += sizeof(WAVEFORMATEX) + m_pCoMemWaveFormatEx->cbSize + 3; // Add 3 to round up
- cb -= cb % 4; // Round to DWORD
- }
- return cb;
- }
-
- ULONG Serialize(BYTE * pBuffer) const
- {
- ULONG cb = SerializeSize();
- *((UNALIGNED ULONG *)pBuffer) = cb;
- pBuffer += sizeof(ULONG);
- *((UNALIGNED GUID *)pBuffer) = m_guidFormatId;
- if (m_pCoMemWaveFormatEx)
- {
- pBuffer += sizeof(m_guidFormatId);
- memcpy(pBuffer, m_pCoMemWaveFormatEx, sizeof(WAVEFORMATEX) + m_pCoMemWaveFormatEx->cbSize);
- }
- return cb;
- }
-
- HRESULT Deserialize(const BYTE * pBuffer, ULONG * pcbUsed)
- {
- HRESULT hr = S_OK;
- ::CoTaskMemFree(m_pCoMemWaveFormatEx);
- m_pCoMemWaveFormatEx = NULL;
- *pcbUsed = *((UNALIGNED ULONG *)pBuffer);
- pBuffer += sizeof(ULONG);
- // Misaligment exception is generated for SHx platform.
- // Marking pointer as UNALIGNED does not help.
-#ifndef _WIN32_WCE
- m_guidFormatId = *((UNALIGNED GUID *)pBuffer);
-#else
- memcpy(&m_guidFormatId, pBuffer, sizeof(GUID));
-#endif
- if (*pcbUsed > sizeof(GUID) + sizeof(ULONG))
- {
- pBuffer += sizeof(m_guidFormatId);
- hr = CoMemCopyWFEX((const WAVEFORMATEX *)pBuffer, &m_pCoMemWaveFormatEx);
- if (FAILED(hr))
- {
- m_guidFormatId = GUID_NULL;
- }
- }
- return hr;
- }
-
-};
-
-
-
-// Return the default codepage given a LCID.
-// Note some of the newer locales do not have associated Windows codepages. For these, we return UTF-8.
-
-inline UINT SpCodePageFromLcid(LCID lcid)
-{
- char achCodePage[6];
-
- return (0 != GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, achCodePage, sizeof(achCodePage))) ? atoi(achCodePage) : 65001;
-}
-
-
-/****************************************************************************
-* SpClearEvent *
-*--------------*
-* Description:
-* Helper function that can be used by clients that do not use the CSpEvent
-* class.
-*
-* Returns:
-*
-*****************************************************************************/
-
-inline void SpClearEvent(SPEVENT * pe)
-{
- if( pe->elParamType != SPEI_UNDEFINED)
- {
- if( pe->elParamType == SPET_LPARAM_IS_POINTER ||
- pe->elParamType == SPET_LPARAM_IS_STRING)
- {
- ::CoTaskMemFree((void *)pe->lParam);
- }
- else if (pe->elParamType == SPET_LPARAM_IS_TOKEN ||
- pe->elParamType == SPET_LPARAM_IS_OBJECT)
- {
- ((IUnknown*)pe->lParam)->Release();
- }
- }
- memset(pe, 0, sizeof(*pe));
-}
-
-/****************************************************************************
-* SpInitEvent *
-*-------------*
-* Description:
-*
-* Returns:
-*
-*****************************************************************************/
-
-inline void SpInitEvent(SPEVENT * pe)
-{
- memset(pe, 0, sizeof(*pe));
-}
-
-/****************************************************************************
-* SpEventSerializeSize *
-*----------------------*
-* Description:
-* Computes the required size of a buffer to serialize an event. The caller
-* must specify which type of serialized event is desired -- either SPSERIALIZEDEVENT
-* or SPSERIALIZEDEVENT64.
-*
-* Returns:
-* Size in bytes required to seriailze the event.
-*
-****************************************************************************/
-
-// WCE compiler does not work propertly with template
-#ifndef _WIN32_WCE
-template <class T>
-inline ULONG SpEventSerializeSize(const SPEVENT * pEvent)
-
-{
- ULONG ulSize = sizeof(T);
-
-#else
-
-inline ULONG SpEventSerializeSize(const SPEVENT * pEvent, ULONG ulSize)
-{
-#endif //_WIN32_WCE
-
- if( ( pEvent->elParamType == SPET_LPARAM_IS_POINTER ) && pEvent->lParam )
- {
- ulSize += ULONG(pEvent->wParam);
- }
- else if ((pEvent->elParamType == SPET_LPARAM_IS_STRING) && pEvent->lParam != NULL)
- {
- ulSize += (wcslen((WCHAR*)pEvent->lParam) + 1) * sizeof( WCHAR );
- }
- else if( pEvent->elParamType == SPET_LPARAM_IS_TOKEN )
- {
- CSpDynamicString dstrObjectId;
- if( ((ISpObjectToken*)(pEvent->lParam))->GetId( &dstrObjectId ) == S_OK )
- {
- ulSize += (dstrObjectId.Length() + 1) * sizeof( WCHAR );
- }
- }
- // Round up to nearest DWORD
- ulSize += 3;
- ulSize -= ulSize % 4;
- return ulSize;
-}
-
-/****************************************************************************
-* SpSerializedEventSize *
-*-----------------------*
-* Description:
-* Returns the size, in bytes, used by a serialized event. The caller can
-* pass a pointer to either a SPSERIAILZEDEVENT or SPSERIALIZEDEVENT64 structure.
-*
-* Returns:
-* Number of bytes used by serizlied event
-*
-********************************************************************* RAL ***/
-
-// WCE compiler does not work propertly with template
-#ifndef _WIN32_WCE
-template <class T>
-inline ULONG SpSerializedEventSize(const T * pSerEvent)
-{
- ULONG ulSize = sizeof(T);
-
- if( ( pSerEvent->elParamType == SPET_LPARAM_IS_POINTER ) && pSerEvent->SerializedlParam )
- {
- ulSize += ULONG(pSerEvent->SerializedwParam);
- }
- else if ((pSerEvent->elParamType == SPET_LPARAM_IS_STRING || pSerEvent->elParamType == SPET_LPARAM_IS_TOKEN) &&
- pSerEvent->SerializedlParam != NULL)
- {
- ulSize += (wcslen((WCHAR*)(pSerEvent + 1)) + 1) * sizeof( WCHAR );
- }
- // Round up to nearest DWORD
- ulSize += 3;
- ulSize -= ulSize % 4;
- return ulSize;
-}
-
-#else //_WIN32_WCE
-
-inline ULONG SpSerializedEventSize(const SPSERIALIZEDEVENT * pSerEvent, ULONG ulSize)
-{
- if( ( pSerEvent->elParamType == SPET_LPARAM_IS_POINTER ) && pSerEvent->SerializedlParam )
- {
- ulSize += ULONG(pSerEvent->SerializedwParam);
- }
- else if ((pSerEvent->elParamType == SPET_LPARAM_IS_STRING || pSerEvent->elParamType == SPET_LPARAM_IS_TOKEN) &&
- pSerEvent->SerializedlParam != NULL)
- {
- ulSize += (wcslen((WCHAR*)(pSerEvent + 1)) + 1) * sizeof( WCHAR );
- }
- // Round up to nearest DWORD
- ulSize += 3;
- ulSize -= ulSize % 4;
- return ulSize;
-}
-
-inline ULONG SpSerializedEventSize(const SPSERIALIZEDEVENT64 * pSerEvent, ULONG ulSize)
-{
- if( ( pSerEvent->elParamType == SPET_LPARAM_IS_POINTER ) && pSerEvent->SerializedlParam )
- {
- ulSize += ULONG(pSerEvent->SerializedwParam);
- }
- else if ((pSerEvent->elParamType == SPET_LPARAM_IS_STRING || pSerEvent->elParamType == SPET_LPARAM_IS_TOKEN) &&
- pSerEvent->SerializedlParam != NULL)
- {
- ulSize += (wcslen((WCHAR*)(pSerEvent + 1)) + 1) * sizeof( WCHAR );
- }
- // Round up to nearest DWORD
- ulSize += 3;
- ulSize -= ulSize % 4;
- return ulSize;
-}
-
-#endif //_WIN32_WCE
-
-/*** CSpEvent helper class
-*
-*/
-class CSpEvent : public SPEVENT
-{
-public:
- CSpEvent()
- {
- SpInitEvent(this);
- }
- ~CSpEvent()
- {
- SpClearEvent(this);
- }
- // If you need to take the address of a CSpEvent that is not const, use the AddrOf() method
- // which will do debug checking of parameters. If you encounter this problem when calling
- // GetEvents from an event source, you may want to use the GetFrom() method of this class.
- const SPEVENT * operator&()
- {
- return this;
- }
- CSpEvent * AddrOf()
- {
- // Note: This method does not ASSERT since we assume the caller knows what they are doing.
- return this;
- }
- void Clear()
- {
- SpClearEvent(this);
- }
- HRESULT CopyTo(SPEVENT * pDestEvent) const
- {
- memcpy(pDestEvent, this, sizeof(*pDestEvent));
- if ((elParamType == SPET_LPARAM_IS_POINTER) && lParam)
- {
- pDestEvent->lParam = (LPARAM)::CoTaskMemAlloc(wParam);
- if (pDestEvent->lParam)
- {
- memcpy((void *)pDestEvent->lParam, (void *)lParam, wParam);
- }
- else
- {
- pDestEvent->eEventId = SPEI_UNDEFINED;
- return E_OUTOFMEMORY;
- }
- }
- else if (elParamType == SPET_LPARAM_IS_STRING && lParam != NULL)
- {
- pDestEvent->lParam = (LPARAM)::CoTaskMemAlloc((wcslen((WCHAR*)lParam) + 1) * sizeof(WCHAR));
- if (pDestEvent->lParam)
- {
- wcscpy((WCHAR*)pDestEvent->lParam, (WCHAR*)lParam);
- }
- else
- {
- pDestEvent->eEventId = SPEI_UNDEFINED;
- return E_OUTOFMEMORY;
- }
- }
- else if (elParamType == SPET_LPARAM_IS_TOKEN ||
- elParamType == SPET_LPARAM_IS_OBJECT)
- {
- ((IUnknown*)lParam)->AddRef();
- }
- return S_OK;
- }
-
- HRESULT GetFrom(ISpEventSource * pEventSrc)
- {
- SpClearEvent(this);
- return pEventSrc->GetEvents(1, this, NULL);
- }
- HRESULT CopyFrom(const SPEVENT * pSrcEvent)
- {
- SpClearEvent(this);
- return static_cast<const CSpEvent *>(pSrcEvent)->CopyTo(this);
- }
- void Detach(SPEVENT * pDestEvent = NULL)
- {
- if (pDestEvent)
- {
- memcpy(pDestEvent, this, sizeof(*pDestEvent));
- }
- memset(this, 0, sizeof(*this));
- }
-
- template <class T>
- ULONG SerializeSize() const
- {
- return SpEventSerializeSize<T>(this);
- }
-
- // Call this method with either SPSERIALIZEDEVENT or SPSERIALIZEDEVENT64
- template <class T>
- void Serialize(T * pSerEvent) const
- {
- pSerEvent->eEventId = this->eEventId;
- pSerEvent->elParamType = this->elParamType;
- pSerEvent->ulStreamNum = this->ulStreamNum;
- pSerEvent->ullAudioStreamOffset = this->ullAudioStreamOffset;
- pSerEvent->SerializedwParam = static_cast<ULONG>(this->wParam);
- pSerEvent->SerializedlParam = static_cast<LONG>(this->lParam);
- if (lParam)
- {
- switch(elParamType)
- {
- case SPET_LPARAM_IS_POINTER:
- memcpy(pSerEvent + 1, (void *)lParam, wParam);
- pSerEvent->SerializedlParam = sizeof(T);
- break;
-
- case SPET_LPARAM_IS_STRING:
- wcscpy((WCHAR *)(pSerEvent + 1), (WCHAR*)lParam);
- pSerEvent->SerializedlParam = sizeof(T);
- break;
-
- case SPET_LPARAM_IS_TOKEN:
- {
- CSpDynamicString dstrObjectId;
- if( SUCCEEDED( ((ISpObjectToken*)lParam)->GetId( &dstrObjectId ) ) )
- {
- pSerEvent->SerializedwParam = (dstrObjectId.Length() + 1) * sizeof( WCHAR );;
- memcpy( pSerEvent + 1, (void *)dstrObjectId.m_psz, static_cast<ULONG>(pSerEvent->SerializedwParam) );
- }
- pSerEvent->SerializedlParam = sizeof(T);
- }
- break;
-
- default:
- break;
- }
- }
- }
-
- template <class T>
- HRESULT Serialize(T ** ppCoMemSerEvent, ULONG * pcbSerEvent) const
- {
-// WCE compiler does not work propertly with template
-#ifndef _WIN32_WCE
- *pcbSerEvent = SpEventSerializeSize<T>(this);
-#else
- *pcbSerEvent = SpEventSerializeSize(this, sizeof(** ppCoMemSerEvent));
-#endif
- *ppCoMemSerEvent = (T *)::CoTaskMemAlloc(*pcbSerEvent);
- if (*ppCoMemSerEvent)
- {
- Serialize(*ppCoMemSerEvent);
- return S_OK;
- }
- else
- {
- *pcbSerEvent = 0;
- return E_OUTOFMEMORY;
- }
- }
-
-
- // Call this method with either SPSERIALIZEDEVENT or SPSERIALIZEDEVENT64
- template <class T>
- HRESULT Deserialize(const T * pSerEvent, ULONG * pcbUsed = NULL)
- {
- Clear();
- HRESULT hr = S_OK;
- const UNALIGNED T * pTemp = pSerEvent;
- this->eEventId = pTemp->eEventId;
- this->elParamType = pTemp->elParamType;
- this->ulStreamNum = pTemp->ulStreamNum;
- this->ullAudioStreamOffset = pTemp->ullAudioStreamOffset;
- this->wParam = static_cast<WPARAM>(pTemp->SerializedwParam);
- this->lParam = static_cast<LPARAM>(pTemp->SerializedlParam);
- if (pTemp->SerializedlParam)
- {
- ULONG cbAlloc = 0;
- switch (pTemp->elParamType)
- {
- case SPET_LPARAM_IS_POINTER:
- cbAlloc = static_cast<ULONG>(wParam);
- break;
-
- case SPET_LPARAM_IS_STRING:
- cbAlloc = sizeof(WCHAR) * (1 + wcslen((const WCHAR *)(pTemp + 1)));
- break;
-
- case SPET_LPARAM_IS_TOKEN:
- {
- ULONG ulDataOffset = ULONG(lParam);
- hr = SpGetTokenFromId( (const WCHAR*)(pTemp + 1),
- (ISpObjectToken **)&lParam );
- wParam = 0;
- }
- break;
- }
- if (cbAlloc)
- {
- void * pvBuff = ::CoTaskMemAlloc(cbAlloc);
- this->lParam = (LPARAM)pvBuff;
- if (pvBuff)
- {
- memcpy(pvBuff, pTemp + 1, cbAlloc);
- }
- else
- {
- hr = E_OUTOFMEMORY;
- }
- }
- }
-
- if( SUCCEEDED( hr ) && pcbUsed )
- {
-// WCE compiler does not work propertly with template
-#ifndef _WIN32_WCE
- *pcbUsed = SpEventSerializeSize<T>(this);
-#else
- *pcbUsed = SpEventSerializeSize(this, sizeof(*pTemp));
-#endif
- }
- return hr;
- }
-
- //
- // Helpers for access to events. Performs run-time checks in debug and casts
- // data to the appropriate types
- //
- SPPHONEID Phoneme() const
- {
- return (SPPHONEID)LOWORD(lParam);
- }
- SPVISEMES Viseme() const
- {
- return (SPVISEMES)LOWORD(lParam);
- }
- ULONG InputWordPos() const
- {
- return ULONG(lParam);
- }
- ULONG InputWordLen() const
- {
- return ULONG(wParam);
- }
- ULONG InputSentPos() const
- {
- return ULONG(lParam);
- }
- ULONG InputSentLen() const
- {
- return ULONG(wParam);
- }
- ISpObjectToken * ObjectToken() const
- {
- return (ISpObjectToken *)lParam;
- }
- ISpObjectToken * VoiceToken() const // More explicit check than ObjectToken()
- {
- return ObjectToken();
- }
- BOOL PersistVoiceChange() const
- {
- return (BOOL)wParam;
- }
- IUnknown * Object() const
- {
- return (IUnknown*)lParam;
- }
- ISpRecoResult * RecoResult() const
- {
- return (ISpRecoResult *)Object();
- }
- BOOL IsPaused()
- {
- return (BOOL)(wParam & SPREF_AutoPause);
- }
- BOOL IsEmulated()
- {
- return (BOOL)(wParam & SPREF_Emulated);
- }
- const WCHAR * String() const
- {
- return (const WCHAR*)lParam;
- }
- const WCHAR * BookmarkName() const
- {
- return String();
- }
- const WCHAR * RequestTypeOfUI() const
- {
- return String();
- }
- SPRECOSTATE RecoState() const
- {
- return static_cast<SPRECOSTATE>(wParam);
- }
- const WCHAR * PropertyName() const
- {
- // Note: Don't use String() method here since in the case of string attributes, the elParamType
- // field specifies LPARAM_IS_POINTER, but the attribute name IS the first string in this buffer
- return (const WCHAR*)lParam;
- }
- const LONG PropertyNumValue() const
- {
- return static_cast<LONG>(wParam);
- }
- const WCHAR * PropertyStringValue() const
- {
- // Search for the first NULL and return pointer to the char past it.
- const WCHAR *psz;
- for (psz = (const WCHAR *)lParam; *psz; psz++) {}
- return psz + 1;
- }
- SPINTERFERENCE Interference() const
- {
- return static_cast<SPINTERFERENCE>(lParam);
- }
- HRESULT EndStreamResult() const
- {
- return static_cast<HRESULT>(lParam);
- }
- BOOL InputStreamReleased() const
- {
- return (wParam & SPESF_STREAM_RELEASED) ? TRUE : FALSE;
- }
-};
-
-class CSpPhrasePtr
-{
-public:
- SPPHRASE * m_pPhrase;
- CSpPhrasePtr() : m_pPhrase(NULL) {}
- CSpPhrasePtr(ISpPhrase * pPhraseObj, HRESULT * phr)
- {
- *phr = pPhraseObj->GetPhrase(&m_pPhrase);
- }
- ~CSpPhrasePtr()
- {
- ::CoTaskMemFree(m_pPhrase);
- }
- //The assert on operator& usually indicates a bug. If this is really
- //what is needed, however, take the address of the m_pPhrase member explicitly.
- SPPHRASE ** operator&()
- {
- return &m_pPhrase;
- }
- operator SPPHRASE *() const
- {
- return m_pPhrase;
- }
- SPPHRASE & operator*() const
- {
- return *m_pPhrase;
- }
- SPPHRASE * operator->() const
- {
- return m_pPhrase;
- }
- bool operator!() const
- {
- return (m_pPhrase == NULL);
- }
- void Clear()
- {
- if (m_pPhrase)
- {
- ::CoTaskMemFree(m_pPhrase);
- m_pPhrase = NULL;
- }
- }
- HRESULT GetFrom(ISpPhrase * pPhraseObj)
- {
- Clear();
- return pPhraseObj->GetPhrase(&m_pPhrase);
- }
-};
-
-
-template <class T>
-class CSpCoTaskMemPtr
-{
-public:
- T * m_pT;
- CSpCoTaskMemPtr() : m_pT(NULL) {}
- CSpCoTaskMemPtr(void * pv) : m_pT((T *)pv) {}
- CSpCoTaskMemPtr(ULONG cElements, HRESULT * phr)
- {
- m_pT = (T *)::CoTaskMemAlloc(cElements * sizeof(T));
- *phr = m_pT ? S_OK : E_OUTOFMEMORY;
- }
- ~CSpCoTaskMemPtr()
- {
- ::CoTaskMemFree(m_pT);
- }
- void Clear()
- {
- if (m_pT)
- {
- ::CoTaskMemFree(m_pT);
- m_pT = NULL;
- }
- }
- HRESULT Alloc(ULONG cArrayElements = 1)
- {
- m_pT = (T *)::CoTaskMemRealloc(m_pT, sizeof(T) * cArrayElements);
- return (m_pT ? S_OK : E_OUTOFMEMORY);
- }
- void Attach(void * pv)
- {
- Clear();
- m_pT = (T *)pv;
- }
- T * Detatch()
- {
- T * pT = m_pT;
- m_pT = NULL;
- return pT;
- }
- //The assert on operator& usually indicates a bug. If this is really
- //what is needed, however, take the address of the m_pT member explicitly.
- T ** operator&()
- {
- return &m_pT;
- }
- T * operator->()
- {
- return m_pT;
- }
- operator T *()
- {
- return m_pT;
- }
- bool operator!() const
- {
- return (m_pT == NULL);
- }
-};
-
-
-#endif /* This must be the last line in the file */
diff --git a/backends/text-to-speech/windows/windows-text-to-speech.cpp b/backends/text-to-speech/windows/windows-text-to-speech.cpp
index 2b405f5553..9f4ecf742a 100644
--- a/backends/text-to-speech/windows/windows-text-to-speech.cpp
+++ b/backends/text-to-speech/windows/windows-text-to-speech.cpp
@@ -30,18 +30,7 @@
#include <windows.h>
#include <servprov.h>
-// Mingw-w64 is missing symbols for two guids declared in sapi.h which are used
-// by sphelper-scummvm.h. Mingw32 doesn't include any sapi headers or libraries
-// so the only way to currently build there is to manually use Microsoft's, in
-// which case the guids will be defined by their library.
-#if defined(__MINGW32__) && defined(__MINGW64_VERSION_MAJOR)
-#include <initguid.h>
-DEFINE_GUID(SPDFID_Text, 0x7ceef9f9, 0x3d13, 0x11d2, 0x9e, 0xe7, 0x00, 0xc0, 0x4f, 0x79, 0x73, 0x96);
-DEFINE_GUID(SPDFID_WaveFormatEx, 0xc31adbae, 0x527f, 0x4ff5, 0xa2, 0x30, 0xf6, 0x2b, 0xb6, 0x1f, 0xf7, 0x0c);
-#endif
-
#include <sapi.h>
-#include "backends/text-to-speech/windows/sphelper-scummvm.h"
#include "backends/platform/sdl/win32/win32_wrapper.h"
#include "backends/text-to-speech/windows/windows-text-to-speech.h"
@@ -78,16 +67,30 @@ void WindowsTextToSpeechManager::init() {
return;
// init audio
- CSpStreamFormat format;
- format.AssignFormat(SPSF_11kHz8BitMono);
- ISpObjectToken *pToken;
- HRESULT hr = SpGetDefaultTokenFromCategoryId(SPCAT_AUDIOOUT, &pToken);
+ ISpObjectTokenCategory *pTokenCategory;
+ HRESULT hr = CoCreateInstance(CLSID_SpObjectTokenCategory, NULL, CLSCTX_ALL, IID_ISpObjectTokenCategory, (void **)&pTokenCategory);
+ if (SUCCEEDED(hr)) {
+ hr = pTokenCategory->SetId(SPCAT_AUDIOOUT, TRUE);
+ if (SUCCEEDED(hr)) {
+ WCHAR *tokenId;
+ hr = pTokenCategory->GetDefaultTokenId(&tokenId);
+ if (SUCCEEDED(hr)) {
+ ISpObjectToken *pToken;
+ hr = CoCreateInstance(CLSID_SpObjectToken, NULL, CLSCTX_ALL, IID_ISpObjectToken, (void **)&pToken);
+ if (SUCCEEDED(hr)) {
+ hr = pToken->SetId(NULL, tokenId, FALSE);
+ if (SUCCEEDED(hr)) {
+ hr = pToken->CreateInstance(NULL, CLSCTX_ALL, IID_ISpAudio, (void **)&_audio);
+ }
+ }
+ CoTaskMemFree(tokenId);
+ }
+ }
+ }
if (FAILED(hr)) {
warning("Could not initialize TTS audio");
return;
}
- pToken->CreateInstance(NULL, CLSCTX_ALL, IID_ISpAudio, (void **)&_audio);
- _audio->SetFormat(format.FormatId(), format.WaveFormatExPtr());
// init voice
hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&_voice);
@@ -348,18 +351,22 @@ void WindowsTextToSpeechManager::createVoice(void *cpVoiceToken) {
// description
WCHAR *descW;
- SpGetDescription(voiceToken, &descW);
- char *buffer = Win32::unicodeToAnsi(descW);
- Common::String desc = buffer;
+ char *buffer;
+ Common::String desc;
+ HRESULT hr = voiceToken->GetStringValue(NULL, &descW);
+ if (SUCCEEDED(hr)) {
+ buffer = Win32::unicodeToAnsi(descW);
+ desc = buffer;
+ delete[] buffer;
+ CoTaskMemFree(descW);
+ }
+
if (desc == "Sample TTS Voice") {
// This is really bad voice, it is basicaly unusable
- free(buffer);
return;
}
- free(buffer);
// voice attributes
- HRESULT hr = S_OK;
ISpDataKey *key = nullptr;
hr = voiceToken->OpenKey(L"Attributes", &key);
@@ -379,7 +386,7 @@ void WindowsTextToSpeechManager::createVoice(void *cpVoiceToken) {
}
buffer = Win32::unicodeToAnsi(data);
Common::String language = lcidToLocale(buffer);
- free(buffer);
+ delete[] buffer;
CoTaskMemFree(data);
// only get the voices for the current language
@@ -397,7 +404,7 @@ void WindowsTextToSpeechManager::createVoice(void *cpVoiceToken) {
}
buffer = Win32::unicodeToAnsi(data);
Common::TTSVoice::Gender gender = !strcmp(buffer, "Male") ? Common::TTSVoice::MALE : Common::TTSVoice::FEMALE;
- free(buffer);
+ delete[] buffer;
CoTaskMemFree(data);
// age
@@ -409,7 +416,7 @@ void WindowsTextToSpeechManager::createVoice(void *cpVoiceToken) {
}
buffer = Win32::unicodeToAnsi(data);
Common::TTSVoice::Age age = !strcmp(buffer, "Adult") ? Common::TTSVoice::ADULT : Common::TTSVoice::UNKNOWN_AGE;
- free(buffer);
+ delete[] buffer;
CoTaskMemFree(data);
_ttsState->_availableVoices.push_back(Common::TTSVoice(gender, age, (void *) voiceToken, desc));
@@ -441,12 +448,19 @@ Common::String WindowsTextToSpeechManager::lcidToLocale(Common::String lcid) {
void WindowsTextToSpeechManager::updateVoices() {
_ttsState->_availableVoices.clear();
- HRESULT hr = S_OK;
ISpObjectToken *cpVoiceToken = nullptr;
IEnumSpObjectTokens *cpEnum = nullptr;
unsigned long ulCount = 0;
- hr = SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum);
+ ISpObjectTokenCategory *cpCategory;
+ HRESULT hr = CoCreateInstance(CLSID_SpObjectTokenCategory, NULL, CLSCTX_ALL, IID_ISpObjectTokenCategory, (void**)&cpCategory);
+ if (SUCCEEDED(hr)) {
+ hr = cpCategory->SetId(SPCAT_VOICES, FALSE);
+ if (SUCCEEDED(hr)) {
+ hr = cpCategory->EnumTokens(NULL, NULL, &cpEnum);
+ }
+ }
+
if (SUCCEEDED(hr)) {
hr = cpEnum->GetCount(&ulCount);
}