summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--GUI/GUI/GUI/Config.cpp2
-rw-r--r--GUI/GUI/GUI/Frame.cpp1
-rw-r--r--GUI/GUI/GUI/Logging.cpp56
-rw-r--r--GUI/GUI/GUI/Logging.h53
-rw-r--r--GUI/GUI/GUI/PythonWrapper.cpp117
-rw-r--r--GUI/GUI/GUI/PythonWrapper.h2
-rw-r--r--GUI/GUI/GUI/WhisperCPP.cpp159
-rw-r--r--GUI/GUI/GUI/WhisperCPP.h22
-rw-r--r--GUI/Libraries/.gitignore2
-rw-r--r--GUI/Libraries/fetch.ps131
-rw-r--r--GUI/README.md2
11 files changed, 251 insertions, 196 deletions
diff --git a/GUI/GUI/GUI/Config.cpp b/GUI/GUI/GUI/Config.cpp
index 50f0dca..a877d4a 100644
--- a/GUI/GUI/GUI/Config.cpp
+++ b/GUI/GUI/GUI/Config.cpp
@@ -78,7 +78,7 @@ AppConfig::AppConfig()
use_cpu(false),
use_builtin(false),
- chars_per_sync(20),
+ chars_per_sync(8),
bytes_per_char(1),
rows(4),
cols(48),
diff --git a/GUI/GUI/GUI/Frame.cpp b/GUI/GUI/GUI/Frame.cpp
index 5332490..0bac3aa 100644
--- a/GUI/GUI/GUI/Frame.cpp
+++ b/GUI/GUI/GUI/Frame.cpp
@@ -1991,6 +1991,7 @@ void Frame::OnWhisperStop(wxCommandEvent& event) {
void Frame::OnAppDrain(wxTimerEvent& event) {
DrainAsyncOutput(py_app_, transcribe_out_);
DrainAsyncOutput(env_proc_, transcribe_out_);
+ Logging::kThreadLogger.Drain();
}
void Frame::LoadAndSetIcons() {
diff --git a/GUI/GUI/GUI/Logging.cpp b/GUI/GUI/GUI/Logging.cpp
index 78594b4..f799e31 100644
--- a/GUI/GUI/GUI/Logging.cpp
+++ b/GUI/GUI/GUI/Logging.cpp
@@ -1,8 +1,48 @@
#include "Logging.h"
+#include <wx/wxprec.h>
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/process.h>
+#include <wx/txtstrm.h>
+
+#include <fstream>
#include <regex>
#include <string>
+Logging::ThreadLogger Logging::kThreadLogger = Logging::ThreadLogger();
+
+Logging::ThreadLogger::ThreadLogger() {}
+
+void Logging::ThreadLogger::Append(wxTextCtrl* frame, const std::string&& message)
+{
+ std::scoped_lock l(mu_);
+ auto entry = messages_.find(frame);
+ if (entry == messages_.end()) {
+ messages_[frame] = { std::move(message) };
+ }
+ else {
+ messages_[frame].push_back(message);
+ }
+}
+
+void Logging::ThreadLogger::Drain()
+{
+ std::scoped_lock l(mu_);
+ std::ofstream log_ofs("Resources/log.txt", std::ios_base::app);
+ for (const auto& [frame, messages] : messages_) {
+ for (const auto& message : messages) {
+ frame->AppendText(message);
+ log_ofs << message;
+ }
+ }
+ log_ofs.close();
+ messages_.clear();
+}
+
std::string Logging::HidePII(const std::string&& str,
const std::string& replacement) {
try {
@@ -16,3 +56,19 @@ std::string Logging::HidePII(const std::string&& str,
wxLogFatalError("Unhandled regex error (HidePII)");
return ""; // Compiler thinks we can get here (we can't) and prints a warning.
}
+
+void Logging::DrainAsyncOutput(wxProcess* proc, wxTextCtrl* frame) {
+ if (!proc) {
+ return;
+ }
+
+ while (proc->IsInputAvailable()) {
+ wxTextInputStream iss(*(proc->GetInputStream()));
+ Log(frame, " {}\n", iss.ReadLine());
+ }
+
+ while (proc->IsErrorAvailable()) {
+ wxTextInputStream iss(*(proc->GetErrorStream()));
+ Log(frame, " {}\n", iss.ReadLine());
+ }
+}
diff --git a/GUI/GUI/GUI/Logging.h b/GUI/GUI/GUI/Logging.h
index 99462c0..c85a376 100644
--- a/GUI/GUI/GUI/Logging.h
+++ b/GUI/GUI/GUI/Logging.h
@@ -16,30 +16,23 @@
#include <string_view>
namespace Logging {
+ // Remove personally identifying information (PII) from str.
+ //
+ // For example, this translates "C:/Users/foo/Desktop" to "C:/Users/*****/Desktop".
+ std::string HidePII(const std::string&& str, const std::string& replacement = "*****");
-#if 0
- class Log {
+ class ThreadLogger {
public:
- static Log& Get() {
- static Log l;
- return l;
- }
-
- bool Write(const std::string& text);
+ ThreadLogger();
+ void Append(wxTextCtrl* frame, const std::string&& message);
+ void Drain();
private:
- Log() {}
-
- bool Open(const std::string& path);
-
- int fd_;
+ std::mutex mu_;
+ std::unordered_map<wxTextCtrl*, std::list<std::string>> messages_;
};
-#endif
- // Remove personally identifying information (PII) from str.
- //
- // For example, this translates "C:/Users/foo/Desktop" to "C:/Users/*****/Desktop".
- std::string HidePII(const std::string&& str, const std::string& replacement = "*****");
+ extern ThreadLogger kThreadLogger;
// Provides a simple Python format()-like interface to wxTextCtrl.
// Ex: Log(my_textctrl_, "{}\n", "Hello, world!");
@@ -47,28 +40,10 @@ namespace Logging {
void Log(wxTextCtrl* frame, std::string_view format, Args&&... args) {
const std::string raw = std::vformat(format, std::make_format_args(args...));
const std::string masked = HidePII(std::move(raw));
- frame->AppendText(masked);
- // Limit log to 10 MB to avoid runaway memory usage.
- const int max_frame_len_bytes = 10 * 1000 * 1000;
- if (frame->GetLastPosition() > max_frame_len_bytes) {
- frame->Remove(0, frame->GetLastPosition() - max_frame_len_bytes);
- }
- }
-
- inline void DrainAsyncOutput(wxProcess* proc, wxTextCtrl* frame) {
- if (!proc) {
- return;
- }
- while (proc->IsInputAvailable()) {
- wxTextInputStream iss(*(proc->GetInputStream()));
- Log(frame, " {}\n", iss.ReadLine());
- }
-
- while (proc->IsErrorAvailable()) {
- wxTextInputStream iss(*(proc->GetErrorStream()));
- Log(frame, " {}\n", iss.ReadLine());
- }
+ kThreadLogger.Append(frame, std::move(masked));
}
+
+ void DrainAsyncOutput(wxProcess* proc, wxTextCtrl* frame);
}
diff --git a/GUI/GUI/GUI/PythonWrapper.cpp b/GUI/GUI/GUI/PythonWrapper.cpp
index bcb7b1d..c90520d 100644
--- a/GUI/GUI/GUI/PythonWrapper.cpp
+++ b/GUI/GUI/GUI/PythonWrapper.cpp
@@ -1,10 +1,12 @@
#include "Logging.h"
#include "PythonWrapper.h"
+#include "ScopeGuard.h"
#include "Util.h"
#include "Config.h"
#include <stdio.h>
+#include <Windows.h>
#include <filesystem>
#include <fstream>
@@ -60,58 +62,95 @@ bool PythonWrapper::InvokeCommandWithArgs(
cmd_oss << " " << arg;
}
- wxString path;
- if (!wxGetEnv("PATH", &path)) {
- *py_stderr = "Failed to get PATH";
- return false;
- }
- if (!wxSetEnv("PATH", path + ";Resources/PortableGit/bin")) {
- *py_stderr = "Failed to append to PATH";
+ HANDLE stdout_read{};
+ HANDLE stdout_write{};
+ SECURITY_ATTRIBUTES sec_attr{};
+ sec_attr.nLength = sizeof(sec_attr);
+ sec_attr.bInheritHandle = TRUE;
+ if (!CreatePipe(&stdout_read, &stdout_write, &sec_attr, 0)) {
+ if (py_stderr) {
+ std::ostringstream err_oss;
+ err_oss << "Error while executing python command \"" << cmd_oss.str()
+ << "\": Failed to create stdout pipe" << std::endl;
+ *py_stderr = err_oss.str();
+ }
return false;
}
+ ScopeGuard stdout_cleanup([&]() {
+ CloseHandle(stdout_read);
+ CloseHandle(stdout_write);
+ });
- wxArrayString cmd_stdout;
- wxArrayString cmd_stderr;
- long result = wxExecute(cmd_oss.str(), cmd_stdout, cmd_stderr, /*flags=*/0);
- std::ostringstream cmd_stdout_oss;
- for (const auto& line : cmd_stdout) {
- if (!cmd_stdout_oss.str().empty()) {
- cmd_stdout_oss << std::endl;
- }
- cmd_stdout_oss << line;
- }
- std::ostringstream cmd_stderr_oss;
- for (const auto& line : cmd_stderr) {
- if (!cmd_stderr_oss.str().empty()) {
- cmd_stderr_oss << std::endl;
- }
- cmd_stderr_oss << line;
- }
- if (result == -1) {
- std::ostringstream err_oss;
- err_oss << "Error while executing python command \"" << cmd_oss.str() << "\": Failed to launch process" << std::endl;
- err_oss << cmd_stdout_oss.str() << std::endl;
- err_oss << cmd_stderr_oss.str() << std::endl;
+ HANDLE stderr_read{};
+ HANDLE stderr_write{};
+ if (!CreatePipe(&stderr_read, &stderr_write, &sec_attr, 0)) {
if (py_stderr) {
+ std::ostringstream err_oss;
+ err_oss << "Error while executing python command \"" << cmd_oss.str()
+ << "\": Failed to create stderr pipe" << std::endl;
*py_stderr = err_oss.str();
}
return false;
- } else if (result) {
+ }
+ ScopeGuard stderr_cleanup([&]() {
+ CloseHandle(stderr_read);
+ CloseHandle(stderr_write);
+ });
+
+ STARTUPINFOA si{};
+ si.cb = sizeof(si);
+ si.hStdOutput = stdout_write;
+ si.hStdError = stderr_write;
+ PROCESS_INFORMATION pi{};
+ std::string path = "Resources/PortableGit/bin";
+ std::string env = "PATH=" + path;
+ //std::string env;
+
+ //std::string tmp_cmd = "Get-ChildItem";
+
+ std::string cmd_str = cmd_oss.str();
+ if (!CreateProcessA(NULL, // application name
+ cmd_str.data(),
+ //tmp_cmd.data(),
+ NULL, // process attributes
+ NULL, // thread attributes
+ FALSE, // whether to inherit parent's handles
+ 0, // creation flags
+ env.data(),
+ NULL, // current directory (use parent's)
+ &si,
+ &pi)) {
if (py_stderr) {
std::ostringstream err_oss;
- err_oss << "Error while executing python command \"" << cmd_oss.str() <<
- "\"" << std::endl <<
- "Process returned " << result << ": " << std::endl <<
- cmd_stdout_oss.str() << std::endl <<
- cmd_stderr_oss.str() << std::endl;
+ err_oss << "Error while executing python command \"" << cmd_oss.str()
+ << "\": Failed to launch process" << std::endl;
*py_stderr = err_oss.str();
}
return false;
}
+ ScopeGuard pi_cleanup([&] {
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ });
+
+ std::ostringstream stdout_oss, stderr_oss;
+ std::vector<char> buf(4096, 0);
+ DWORD bytes_read = 0;
+ while (ReadFile(si.hStdOutput, buf.data(), buf.size(), &bytes_read, NULL) && bytes_read > 0) {
+ stdout_oss << std::string(buf.data(), bytes_read);
+ }
+ bytes_read = 0;
+ while (ReadFile(si.hStdError, buf.data(), buf.size(), &bytes_read, NULL) && bytes_read > 0) {
+ stderr_oss << std::string(buf.data(), bytes_read);
+ }
+
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ // TODO(yum) retrieve exit code
- *py_stdout = cmd_stdout_oss.str();
+ *py_stdout = stdout_oss.str();
if (py_stderr) {
- *py_stderr = cmd_stderr_oss.str();
+ *py_stderr = stderr_oss.str();
}
return true;
}
@@ -165,7 +204,7 @@ std::string PythonWrapper::DumpMics() {
return py_stdout;
}
-bool PythonWrapper::InstallPip(std::string* out) {
+bool PythonWrapper::InstallPip(std::string* out, std::string* err) {
std::string result;
std::filesystem::path pip_flag = "Resources/Python/.pip_installed";
@@ -174,7 +213,7 @@ bool PythonWrapper::InstallPip(std::string* out) {
}
std::string pip_path = "Resources/Python/get-pip.py";
- if (!InvokeWithArgs({ pip_path }, out)) {
+ if (!InvokeWithArgs({ pip_path }, out, err)) {
return false;
}
diff --git a/GUI/GUI/GUI/PythonWrapper.h b/GUI/GUI/GUI/PythonWrapper.h
index 05de538..3433b0f 100644
--- a/GUI/GUI/GUI/PythonWrapper.h
+++ b/GUI/GUI/GUI/PythonWrapper.h
@@ -47,7 +47,7 @@ namespace PythonWrapper
std::string DumpMics();
// Execute get-pip.py.
- bool InstallPip(std::string* out);
+ bool InstallPip(std::string* out, std::string* err = nullptr);
// TODO(yum) both StartApp and GenerateAnimator should be
// parameterized with config files instead of these ever-growing lists of
diff --git a/GUI/GUI/GUI/WhisperCPP.cpp b/GUI/GUI/GUI/WhisperCPP.cpp
index 809415e..362bad0 100644
--- a/GUI/GUI/GUI/WhisperCPP.cpp
+++ b/GUI/GUI/GUI/WhisperCPP.cpp
@@ -14,6 +14,7 @@
#include <codecvt>
#include <cwchar>
#include <fstream>
+#include <future>
#include <locale>
#include <string>
#include <vector>
@@ -60,9 +61,11 @@ namespace {
};
WhisperCPP::WhisperCPP(wxTextCtrl* out)
- : out_(out), f_(nullptr), did_init_(false), proc_(nullptr), run_(false)
+ : out_(out), f_(nullptr), did_init_(false), proc_(), run_(false)
{
- Log(out_, "Setting concurrency to 2: {}\n", wxThread::SetConcurrency(2));
+ auto p = std::promise<void>();
+ proc_ = p.get_future();
+ p.set_value();
}
WhisperCPP::~WhisperCPP() {
@@ -135,32 +138,26 @@ bool WhisperCPP::OpenMic(const int idx, Whisper::iAudioCapture*& stream) {
return true;
}
-bool WhisperCPP::InstallDependencies(wxProcess*& proc) {
+bool WhisperCPP::InstallDependencies() {
std::filesystem::path flag_file = "Resources/.whisper_deps_installed";
flag_file = flag_file.lexically_normal();
if (std::filesystem::exists(flag_file)) {
- proc = nullptr;
return true;
}
- auto cb = [&](wxProcess* proc, int ret) -> void {
- Log(out_, "Dependency installation exited with code {}\n", ret);
- if (ret == 0) {
- Log(out_, "Dependency installation finished\n");
- }
- DrainAsyncOutput(proc, out_);
- return;
- };
-
- proc = PythonWrapper::InvokeAsyncWithArgs({
+ std::string py_stdout, py_stderr;
+ bool ret = PythonWrapper::InvokeWithArgs({
"-u", // Unbuffered output
"-m pip",
"install",
"-r Resources/Scripts/whisper_requirements.txt",
- }, std::move(cb));
- if (!proc) {
- Log(out_, "Failed to launch installation thread!\n");
+ }, &py_stdout, &py_stderr);
+
+ Log(out_, py_stdout);
+ Log(out_, py_stderr);
+ if (!ret) {
+ Log(out_, "Failed to install dependencies!\n");
return false;
}
@@ -172,30 +169,25 @@ bool WhisperCPP::InstallDependencies(wxProcess*& proc) {
}
bool WhisperCPP::DownloadModel(const std::string& model_name,
- const std::filesystem::path& fs_path, wxProcess*& proc) {
- auto cb = [&](wxProcess* proc, int ret) -> void {
- Log(out_, "Model download completed with code {}\n", ret);
- if (ret == 0) {
- Log(out_, "Model download finished\n");
- }
- DrainAsyncOutput(proc, out_);
- return;
- };
-
+ const std::filesystem::path& fs_path) {
std::ostringstream url_oss;
url_oss << "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/";
url_oss << model_name;
Log(out_, "Model will be saved to {}\n", fs_path.lexically_normal().string());
- proc = PythonWrapper::InvokeAsyncWithArgs({
+ std::string py_stdout, py_stderr;
+ bool ret = PythonWrapper::InvokeWithArgs({
"-u", // Unbuffered output
"-m wget",
url_oss.str(),
"-o", fs_path.string(),
- }, std::move(cb));
- if (!proc) {
- Log(out_, "Failed to launch download thread!\n");
+ }, &py_stdout, &py_stderr);
+ Log(out_, py_stdout);
+ Log(out_, py_stderr);
+ if (!ret) {
+ Log(out_, "Failed to download model!\n");
return false;
}
+
return true;
}
@@ -229,29 +221,13 @@ bool WhisperCPP::CreateContext(Whisper::iModel* model, Whisper::iContext*& conte
return true;
}
-WhisperCPP::AppThread::AppThread(
- const std::function<void(AppThread* thd)>&& cb,
- WhisperCPP* app)
- : wxThread(wxTHREAD_DETACHED), cb_(cb), app_(app)
-{}
-WhisperCPP::AppThread::~AppThread()
-{
- Log(app_->out_, "Destroy transcription thread\n");
- app_->proc_ = nullptr;
-}
-
-void* WhisperCPP::AppThread::Entry() {
- cb_(this);
- return nullptr;
-}
-
void WhisperCPP::Start(const AppConfig& c) {
- if (proc_) {
+ if (!proc_.valid()) {
Log(out_, "Transcription engine already running\n");
return;
}
- proc_ = new AppThread([&](AppThread* thd) {
+ proc_ = std::async(std::launch::async, [&]() -> void {
Log(out_, "Transcription thread top\n");
run_ = true;
@@ -261,28 +237,17 @@ void WhisperCPP::Start(const AppConfig& c) {
}
ScopeGuard mic_stream_cleanup([mic_stream]() { mic_stream->Release(); });
- {
- std::string output;
- Log(out_, "Installing pip\n");
- if (!PythonWrapper::InstallPip(&output)) {
- Log(out_, "Failed to install pip: {}\n", output);
- }
+ std::string pip_out, pip_err;
+ Log(out_, "Installing pip\n");
+ if (!PythonWrapper::InstallPip(&pip_out, &pip_err)) {
+ Log(out_, "Failed to install pip: {}\n", pip_err);
+ return;
}
-
- {
- Log(out_, "Installing Python dependencies\n");
- wxProcess* proc = nullptr;
- if (!InstallDependencies(proc)) {
- return;
- }
- while (proc && proc->Exists(proc->GetPid())) {
- if (!run_ || thd->TestDestroy()) {
- proc->Kill(proc->GetPid(), wxSIGKILL);
- return;
- }
- wxThread::Sleep(100);
- }
+ Log(out_, "Installing Python dependencies\n");
+ if (!InstallDependencies()) {
+ return;
}
+#if 1
std::filesystem::path model_path = "Resources/Models";
model_path /= c.whisper_model;
@@ -291,19 +256,9 @@ void WhisperCPP::Start(const AppConfig& c) {
}
else {
Log(out_, "Downloading model {}\n", c.whisper_model);
- wxProcess* proc = nullptr;
- model_path = model_path.lexically_normal();
- if (!DownloadModel(c.whisper_model, model_path, proc)) {
+ if (!DownloadModel(c.whisper_model, model_path)) {
return;
}
- while (proc->Exists(proc->GetPid())) {
- if (!run_ || thd->TestDestroy()) {
- proc->Kill(proc->GetPid(), wxSIGKILL);
- std::filesystem::remove(model_path);
- return;
- }
- wxThread::Sleep(100);
- }
}
Whisper::iModel* model;
@@ -349,22 +304,25 @@ void WhisperCPP::Start(const AppConfig& c) {
bool is_metadata = false;
for (int j = 0; j < seg.countTokens; j++) {
const sToken& tok = tokens[seg.firstToken + j];
- if (tok.text[0] == '[') {
- continue;
- }
- if (tok.text[0] == ' ' && (
- tok.text[1] == '[' ||
- tok.text[1] == '(')) {
- if (tok.text[strlen(tok.text) - 1] == ']') {
+ std::string_view tok_str(tok.text);
+ if (tok_str.starts_with("[") ||
+ tok_str.starts_with(" [") ||
+ tok_str.starts_with(" (")) {
+ if (tok_str.ends_with("]") ||
+ tok_str.ends_with(")")) {
continue;
}
is_metadata = true;
continue;
}
- if (is_metadata && (
- tok.text[strlen(tok.text) - 1] == ']' ||
- tok.text[strlen(tok.text) - 1] == ')')) {
- is_metadata = false;
+ if (is_metadata) {
+ if (tok_str.ends_with("]") ||
+ tok_str.ends_with(")")) {
+ is_metadata = false;
+ }
+ continue;
+ }
+ if (tok_str.ends_with("BLANK_AUDIO")) {
continue;
}
Log(out, "{}", tok.text);
@@ -379,9 +337,10 @@ void WhisperCPP::Start(const AppConfig& c) {
wparams.new_segment_callback_user_data = out_;
sCaptureCallbacks callbacks{};
+
callbacks.shouldCancel = [](void* pv) noexcept -> HRESULT __stdcall {
WhisperCPP* app = static_cast<WhisperCPP*>(pv);
- if (app->proc_->TestDestroy() || !app->run_) {
+ if (!app->run_) {
Log(app->out_, "Exit transcription loop\n");
return S_FALSE;
}
@@ -391,7 +350,6 @@ void WhisperCPP::Start(const AppConfig& c) {
if (++i % 20 == 0) {
Log(app->out_, "Spin {}\n", i);
}
- wxThread::Sleep(10);
return S_OK;
};
callbacks.pv = this;
@@ -402,11 +360,18 @@ void WhisperCPP::Start(const AppConfig& c) {
Log(out_, "Capture failed: {}\n", hresultToString(err));
return;
}
+#else
+ while (run_) {
+ static int i = 0;
+ if (++i % 100 == 0) {
+ Log(out_, "Spin {}\n", i);
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+#endif
Log(out_, "Exit transcription engine\n");
- }, this);
-
- proc_->Run();
+ });
Log(out_, "Success!\n");
return;
@@ -415,6 +380,8 @@ void WhisperCPP::Start(const AppConfig& c) {
void WhisperCPP::Stop() {
Log(out_, "Stopping transcription engine...\n");
run_ = false;
+ proc_.wait();
+ Log(out_, "Done!\n");
}
bool WhisperCPP::GetMicsImpl(std::vector<sCaptureDevice>& mics) {
diff --git a/GUI/GUI/GUI/WhisperCPP.h b/GUI/GUI/GUI/WhisperCPP.h
index 20b0106..ed934be 100644
--- a/GUI/GUI/GUI/WhisperCPP.h
+++ b/GUI/GUI/GUI/WhisperCPP.h
@@ -2,8 +2,6 @@
#include <wx/filepicker.h>
#include <wx/wxprec.h>
-#include <wx/process.h>
-#include <wx/thread.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
@@ -19,6 +17,7 @@
#include <filesystem>
#include <functional>
+#include <future>
#include <string>
#include <vector>
@@ -30,9 +29,9 @@ public:
bool Init();
bool GetMics(std::vector<std::string>& mics);
bool OpenMic(const int idx, Whisper::iAudioCapture*& stream);
- bool InstallDependencies(wxProcess*& proc);
+ bool InstallDependencies();
bool DownloadModel(const std::string& model_name,
- const std::filesystem::path& fs_path, wxProcess*& proc);
+ const std::filesystem::path& fs_path);
bool LoadModel(const std::string& path, Whisper::iModel*& model);
bool CreateContext(Whisper::iModel* model, Whisper::iContext*& context);
@@ -42,22 +41,9 @@ public:
private:
bool GetMicsImpl(std::vector<Whisper::sCaptureDevice>& mics);
- class AppThread : public wxThread {
- public:
- AppThread(const std::function<void(AppThread* thd)>&& cb, WhisperCPP* app);
-
- virtual ~AppThread();
-
- virtual void* Entry() wxOVERRIDE;
-
- private:
- const std::function<void(AppThread* thd)> cb_;
- WhisperCPP* app_;
- };
-
wxTextCtrl* out_;
Whisper::iMediaFoundation* f_;
bool did_init_;
- AppThread* volatile proc_;
+ std::future<void> proc_;
volatile bool run_;
};
diff --git a/GUI/Libraries/.gitignore b/GUI/Libraries/.gitignore
index 0e14a69..26be5d9 100644
--- a/GUI/Libraries/.gitignore
+++ b/GUI/Libraries/.gitignore
@@ -2,4 +2,4 @@
wx
rapidyaml
whisper
-
+oatpp
diff --git a/GUI/Libraries/fetch.ps1 b/GUI/Libraries/fetch.ps1
index f13bad5..218d48b 100644
--- a/GUI/Libraries/fetch.ps1
+++ b/GUI/Libraries/fetch.ps1
@@ -12,6 +12,15 @@ $WHISPER_1_7_0_URL = "https://github.com/Const-me/Whisper/releases/download/1.7.
$WHISPER_URL = $WHISPER_1_7_0_URL
$WHISPER_FILE = $(Split-Path -Path $WHISPER_URL -Leaf)
+$OATPP_1_3_0_URL = "https://github.com/oatpp/oatpp/archive/refs/tags/1.3.0.zip"
+$OATPP_URL = $OATPP_1_3_0_URL
+$OATPP_FILE = $(Split-Path -Path $OATPP_URL -Leaf)
+$OATPP_VER = $OATPP_FILE -replace '\.[a-z\.]*$'
+$OATPP_DIR = "oatpp-$OATPP_VER"
+
+$NPROC = $(Get-CimInstance Win32_Processor).NumberOfCores
+echo "nproc: $NPROC"
+
pushd $PSScriptRoot
# WX
@@ -61,6 +70,28 @@ if (-Not (Test-Path whisper)) {
popd > $null
}
+if ((Test-Path oatpp) -And ($overwrite)) {
+ rm -Recurse oatpp
+}
+
+if (-Not (Test-Path oatpp)) {
+ mkdir oatpp
+ pushd oatpp > $null
+ Invoke-WebRequest $OATPP_URL -OutFile $OATPP_FILE
+ Expand-Archive $OATPP_FILE -DestinationPath .
+ if (Test-Path ../../GUI/GUI/oatpp/) {
+ rm -Recurse ../../GUI/GUI/oatpp/
+ }
+ mkdir ../../GUI/GUI/oatpp/
+ pushd $OATPP_DIR > $null
+ mkdir build
+ pushd build > $null
+ cmake.exe .. -DCMAKE_BUILD_TYPE=Release -DOATPP_BUILD_TESTS=OFF
+ cmake.exe --build . -j $NPROC --config Release
+ popd > $null
+ popd > $null
+}
+
popd > $null # rapidyaml
popd > $null # $PSScriptRoot
diff --git a/GUI/README.md b/GUI/README.md
index d2fa999..ea28124 100644
--- a/GUI/README.md
+++ b/GUI/README.md
@@ -1,6 +1,6 @@
## Build instructions
-0. Install build dependencies: git, python3, Visual Studio 2022
+0. Install build dependencies: cmake, git, python3, Visual Studio 2022
1. Open Powershell.
2. Make sure you've downloaded submodules:
```