Compare commits
3 commits
126566c3cf
...
510d3547a2
Author | SHA1 | Date | |
---|---|---|---|
510d3547a2 | |||
cc59c0c6db | |||
d95d305734 |
13 changed files with 166 additions and 64 deletions
14
Justfile
14
Justfile
|
@ -1,18 +1,14 @@
|
||||||
build:
|
build:
|
||||||
dotnet build -c Release
|
dotnet build -c Release
|
||||||
make -C speech2 -j$(nproc)
|
make -C speech2 CONFIG=Release -j$(nproc)
|
||||||
|
|
||||||
cp speech2/bin/x86/Release/speech2.dll SAPIServer/bin/Release/net40/windows-x86
|
cp speech2/bin/x86/Release/speech2.dll SAPIServer/bin/Release/net40/windows-x86
|
||||||
cp /usr/i686-w64-mingw32/bin/libgcc_s_dw2-1.dll SAPIServer/bin/Release/net40/windows-x86/
|
cp speech2/bin/x86/Release/speech2.pdb SAPIServer/bin/Release/net40/windows-x86
|
||||||
cp /usr/i686-w64-mingw32/bin/libstdc++-6.dll SAPIServer/bin/Release/net40/windows-x86/
|
|
||||||
|
|
||||||
build-debug:
|
build-debug:
|
||||||
dotnet build -c Debug
|
dotnet build -c Debug
|
||||||
make -C speech2 CONFIG=Release -j$(nproc)
|
make -C speech2 CONFIG=Debug -j$(nproc)
|
||||||
|
cp speech2/bin/x86/Debug/speech2.dll SAPIServer/bin/Debug/net40/windows-x86
|
||||||
cp speech2/bin/x86/Release/speech2.dll SAPIServer/bin/Debug/net40/windows-x86
|
cp speech2/bin/x86/Debug/speech2.pdb SAPIServer/bin/Debug/net40/windows-x86
|
||||||
cp /usr/i686-w64-mingw32/bin/libgcc_s_dw2-1.dll SAPIServer/bin/Debug/net40/windows-x86/
|
|
||||||
cp /usr/i686-w64-mingw32/bin/libstdc++-6.dll SAPIServer/bin/Debug/net40/windows-x86/
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf SAPIServer/bin SAPIServer/obj
|
rm -rf SAPIServer/bin SAPIServer/obj
|
||||||
|
|
|
@ -6,8 +6,11 @@ Simple HTTP frontend API for Microsoft Speech API
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
- .NET SDK
|
- .NET SDK
|
||||||
|
- VS2022 lib pack (TODO: link)
|
||||||
- mingw-w64 toolchain built with `win32` thread model (`pthread` won't work)
|
- mingw-w64 toolchain built with `win32` thread model (`pthread` won't work)
|
||||||
|
|
||||||
|
You'll also need to chattr +F (or mount the whole thing with `ciopfs` and rename the headers to lowercase, if not on ext4 or you don't want to tune2fs) the windows sdk header directories so the build works.
|
||||||
|
|
||||||
`just` should do the trick.
|
`just` should do the trick.
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
|
@ -36,16 +36,18 @@ namespace SAPIServer {
|
||||||
|
|
||||||
// Speech2 DLL API. Sync with c++ code.
|
// Speech2 DLL API. Sync with c++ code.
|
||||||
internal class SpeechDLL {
|
internal class SpeechDLL {
|
||||||
[DllImport("speech2.dll")]
|
private const string Speech2DLL = "speech2.dll";
|
||||||
|
|
||||||
|
[DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)]
|
||||||
public static extern IntPtr speech2_create_api(EngineType type);
|
public static extern IntPtr speech2_create_api(EngineType type);
|
||||||
|
|
||||||
[DllImport("speech2.dll")]
|
[DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)]
|
||||||
public static extern void speech2_destroy_api(IntPtr pAPI);
|
public static extern void speech2_destroy_api(IntPtr pAPI);
|
||||||
|
|
||||||
[DllImport("speech2.dll")]
|
[DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)]
|
||||||
public static extern int speech2_api_get_voiceinfo_count(IntPtr pAPI);
|
public static extern int speech2_api_get_voiceinfo_count(IntPtr pAPI);
|
||||||
|
|
||||||
[DllImport("speech2.dll")]
|
[DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)]
|
||||||
public static extern IntPtr speech2_api_get_voiceinfo_index(IntPtr pAPI, int index);
|
public static extern IntPtr speech2_api_get_voiceinfo_index(IntPtr pAPI, int index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +63,8 @@ namespace SAPIServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<VoiceDef> GetVoices() {
|
public List<VoiceDef> GetVoices() {
|
||||||
|
Console.WriteLine("SpeechAPI.GetVoices()");
|
||||||
|
|
||||||
var count = SpeechDLL.speech2_api_get_voiceinfo_count(handle);
|
var count = SpeechDLL.speech2_api_get_voiceinfo_count(handle);
|
||||||
Console.WriteLine($"count {count}");
|
Console.WriteLine($"count {count}");
|
||||||
var list = new List<VoiceDef>();
|
var list = new List<VoiceDef>();
|
||||||
|
|
|
@ -2,35 +2,29 @@ include build/arch.mk
|
||||||
include build/configs.mk
|
include build/configs.mk
|
||||||
|
|
||||||
NAME = speech2
|
NAME = speech2
|
||||||
|
TYPE = dll
|
||||||
BINDIR = bin/$(ARCH)/$(CONFIG)
|
|
||||||
OBJDIR = obj/$(ARCH)/$(CONFIG)
|
|
||||||
|
|
||||||
# Any C++ file in src/ is automatically picked up.
|
# Any C++ file in src/ is automatically picked up.
|
||||||
CXXSRCS = $(wildcard src/*.cpp) $(wildcard src/*/*.cpp)
|
CXXSRCS = $(wildcard src/*.cpp) $(wildcard src/*/*.cpp)
|
||||||
VPATH = $(dir $(CXXSRCS))
|
|
||||||
OBJS = $(addprefix $(OBJDIR)/,$(notdir $(CXXSRCS:.cpp=.o)))
|
|
||||||
|
|
||||||
.PHONY: all dumpinfo clean matrix
|
# Required libraries.
|
||||||
|
LIBS = kernel32.lib shell32.lib user32.lib uuid.lib ole32.lib
|
||||||
|
|
||||||
all: $(BINDIR)/$(NAME).dll
|
.PHONY: all clean matrix
|
||||||
|
|
||||||
# dir rules
|
|
||||||
$(BINDIR)/:
|
|
||||||
echo -e "\e[95mMKDIR $@\e[0m"
|
|
||||||
mkdir -p $(BINDIR)
|
|
||||||
|
|
||||||
$(OBJDIR)/:
|
|
||||||
echo -e "\e[95mMKDIR $@\e[0m"
|
|
||||||
mkdir -p $(OBJDIR)
|
|
||||||
|
|
||||||
include build/rules.mk
|
include build/rules.mk
|
||||||
|
|
||||||
|
all: $(BUILD_PRODUCT)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
echo -e "\e[91mCleaning... \e[0m"
|
echo -e "\e[91mCleaning... \e[0m"
|
||||||
rm -rf $(BINDIR)/ $(OBJS)
|
rm -rf $(BINDIR)/ $(OBJS)
|
||||||
|
|
||||||
|
# A fun make trick. This allows for verbose compilation if desired.
|
||||||
|
# Set V=1 or anything, and it'll be verbose.
|
||||||
$V.SILENT:
|
$V.SILENT:
|
||||||
|
|
||||||
# Include dependency files.
|
# Include dependency files generated by compilation.
|
||||||
|
# `make clean` keeps them so we can reuse, however they can
|
||||||
|
# still optionally be blown away.
|
||||||
-include $(OBJS:.o=.d)
|
-include $(OBJS:.o=.d)
|
||||||
|
|
30
speech2/Makefile.testprog
Normal file
30
speech2/Makefile.testprog
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
include build/arch.mk
|
||||||
|
include build/configs.mk
|
||||||
|
|
||||||
|
NAME = testprog
|
||||||
|
TYPE = exe
|
||||||
|
|
||||||
|
# Any C++ file in src/ is automatically picked up.
|
||||||
|
CXXSRCS = testprog.cpp
|
||||||
|
|
||||||
|
# Required libraries.
|
||||||
|
LIBS = kernel32.lib shell32.lib user32.lib uuid.lib ole32.lib
|
||||||
|
|
||||||
|
.PHONY: all clean matrix
|
||||||
|
|
||||||
|
include build/rules.mk
|
||||||
|
|
||||||
|
all: $(BUILD_PRODUCT)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
echo -e "\e[91mCleaning... \e[0m"
|
||||||
|
rm -rf $(BINDIR)/ $(OBJS)
|
||||||
|
|
||||||
|
# A fun make trick. This allows for verbose compilation if desired.
|
||||||
|
# Set V=1 or anything, and it'll be verbose.
|
||||||
|
$V.SILENT:
|
||||||
|
|
||||||
|
# Include dependency files generated by compilation.
|
||||||
|
# `make clean` keeps them so we can reuse, however they can
|
||||||
|
# still optionally be blown away.
|
||||||
|
-include $(OBJS:.o=.d)
|
|
@ -1,19 +1,26 @@
|
||||||
x86_Valid=yes
|
x86_Valid=yes
|
||||||
x86_TRIPLET=i686-w64-mingw32
|
x86_TRIPLET=i686-pc-windows-msvc
|
||||||
|
|
||||||
#x64_Valid=yes
|
|
||||||
#x64_TRIPLET=x86_64-w64-mingw32
|
|
||||||
|
|
||||||
|
|
||||||
|
# Only supported arch.
|
||||||
ifeq ($(ARCH),)
|
ifeq ($(ARCH),)
|
||||||
ARCH = x86
|
ARCH = x86
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(VCDIR),)
|
||||||
|
$(error Please set VCDIR in your environment to an appropiate path)
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($($(ARCH)_Valid),yes)
|
ifneq ($($(ARCH)_Valid),yes)
|
||||||
$(error Please select a valid target)
|
$(error Please select a valid target)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# if we really need C
|
CC = clang -target $($(ARCH)_TRIPLET)
|
||||||
CC = $($(ARCH)_TRIPLET)-gcc
|
CXX = clang -target $($(ARCH)_TRIPLET)
|
||||||
CXX = $($(ARCH)_TRIPLET)-g++
|
|
||||||
WINDRES = $($(ARCH)_TRIPLET)-windres
|
LD = lld-link
|
||||||
|
|
||||||
|
# This is $(WINDRES) thanks to the fact I
|
||||||
|
# depended on the (relatively low quality)
|
||||||
|
# MinGW toolchain. Thank God For LLVM.
|
||||||
|
WINDRES = llvm-rc
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,33 @@
|
||||||
# Base compiler flags. Only change if you *explicitly* know what you're doing.
|
# Base compiler flags. Only change if you *explicitly* know what you're doing.
|
||||||
BASE_CCFLAGS = -MMD -fvisibility=hidden -std=gnu17 -fpermissive -fno-pic -fno-pie -fno-ident -msse -Iinclude -Isrc -D_UCRT -D_WIN32_WINNT=0x0501
|
|
||||||
BASE_CXXFLAGS = -MMD -fvisibility=hidden -std=c++20 -fpermissive -fno-pic -fno-pie -fno-ident -msse -Iinclude -Isrc -Ithird_party -D_UCRT -D_WIN32_WINNT=0x0501
|
|
||||||
BASE_LDFLAGS = -Wl,--subsystem=windows -fvisibility=hidden -shared -lkernel32 -lshell32 -luser32 -luuid -lole32
|
|
||||||
|
|
||||||
|
CXXRTDIR = $(VCDIR)/crt
|
||||||
|
UCRTDIR = $(VCDIR)/ucrt
|
||||||
|
PSDKDIR = $(VCDIR)/winsdk
|
||||||
|
|
||||||
|
Release_RTLIBS = libcmt.lib libucrt.lib libvcruntime.lib libcpmt.lib
|
||||||
|
Debug_RTLIBS = libcmtd.lib libucrtd.lib libvcruntimed.lib libcpmtd.lib
|
||||||
|
|
||||||
|
# I really should rename this x_x
|
||||||
|
CLANG_FLAGS = -fms-extensions -fms-compatibility-version=19 -isystem $(CXXRTDIR)/include -isystem $(UCRTDIR)/include -isystem $(PSDKDIR)/include/shared -isystem $(PSDKDIR)/include/um
|
||||||
|
|
||||||
|
BASE_FLAGS = -MMD -gcodeview -fvisibility=hidden $(CLANG_FLAGS) -march=pentium-mmx -Iinclude -Isrc -Ithird_party -mstack-alignment=4 -D_WIN32_WINNT=0x0501
|
||||||
|
|
||||||
|
BASE_CCFLAGS = $(BASE_FLAGS) -std=gnu17
|
||||||
|
BASE_CXXFLAGS = $(BASE_FLAGS) -std=c++20
|
||||||
|
BASE_LDFLAGS_SHARED = /dll
|
||||||
|
|
||||||
|
BASE_LDFLAGS = /nodefaultlib /version:5.1 /machine:i386 /subsystem:windows,5.1 /libpath:$(CXXRTDIR)/lib/x86 /libpath:$(UCRTDIR)/lib /libpath:$(PSDKDIR)/lib
|
||||||
|
|
||||||
|
# TODO: Figure out what optimizations are safe and don't break the stack
|
||||||
Release_Valid = yes
|
Release_Valid = yes
|
||||||
Release_CCFLAGS = -O3 -ffast-math -fomit-frame-pointer -DNDEBUG
|
Release_CCFLAGS = -O0 -DNDEBUG
|
||||||
Release_CXXFLAGS = -O3 -ffast-math -fomit-frame-pointer -DNDEBUG
|
Release_CXXFLAGS = -O0 -DNDEBUG
|
||||||
Release_LDFLAGS = -s
|
Release_LDFLAGS = /debug /pdb:$(BINDIR)/$(NAME).pdb
|
||||||
|
|
||||||
Debug_Valid = yes
|
Debug_Valid = yes
|
||||||
Debug_CCFLAGS = -O0 -g -DDEBUG
|
Debug_CCFLAGS = -O0 -DDEBUG # -D_DEBUG
|
||||||
Debug_CXXFLAGS = -O0 -g -DDEBUG
|
Debug_CXXFLAGS = -O0 -DDEBUG # -D_DEBUG -D_ITERATOR_DEBUG_LEVEL=0
|
||||||
Debug_LDFLAGS =
|
Debug_LDFLAGS = /debug /pdb:$(BINDIR)/$(NAME).pdb
|
||||||
|
|
||||||
# select a default configuration or validate configuration
|
# select a default configuration or validate configuration
|
||||||
ifeq ($(CONFIG),)
|
ifeq ($(CONFIG),)
|
||||||
|
@ -21,3 +37,7 @@ endif
|
||||||
ifneq ($($(CONFIG)_Valid),yes)
|
ifneq ($($(CONFIG)_Valid),yes)
|
||||||
$(error Please select a valid configuration)
|
$(error Please select a valid configuration)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# define the directories used for output products here.
|
||||||
|
BINDIR = bin/$(ARCH)/$(CONFIG)
|
||||||
|
OBJDIR = obj/$(ARCH)/$(CONFIG)
|
||||||
|
|
|
@ -1,6 +1,24 @@
|
||||||
|
|
||||||
|
# TODO: Handle C sources and deduplicate.
|
||||||
|
VPATH = $(dir $(CXXSRCS))
|
||||||
|
OBJS = $(addprefix $(OBJDIR)/,$(notdir $(CXXSRCS:.cpp=.o)))
|
||||||
|
|
||||||
|
# Build types
|
||||||
|
ifeq ($(TYPE),dll)
|
||||||
|
BUILD_PRODUCT = $(BINDIR)/$(NAME).dll
|
||||||
|
|
||||||
$(BINDIR)/$(NAME).dll: $(BINDIR)/ $(OBJDIR)/ $(OBJS)
|
$(BINDIR)/$(NAME).dll: $(BINDIR)/ $(OBJDIR)/ $(OBJS)
|
||||||
echo -e "\e[92mLinking binary $@\e[0m"
|
echo -e "\e[92mLinking DLL $@\e[0m"
|
||||||
$(CXX) $(OBJS) $(BASE_LDFLAGS) $($(CONFIG)_LDFLAGS) -o $@
|
$(LD) $(BASE_LDFLAGS_SHARED) $(BASE_LDFLAGS) $($(CONFIG)_LDFLAGS) $($(CONFIG)_RTLIBS) $(LIBS) $(OBJS) /out:$@
|
||||||
|
else
|
||||||
|
ifeq ($(TYPE),exe)
|
||||||
|
BUILD_PRODUCT = $(BINDIR)/$(NAME).exe
|
||||||
|
|
||||||
|
$(BINDIR)/$(NAME).exe: $(BINDIR)/ $(OBJDIR)/ $(OBJS)
|
||||||
|
echo -e "\e[92mLinking EXE $@\e[0m"
|
||||||
|
$(LD) $(BASE_LDFLAGS) $($(CONFIG)_LDFLAGS) $($(CONFIG)_RTLIBS) $(LIBS) $(OBJS) /out:$@
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
$(OBJDIR)/%.o: %.c
|
$(OBJDIR)/%.o: %.c
|
||||||
echo -e "\e[94mCompiling C source file $< ($@)\e[0m"
|
echo -e "\e[94mCompiling C source file $< ($@)\e[0m"
|
||||||
|
@ -17,3 +35,12 @@ $(OBJDIR)/%.o: %.S
|
||||||
$(OBJDIR)/%.o: %.rc
|
$(OBJDIR)/%.o: %.rc
|
||||||
echo -e "\e[94mCompiling Windows resource script $<\e[0m"
|
echo -e "\e[94mCompiling Windows resource script $<\e[0m"
|
||||||
$(WINDRES) -Iinclude $< -o $@
|
$(WINDRES) -Iinclude $< -o $@
|
||||||
|
|
||||||
|
# dir rules
|
||||||
|
$(BINDIR)/:
|
||||||
|
echo -e "\e[95mMKDIR $@\e[0m"
|
||||||
|
mkdir -p $(BINDIR)
|
||||||
|
|
||||||
|
$(OBJDIR)/:
|
||||||
|
echo -e "\e[95mMKDIR $@\e[0m"
|
||||||
|
mkdir -p $(OBJDIR)
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "speechapi.hpp"
|
#include "speechapi.hpp"
|
||||||
|
|
||||||
#define SP2_EXPORT __declspec(dllexport)
|
#define SPEECH2_API __declspec(dllexport) WINAPI
|
||||||
|
|
||||||
// Engine type. Sync with C#
|
// Engine type. Sync with C#
|
||||||
enum class EngineType : int { ET_SAPI4, ET_SAPI5, ET_DECTALK };
|
enum class EngineType : int { ET_SAPI4, ET_SAPI5, ET_DECTALK };
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
SP2_EXPORT void* speech2_create_api(EngineType type) {
|
SPEECH2_API void* speech2_create_api(EngineType type) {
|
||||||
ISpeechAPI* api = nullptr;
|
ISpeechAPI* api = nullptr;
|
||||||
|
|
||||||
|
//printf("speech2_create_api(%d)\n", type);
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case EngineType::ET_SAPI4:
|
case EngineType::ET_SAPI4:
|
||||||
api = ISpeechAPI::CreateSapi4();
|
api = ISpeechAPI::CreateSapi4();
|
||||||
|
@ -17,6 +20,8 @@ SP2_EXPORT void* speech2_create_api(EngineType type) {
|
||||||
default: return nullptr;
|
default: return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("api is %p\n", api);
|
||||||
|
|
||||||
if(auto hr = api->Initialize(); FAILED(hr)) {
|
if(auto hr = api->Initialize(); FAILED(hr)) {
|
||||||
delete api;
|
delete api;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -25,14 +30,14 @@ SP2_EXPORT void* speech2_create_api(EngineType type) {
|
||||||
return static_cast<void*>(api);
|
return static_cast<void*>(api);
|
||||||
}
|
}
|
||||||
|
|
||||||
SP2_EXPORT void speech2_destroy_api(void* engine) {
|
SPEECH2_API void speech2_destroy_api(void* engine) {
|
||||||
if(engine)
|
if(engine)
|
||||||
delete static_cast<ISpeechAPI*>(engine);
|
delete static_cast<ISpeechAPI*>(engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// API bindings TODO
|
// API bindings TODO
|
||||||
|
|
||||||
SP2_EXPORT int speech2_api_get_voiceinfo_count(void* engine) {
|
SPEECH2_API int speech2_api_get_voiceinfo_count(void* engine) {
|
||||||
if(engine) {
|
if(engine) {
|
||||||
auto* api = static_cast<ISpeechAPI*>(engine);
|
auto* api = static_cast<ISpeechAPI*>(engine);
|
||||||
return api->GetVoices().size();
|
return api->GetVoices().size();
|
||||||
|
@ -40,7 +45,7 @@ SP2_EXPORT int speech2_api_get_voiceinfo_count(void* engine) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SP2_EXPORT const ISpeechAPI::VoiceInfo* speech2_api_get_voiceinfo_index(void* engine, int index) {
|
SPEECH2_API const ISpeechAPI::VoiceInfo* speech2_api_get_voiceinfo_index(void* engine, int index) {
|
||||||
if(engine) {
|
if(engine) {
|
||||||
auto* api = static_cast<ISpeechAPI*>(engine);
|
auto* api = static_cast<ISpeechAPI*>(engine);
|
||||||
return &api->GetVoices()[index];
|
return &api->GetVoices()[index];
|
||||||
|
|
|
@ -7,7 +7,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
|
||||||
// have COM initalized by default, so we don't need to do so there.
|
// have COM initalized by default, so we don't need to do so there.
|
||||||
switch(fdwReason) {
|
switch(fdwReason) {
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
CoInitialize(nullptr);
|
//CoInitialize(nullptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DLL_THREAD_ATTACH: break;
|
case DLL_THREAD_ATTACH: break;
|
||||||
|
@ -18,7 +18,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
|
||||||
if(lpvReserved != nullptr) {
|
if(lpvReserved != nullptr) {
|
||||||
break; // do not do cleanup if process termination scenario
|
break; // do not do cleanup if process termination scenario
|
||||||
}
|
}
|
||||||
CoUninitialize();
|
//CoUninitialize();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
#include "sapi4/include/speech.h"
|
#include "sapi4/include/speech.h"
|
||||||
#include "speechapi.hpp"
|
#include "speechapi.hpp"
|
||||||
|
|
||||||
|
// stupid hacky but Whatevers
|
||||||
|
|
||||||
|
|
||||||
struct SpeechAPI_SAPI4 : public ISpeechAPI {
|
struct SpeechAPI_SAPI4 : public ISpeechAPI {
|
||||||
virtual ~SpeechAPI_SAPI4() {
|
virtual ~SpeechAPI_SAPI4() {
|
||||||
printf("~SpeechAPI_SAPI4\n");
|
printf("~SpeechAPI_SAPI4\n");
|
||||||
|
@ -17,9 +20,9 @@ struct SpeechAPI_SAPI4 : public ISpeechAPI {
|
||||||
};
|
};
|
||||||
|
|
||||||
HRESULT Initialize() override {
|
HRESULT Initialize() override {
|
||||||
HRESULT hRes;
|
HRESULT hRes{};
|
||||||
|
|
||||||
printf("speech2: SpeechAPI_Sapi4::Initalize() begin\n");
|
printf("speech2: SpeechAPI_Sapi4::Initalize() begin: %p\n", this);
|
||||||
|
|
||||||
hRes = pEnum.CreateInstance(CLSID_TTSEnumerator, CLSCTX_INPROC);
|
hRes = pEnum.CreateInstance(CLSID_TTSEnumerator, CLSCTX_INPROC);
|
||||||
if(FAILED(hRes))
|
if(FAILED(hRes))
|
||||||
|
@ -30,24 +33,30 @@ struct SpeechAPI_SAPI4 : public ISpeechAPI {
|
||||||
|
|
||||||
printf("speech2: SpeechAPI_Sapi4::Initalize() created enum\n");
|
printf("speech2: SpeechAPI_Sapi4::Initalize() created enum\n");
|
||||||
|
|
||||||
|
|
||||||
|
printf("speech2: SpeechAPI_Sapi4::Initalize() starting enumvoices\n");
|
||||||
|
|
||||||
// Fill out voices
|
// Fill out voices
|
||||||
EnumVoices();
|
EnumVoices();
|
||||||
|
|
||||||
|
printf("speech2: SpeechAPI_Sapi4::Initalize() end enumvoices\n");
|
||||||
|
|
||||||
printf("speech2: SpeechAPI_Sapi4::Initalize() filled out voices! Yay\n");
|
printf("speech2: SpeechAPI_Sapi4::Initalize() end\n");
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnumVoices() {
|
void EnumVoices() {
|
||||||
static TTSMODEINFO found {};
|
static TTSMODEINFO found{};
|
||||||
|
|
||||||
while(!pEnum->Next(1, &found, nullptr)) {
|
while(!pEnum->Next(1, &found, nullptr)) {
|
||||||
//auto ptr = strdup(found.szModeName);
|
auto ptr = _strdup(found.szModeName);
|
||||||
printf("EnumVoices() voice %p\n", &found.szModeName);
|
printf("EnumVoices() voice %s\n", found.szModeName);
|
||||||
//voices.push_back(VoiceInfo { .guid = found.gModeID, .voiceName = ptr });
|
voices.push_back({found.gModeID, ptr});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("EnumVoices() end\n");
|
||||||
|
|
||||||
pEnum->Reset();
|
pEnum->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ struct ISpeechAPI {
|
||||||
//VoiceInfo(VoiceInfo&&) = delete;
|
//VoiceInfo(VoiceInfo&&) = delete;
|
||||||
|
|
||||||
~VoiceInfo() {
|
~VoiceInfo() {
|
||||||
|
// Make this a lot less stupid at some point.
|
||||||
if(voiceName)
|
if(voiceName)
|
||||||
free(voiceName);
|
free(voiceName);
|
||||||
}
|
}
|
||||||
|
|
6
speech2/testprog.cpp
Normal file
6
speech2/testprog.cpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("Hello, C++20 on Windows XP~\n");
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue