-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvirtual_tts_mic.cpp
More file actions
144 lines (116 loc) · 3.19 KB
/
Copy pathvirtual_tts_mic.cpp
File metadata and controls
144 lines (116 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <windows.h>
#include <sapi.h>
#include <sperror.h>
#include <iostream>
#include <string>
// libs needed for sapi and virtual cable
#pragma comment(lib, "sapi.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")
// global voice poiner so i can acess it anywhere here
ISpVoice* pVoice;
// log function that works if debug is enabled
void log(const std::string& message)
{
#if _DEBUG
std::cout << "[tts_mic] " << message << std::endl;
#endif
}
// get the virtual cable input token so we can make the voice speak through it
ISpObjectToken* GetCableInputToken()
{
// create a category for audio output tokens
ISpObjectTokenCategory* pCategory = nullptr;
CoCreateInstance(CLSID_SpObjectTokenCategory, nullptr, CLSCTX_ALL, IID_ISpObjectTokenCategory, (void**)&pCategory);
pCategory->SetId(SPCAT_AUDIOOUT, FALSE);
// enumerate the tokens in the category
IEnumSpObjectTokens* pEnum = nullptr;
pCategory->EnumTokens(nullptr, nullptr, &pEnum);
pCategory->Release();
ISpObjectToken* pToken = nullptr;
ISpObjectToken* found = nullptr;
// loop through until we find the virtual cable input token
while (pEnum->Next(1, &pToken, nullptr) == S_OK) {
LPWSTR desc = nullptr;
pToken->GetStringValue(nullptr, &desc);
if (desc && wcsstr(desc, L"CABLE Input") != nullptr) {
found = pToken;
found->AddRef();
}
// free the description string and release the token
if (desc) CoTaskMemFree(desc);
pToken->Release();
}
// release the enumerator
pEnum->Release();
return found;
}
int start_up()
{
log("Setting up voice!");
// initialize COM library
CoInitialize(nullptr);
// create the SAPI voice
pVoice = nullptr;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL, IID_ISpVoice, (void**)&pVoice);
if (FAILED(hr)) {
log("Failed to create SAPI voice.");
return 0;
}
log("Voice initialized successfully!");
log("Setting up voice to use the virtual microphone!");
// get the virtual cable input token and set it as the output for the voice
ISpObjectToken* pCable = GetCableInputToken();
if (pCable) {
pVoice->SetOutput(pCable, FALSE);
pCable->Release();
}
else {
log("Failed to find CABLE Input device.");
return 0;
}
return 1;
}
bool main_loop()
{
std::cout << "Waiting for input! Type 'exit' to quit." << std::endl;
// create a string to hold the input from stdin
std::string input;
// get input from stdin
std::getline(std::cin, input);
// log input for debugging purposes
log("Input received: " + input);
if (input == "exit") {
return true;
}
// convert the input into needed format
std::wstring wline(input.begin(), input.end());
// make it speak the input (will speak it through the virtual microphone)
pVoice->Speak(wline.c_str(), SPF_DEFAULT, nullptr);
return false;
}
void cleanup()
{
// clean up the voice and COM library
if (pVoice) {
pVoice->Release();
pVoice = nullptr;
}
CoUninitialize();
}
int main()
{
log("Starting virtual TTS microphone");
// if can create everything needed then move onto main loop if not then exit with error code 1
if (start_up() == 0)
{
log("Failed to start up virtual TTS microphone");
return 1;
}
bool exit = false;
while (!exit)
{
exit = main_loop();
}
cleanup();
}