diff --git a/Justfile b/Justfile index c065885..c4dfdcd 100644 --- a/Justfile +++ b/Justfile @@ -1,18 +1,14 @@ build: dotnet build -c Release make -C speech2 CONFIG=Release -j$(nproc) - 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 /usr/i686-w64-mingw32/bin/libstdc++-6.dll SAPIServer/bin/Release/net40/windows-x86/ + cp speech2/bin/x86/Release/speech2.pdb SAPIServer/bin/Release/net40/windows-x86 build-debug: dotnet build -c Debug - make -C speech2 CONFIG=Release -j$(nproc) - - cp speech2/bin/x86/Release/speech2.dll 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/ + make -C speech2 CONFIG=Debug -j$(nproc) + cp speech2/bin/x86/Debug/speech2.dll SAPIServer/bin/Debug/net40/windows-x86 + cp speech2/bin/x86/Debug/speech2.pdb SAPIServer/bin/Debug/net40/windows-x86 clean: rm -rf SAPIServer/bin SAPIServer/obj diff --git a/README.md b/README.md index 3de629f..64602de 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,11 @@ Simple HTTP frontend API for Microsoft Speech API Requirements - .NET SDK +- VS2022 lib pack (TODO: link) - 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. ## Running diff --git a/SAPIServer/SpeechDLL.cs b/SAPIServer/SpeechDLL.cs index a1df34b..e2544e7 100644 --- a/SAPIServer/SpeechDLL.cs +++ b/SAPIServer/SpeechDLL.cs @@ -38,16 +38,16 @@ namespace SAPIServer { internal class SpeechDLL { private const string Speech2DLL = "speech2.dll"; - [DllImport(Speech2DLL, CallingConvention = CallingConvention.Cdecl)] + [DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr speech2_create_api(EngineType type); - [DllImport(Speech2DLL, CallingConvention = CallingConvention.Cdecl)] + [DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)] public static extern void speech2_destroy_api(IntPtr pAPI); - [DllImport(Speech2DLL, CallingConvention = CallingConvention.Cdecl)] + [DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)] public static extern int speech2_api_get_voiceinfo_count(IntPtr pAPI); - [DllImport(Speech2DLL, CallingConvention = CallingConvention.Cdecl)] + [DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr speech2_api_get_voiceinfo_index(IntPtr pAPI, int index); } @@ -63,6 +63,8 @@ namespace SAPIServer { } public List GetVoices() { + Console.WriteLine("SpeechAPI.GetVoices()"); + var count = SpeechDLL.speech2_api_get_voiceinfo_count(handle); Console.WriteLine($"count {count}"); var list = new List(); diff --git a/speech2/Makefile b/speech2/Makefile index b64529d..d4384a1 100644 --- a/speech2/Makefile +++ b/speech2/Makefile @@ -7,6 +7,9 @@ TYPE = dll # Any C++ file in src/ is automatically picked up. CXXSRCS = $(wildcard src/*.cpp) $(wildcard src/*/*.cpp) +# Required libraries. +LIBS = kernel32.lib shell32.lib user32.lib uuid.lib ole32.lib + .PHONY: all clean matrix include build/rules.mk diff --git a/speech2/build/configs.mk b/speech2/build/configs.mk index c6cb3a0..57fd68c 100644 --- a/speech2/build/configs.mk +++ b/speech2/build/configs.mk @@ -1,33 +1,32 @@ # Base compiler flags. Only change if you *explicitly* know what you're doing. - CXXRTDIR = $(VCDIR)/crt UCRTDIR = $(VCDIR)/ucrt PSDKDIR = $(VCDIR)/winsdk -# TODO: Switch to debug builds 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 -g3 -fvisibility=hidden $(CLANG_FLAGS) -march=pentium3 -Iinclude -Isrc -Ithird_party -D_WIN32_WINNT=0x0501 +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:console,5.1 /libpath:$(CXXRTDIR)/lib/x86 /libpath:$(UCRTDIR)/lib /libpath:$(PSDKDIR)/lib +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_CCFLAGS = -O3 -DNDEBUG -Release_CXXFLAGS = -O3 -DNDEBUG +Release_CCFLAGS = -O0 -DNDEBUG +Release_CXXFLAGS = -O0 -DNDEBUG Release_LDFLAGS = /debug /pdb:$(BINDIR)/$(NAME).pdb Debug_Valid = yes -Debug_CCFLAGS = -O0 -g -DDEBUG -Debug_CXXFLAGS = -O0 -g -DDEBUG +Debug_CCFLAGS = -O0 -DDEBUG # -D_DEBUG +Debug_CXXFLAGS = -O0 -DDEBUG # -D_DEBUG -D_ITERATOR_DEBUG_LEVEL=0 Debug_LDFLAGS = /debug /pdb:$(BINDIR)/$(NAME).pdb # select a default configuration or validate configuration diff --git a/speech2/build/rules.mk b/speech2/build/rules.mk index 1890832..688452b 100644 --- a/speech2/build/rules.mk +++ b/speech2/build/rules.mk @@ -9,7 +9,7 @@ BUILD_PRODUCT = $(BINDIR)/$(NAME).dll $(BINDIR)/$(NAME).dll: $(BINDIR)/ $(OBJDIR)/ $(OBJS) echo -e "\e[92mLinking DLL $@\e[0m" - $(LD) $(BASE_LDFLAGS_SHARED) $(BASE_LDFLAGS) $($(CONFIG)_LDFLAGS) $(RTLIBS) $(LIBS) $(OBJS) /out:$@ + $(LD) $(BASE_LDFLAGS_SHARED) $(BASE_LDFLAGS) $($(CONFIG)_LDFLAGS) $($(CONFIG)_RTLIBS) $(LIBS) $(OBJS) /out:$@ else ifeq ($(TYPE),exe) BUILD_PRODUCT = $(BINDIR)/$(NAME).exe diff --git a/speech2/src/bindings.cpp b/speech2/src/bindings.cpp index f492cf9..7c217a8 100644 --- a/speech2/src/bindings.cpp +++ b/speech2/src/bindings.cpp @@ -1,17 +1,17 @@ #include #include "speechapi.hpp" -#define SP2_EXPORT __declspec(dllexport) __cdecl +#define SPEECH2_API __declspec(dllexport) WINAPI // Engine type. Sync with C# enum class EngineType : int { ET_SAPI4, ET_SAPI5, ET_DECTALK }; extern "C" { -SP2_EXPORT void* speech2_create_api(EngineType type) { +SPEECH2_API void* speech2_create_api(EngineType type) { ISpeechAPI* api = nullptr; - printf("speech2_create_api(%d)\n", type); + //printf("speech2_create_api(%d)\n", type); switch(type) { case EngineType::ET_SAPI4: @@ -20,6 +20,8 @@ SP2_EXPORT void* speech2_create_api(EngineType type) { default: return nullptr; } + printf("api is %p\n", api); + if(auto hr = api->Initialize(); FAILED(hr)) { delete api; return nullptr; @@ -28,14 +30,14 @@ SP2_EXPORT void* speech2_create_api(EngineType type) { return static_cast(api); } -SP2_EXPORT void speech2_destroy_api(void* engine) { +SPEECH2_API void speech2_destroy_api(void* engine) { if(engine) delete static_cast(engine); } // 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) { auto* api = static_cast(engine); return api->GetVoices().size(); @@ -43,7 +45,7 @@ SP2_EXPORT int speech2_api_get_voiceinfo_count(void* engine) { 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) { auto* api = static_cast(engine); return &api->GetVoices()[index]; diff --git a/speech2/src/dllmain.cpp b/speech2/src/dllmain.cpp index a1db439..51dccf6 100644 --- a/speech2/src/dllmain.cpp +++ b/speech2/src/dllmain.cpp @@ -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. switch(fdwReason) { case DLL_PROCESS_ATTACH: - CoInitialize(nullptr); + //CoInitialize(nullptr); break; case DLL_THREAD_ATTACH: break; @@ -18,7 +18,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if(lpvReserved != nullptr) { break; // do not do cleanup if process termination scenario } - CoUninitialize(); + //CoUninitialize(); break; } return TRUE; diff --git a/speech2/src/sapi4/api_sapi4.cpp b/speech2/src/sapi4/api_sapi4.cpp index b67d7ed..1e48bf5 100644 --- a/speech2/src/sapi4/api_sapi4.cpp +++ b/speech2/src/sapi4/api_sapi4.cpp @@ -6,6 +6,9 @@ #include "sapi4/include/speech.h" #include "speechapi.hpp" +// stupid hacky but Whatevers + + struct SpeechAPI_SAPI4 : public ISpeechAPI { virtual ~SpeechAPI_SAPI4() { printf("~SpeechAPI_SAPI4\n"); @@ -17,7 +20,7 @@ struct SpeechAPI_SAPI4 : public ISpeechAPI { }; HRESULT Initialize() override { - HRESULT hRes; + HRESULT hRes{}; printf("speech2: SpeechAPI_Sapi4::Initalize() begin: %p\n", this); @@ -30,9 +33,13 @@ struct SpeechAPI_SAPI4 : public ISpeechAPI { printf("speech2: SpeechAPI_Sapi4::Initalize() created enum\n"); + + printf("speech2: SpeechAPI_Sapi4::Initalize() starting enumvoices\n"); + // Fill out voices EnumVoices(); + printf("speech2: SpeechAPI_Sapi4::Initalize() end enumvoices\n"); printf("speech2: SpeechAPI_Sapi4::Initalize() end\n"); @@ -40,19 +47,16 @@ struct SpeechAPI_SAPI4 : public ISpeechAPI { } void EnumVoices() { - TTSMODEINFO found{}; - DWORD piss = 0; + static TTSMODEINFO found{}; - - - while(!pEnum->Next(1, &found, &piss)) { - //auto ptr = strdup(found.szModeName); + while(!pEnum->Next(1, &found, nullptr)) { + auto ptr = _strdup(found.szModeName); printf("EnumVoices() voice %s\n", found.szModeName); - //voices.push_back(VoiceInfo { .guid = found.gModeID, .voiceName = ptr }); - - ZeroMemory(&found, sizeof(TTSMODEINFO)); + voices.push_back({found.gModeID, ptr}); } + printf("EnumVoices() end\n"); + pEnum->Reset(); } diff --git a/speech2/src/speechapi.hpp b/speech2/src/speechapi.hpp index 88ed6e7..ab9b811 100644 --- a/speech2/src/speechapi.hpp +++ b/speech2/src/speechapi.hpp @@ -13,6 +13,7 @@ struct ISpeechAPI { //VoiceInfo(VoiceInfo&&) = delete; ~VoiceInfo() { + // Make this a lot less stupid at some point. if(voiceName) free(voiceName); }