History

Lots of progress today

Zach Fox committed 8 years ago

Commit daeedc61 parent 5d4de3d5 files · +94 −51Browse files

Showing the changes to interface/src/scripting/TTSScriptingInterface.cpp (1 of 5 files). Show all

Unified · Split

interface/src/scripting/TTSScriptingInterface.cpp+163−0
@@ -0,0 +1,163 @@
1//
2// TTSScriptingInterface.cpp
3// libraries/audio-client/src/scripting
4//
5// Created by Zach Fox on 2018-10-10.
6// Copyright 2018 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#include "TTSScriptingInterface.h"
13#include "avatar/AvatarManager.h"
14
15TTSScriptingInterface::TTSScriptingInterface() {
16 //
17 // Create text to speech engine
18 //
19 HRESULT hr = m_tts.CoCreateInstance(CLSID_SpVoice);
20 if (FAILED(hr)) {
21 qDebug() << "Text-to-speech engine creation failed.";
22 }
23
24 //
25 // Get token corresponding to default voice
26 //
27 hr = SpGetDefaultTokenFromCategoryId(SPCAT_VOICES, &m_voiceToken, FALSE);
28 if (FAILED(hr)) {
29 qDebug() << "Can't get default voice token.";
30 }
31
32 //
33 // Set default voice
34 //
35 hr = m_tts->SetVoice(m_voiceToken);
36 if (FAILED(hr)) {
37 qDebug() << "Can't set default voice.";
38 }
39}
40
41TTSScriptingInterface::~TTSScriptingInterface() {
42}
43
44class ReleaseOnExit {
45public:
46 ReleaseOnExit(IUnknown* p) : m_p(p) {}
47 ~ReleaseOnExit() {
48 if (m_p) {
49 m_p->Release();
50 }
51 }
52
53private:
54 IUnknown* m_p;
55};
56
57void TTSScriptingInterface::testTone(const bool& alsoInject) {
58 QByteArray byteArray(480000, 0);
59 _lastSoundByteArray.resize(0);
60 _lastSoundByteArray.resize(480000);
61
62 int32_t a = 0;
63 int16_t* samples = reinterpret_cast<int16_t*>(byteArray.data());
64 for (a = 0; a < 240000; a++) {
65 int16_t temp = (glm::sin(glm::radians((float)a))) * 32768;
66 samples[a] = temp;
67 }
68 emit ttsSampleCreated(_lastSoundByteArray);
69
70 if (alsoInject) {
71 AudioInjectorOptions options;
72 options.position = DependencyManager::get<AvatarManager>()->getMyAvatarPosition();
73
74 _lastSoundAudioInjector = AudioInjector::playSound(_lastSoundByteArray, options);
75 }
76}
77
78void TTSScriptingInterface::speakText(const QString& textToSpeak, const bool& alsoInject) {
79 WAVEFORMATEX fmt;
80 fmt.wFormatTag = WAVE_FORMAT_PCM;
81 fmt.nSamplesPerSec = 24000;
82 fmt.wBitsPerSample = 16;
83 fmt.nChannels = 1;
84 fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
85 fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
86 fmt.cbSize = 0;
87
88 IStream* pStream = NULL;
89
90 ISpStream* pSpStream = nullptr;
91 HRESULT hr = CoCreateInstance(CLSID_SpStream, nullptr, CLSCTX_ALL, __uuidof(ISpStream), (void**)&pSpStream);
92 if (FAILED(hr)) {
93 qDebug() << "CoCreateInstance failed.";
94 }
95 ReleaseOnExit rSpStream(pSpStream);
96
97 pStream = SHCreateMemStream(NULL, 0);
98 if (nullptr == pStream) {
99 qDebug() << "SHCreateMemStream failed.";
100 }
101
102 hr = pSpStream->SetBaseStream(pStream, SPDFID_WaveFormatEx, &fmt);
103 if (FAILED(hr)) {
104 qDebug() << "Can't set base stream.";
105 }
106
107 hr = m_tts->SetOutput(pSpStream, true);
108 if (FAILED(hr)) {
109 qDebug() << "Can't set output stream.";
110 }
111
112 ReleaseOnExit rStream(pStream);
113
114 ULONG streamNumber;
115 hr = m_tts->Speak(reinterpret_cast<LPCWSTR>(textToSpeak.utf16()), SPF_IS_XML | SPF_ASYNC | SPF_PURGEBEFORESPEAK,
116 &streamNumber);
117 if (FAILED(hr)) {
118 qDebug() << "Speak failed.";
119 }
120
121 m_tts->WaitUntilDone(-1);
122
123 hr = pSpStream->GetBaseStream(&pStream);
124 if (FAILED(hr)) {
125 qDebug() << "Couldn't get base stream.";
126 }
127
128 hr = IStream_Reset(pStream);
129 if (FAILED(hr)) {
130 qDebug() << "Couldn't reset stream.";
131 }
132
133 ULARGE_INTEGER StreamSize;
134 StreamSize.LowPart = 0;
135 hr = IStream_Size(pStream, &StreamSize);
136
137 DWORD dwSize = StreamSize.QuadPart;
138 char* buf1 = new char[dwSize + 1];
139 memset(buf1, 0, dwSize + 1);
140
141 hr = IStream_Read(pStream, buf1, dwSize);
142 if (FAILED(hr)) {
143 qDebug() << "Couldn't read from stream.";
144 }
145
146 _lastSoundByteArray.resize(0);
147 _lastSoundByteArray.append(buf1, dwSize);
148
149 emit ttsSampleCreated(_lastSoundByteArray);
150
151 if (alsoInject) {
152 AudioInjectorOptions options;
153 options.position = DependencyManager::get<AvatarManager>()->getMyAvatarPosition();
154
155 _lastSoundAudioInjector = AudioInjector::playSound(_lastSoundByteArray, options);
156 }
157}
158
159void TTSScriptingInterface::stopLastSpeech() {
160 if (_lastSoundAudioInjector) {
161 _lastSoundAudioInjector->stop();
162 }
163}