Skip to content
Snippets Groups Projects
Commit 6c84d43d authored by Matus Novak's avatar Matus Novak
Browse files

Added decoder-gui

parent 2f95d28c
No related branches found
No related tags found
No related merge requests found
Pipeline #9681 failed
#ifndef REW_COMMON_DIRECTORY_SINK_H
#define REW_COMMON_DIRECTORY_SINK_H
#include <fstream>
#include "named_raw_file.h"
#include "input.h"
REW_NAMESPACE {
class DirectorySink: public rew::Input<rew::NamedRawFile> {
public:
DirectorySink(const std::string& destination):destination(destination) {
}
virtual ~DirectorySink() = default;
void process(const rew::NamedRawFile* data, const size_t length) override {
for (size_t i = 0; i < length; i++) {
const auto& namedFile = data[i];
auto terminator = namedFile.length;
for (size_t i = 0; i < namedFile.length; i++) {
if (namedFile.data[i] == '\0') {
terminator = i;
break;
}
}
if (terminator != namedFile.length) {
const auto sptr = reinterpret_cast<const char*>(namedFile.data.get());
const auto name = std::string(sptr, terminator);
const auto contents = reinterpret_cast<const char*>(namedFile.data.get() + terminator + 1);
const auto total = namedFile.length - terminator - 1;
std::string path = destination + DELIMITER + name;
std::cout << "Writing file: " << path << " of size: " << total << " bytes!" << std::endl;
std::fstream file(path, std::ios::out | std::ios::binary);
if (!file) {
std::cerr << "Failed to open file: " << path << " for writing!" << std::endl;
}
else {
file.write(contents, total);
}
}
else {
std::cerr << "File index: " << namedFile.index << " successfully inflated but contains bad filename!" << std::endl;
}
}
}
private:
std::string destination;
};
}
#endif
report/images/decoder-gui.png

29.6 KiB

......@@ -15,10 +15,11 @@
#include <thread>
#include <future>
#include <rew/decoder/decoder.h>
#include <rew/common/named_raw_file.h>
#include <rew/common/directory_sink.h>
#include <rew/decoder/physical_audio_source.h>
#include <rew/decoder/tcp_http_server.h>
///=====================================================================================================================
std::string getFullPath(const std::string& path) {
#ifdef _WIN32
......@@ -89,53 +90,6 @@ argagg::parser argparser{ {
}
} };
///=====================================================================================================================
class CustomSink: public rew::Input<rew::NamedRawFile> {
public:
CustomSink(const std::string& destination):destination(destination) {
}
virtual ~CustomSink() = default;
void process(const rew::NamedRawFile* data, const size_t length) override {
for (size_t i = 0; i < length; i++) {
const auto& namedFile = data[i];
auto terminator = namedFile.length;
for (size_t i = 0; i < namedFile.length; i++) {
if (namedFile.data[i] == '\0') {
terminator = i;
break;
}
}
if (terminator != namedFile.length) {
const auto sptr = reinterpret_cast<const char*>(namedFile.data.get());
const auto name = std::string(sptr, terminator);
const auto contents = reinterpret_cast<const char*>(namedFile.data.get() + terminator + 1);
const auto total = namedFile.length - terminator - 1;
std::string path = destination + DELIMITER + name;
std::cout << "Writing file: " << path << " of size: " << total << " bytes!" << std::endl;
std::fstream file(path, std::ios::out | std::ios::binary);
if (!file) {
std::cerr << "Failed to open file: " << path << " for writing!" << std::endl;
}
else {
file.write(contents, total);
}
}
else {
std::cerr << "File index: " << namedFile.index << " successfully inflated but contains bad filename!" << std::endl;
}
}
}
private:
std::string destination;
};
///=====================================================================================================================
int main (const int argc, char* argv[]) {
static bool terminate = false;
......@@ -185,7 +139,7 @@ int main (const int argc, char* argv[]) {
if (!folderIsValid(outputPath))
throw std::runtime_error("Output path: \"" + outputPath + "\" is not a folder!");
sink = std::make_shared<CustomSink>(outputPath);
sink = std::make_shared<rew::DirectorySink>(outputPath);
}
else if (args["serve"]) {
......
......@@ -13,11 +13,11 @@
#include <iostream>
#include <thread>
#include <future>
#include <functional>
#include <rew/decoder/decoder.h>
#include <rew/common/named_raw_file.h>
#include <rew/common/directory_sink.h>
#include <rew/decoder/physical_audio_source.h>
#include "rew/encoder/audio_sink.h"
#include "rew/encoder/wav_writer.h"
#include <rew/decoder/tcp_http_server.h>
#ifdef _MSC_VER
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
......@@ -127,6 +127,386 @@ private:
std::string destination;
};
///=====================================================================================================================
static int onClosing(uiWindow *w, void *data) {
uiQuit();
return 1;
}
///=====================================================================================================================
static int onShouldQuit(void *data) {
uiWindow *mainwin = uiWindow(data);
uiControlDestroy(uiControl(mainwin));
return 1;
}
///=====================================================================================================================
class Context;
static struct Globals {
std::shared_ptr<Context> context;
bool sourceDevice = false;
bool sourceFile = false;
bool destinationFile = false;
bool destinationServe = false;
std::string sourceFileStr;
std::string destinationFileStr;
} globals;
///=====================================================================================================================
class Context: public std::enable_shared_from_this<Context> {
public:
Context(Globals& globals, const std::function<void()>& callback)
: globals(globals),
callback(callback) {
if (globals.destinationFile) {
std::cout << "destination: " << globals.destinationFileStr << std::endl;
const auto outputPath = getFullPath(globals.destinationFileStr);
if (!pathIsValid(outputPath))
throw std::runtime_error("Output path: \"" + outputPath + "\" does not exist!");
if (!folderIsValid(outputPath))
throw std::runtime_error("Output path: \"" + outputPath + "\" is not a folder!");
sink = std::make_shared<rew::DirectorySink>(outputPath);
}
else if (globals.destinationServe) {
std::cout << "Starting server" << std::endl;
server = std::make_shared<rew::TcpHttpServer>("localhost", 8080);
sink = server;
server->start();
}
else {
throw std::runtime_error("Please select a destination");
}
if (globals.sourceFile) {
std::cout << "source: " << globals.sourceFileStr << std::endl;
const auto inputPath = getFullPath(globals.sourceFileStr);
if (!pathIsValid(inputPath))
throw std::runtime_error("Input file: \"" + inputPath + "\" does not exist!");
auto wav = std::make_shared<rew::WavReader>();
auto source = std::make_shared<rew::AudioSource>(wav);
decoder = std::make_shared<rew::Decoder>(source, sink, DEFAULT_LOW_TONE_FREQ, DEFAULT_HIGH_TONE_FREQ, DEFAULT_SAMPLE_LENGTH_MS);
thread = std::thread([=]() -> void {
source->open(inputPath);
source->process();
source->close();
if (this->callback && !this->server) {
this->stopped = true;
this->callback();
}
});
}
else if (globals.sourceDevice) {
audio = std::make_shared<rew::PhysicalAudioSource>();
decoder = std::make_shared<rew::Decoder>(audio, sink, DEFAULT_LOW_TONE_FREQ, DEFAULT_HIGH_TONE_FREQ, DEFAULT_SAMPLE_LENGTH_MS);
thread = std::thread([=]() -> void {
audio->start();
audio->process();
if (this->callback && !this->server) {
this->stopped = true;
this->callback();
}
});
}
else {
throw std::runtime_error("Please select a source");
}
}
~Context() {
stop();
}
void stop() {
if (thread.joinable()) {
if (server) server->stop();
if (audio) audio->close();
thread.join();
}
}
inline bool isStopped() const {
return stopped;
}
private:
Globals& globals;
std::shared_ptr<rew::Input<rew::NamedRawFile>> sink;
std::shared_ptr<rew::PhysicalAudioSource> audio;
std::shared_ptr<rew::TcpHttpServer> server;
std::shared_ptr<rew::Decoder> decoder;
std::thread thread;
std::function<void()> callback;
bool stopped = false;
};
///=====================================================================================================================
static void widgetsSelectSource(uiWindow* mainwin, uiBox* box) {
const auto group = uiNewGroup("Select source");
uiGroupSetMargined(group, 1);
uiBoxAppend(box, uiControl(group), 0);
uiBoxAppend(box, uiControl(uiNewHorizontalSeparator()), 0);
const auto cboxDevice = uiNewCheckbox("From audio input device");
const auto cboxFile = uiNewCheckbox("From audio file");
static struct CBoxData {
Globals& globals;
uiCheckbox* device;
uiCheckbox* file;
} cboxData{globals, cboxDevice, cboxFile};
uiBoxAppend(box, uiControl(cboxDevice), 0);
uiCheckboxOnToggled(cboxDevice, [](uiCheckbox* cbox, void* data) -> void {
auto& d = *reinterpret_cast<CBoxData*>(data);
d.globals.sourceDevice = uiCheckboxChecked(cbox);
uiCheckboxSetChecked(d.file, !d.globals.sourceDevice);
}, &cboxData);
const auto combo = uiNewCombobox();
const auto devices = rew::PhysicalAudioSource::getDevices();
for (const auto& device : devices) {
if (device.inputChannels == 0) continue;
uiComboboxAppend(combo, device.name.c_str());
}
uiBoxAppend(box, uiControl(combo), 0);
uiComboboxOnSelected(combo, [](uiCombobox* combo, void* data) -> void {
auto& d = *reinterpret_cast<CBoxData*>(data);
d.globals.sourceDevice = true;
uiCheckboxSetChecked(d.device, d.globals.sourceDevice);
uiCheckboxSetChecked(d.file, !d.globals.sourceDevice);
}, &cboxData);
uiBoxAppend(box, uiControl(cboxFile), 0);
uiCheckboxOnToggled(cboxFile, [](uiCheckbox* cbox, void* data) -> void {
auto& d = *reinterpret_cast<CBoxData*>(data);
d.globals.sourceFile = uiCheckboxChecked(cbox);
uiCheckboxSetChecked(d.device, !d.globals.sourceFile);
}, &cboxData);
const auto grid = uiNewGrid();
uiGridSetPadded(grid, 1);
uiBoxAppend(box, uiControl(grid), 0);
const auto fileButton = uiNewButton("Select Folder");
const auto fileEntry = uiNewEntry();
static struct SelectFileData {
uiWindow* mainwin;
Globals& globals;
uiCheckbox* device;
uiCheckbox* file;
uiEntry* entry;
} selectFileData{mainwin, globals, cboxDevice, cboxFile, fileEntry};
const auto onOpenFileClicked = [](uiButton *b, void *data) -> void {
auto& d = *reinterpret_cast<SelectFileData*>(data);
const auto filename = uiOpenFile(d.mainwin);
if (filename == NULL) {
uiEntrySetText(d.entry, "");
return;
}
if (!pathIsValid(filename)) {
uiMsgBoxError(d.mainwin,
"Select file error",
"You must select a valid file!");
uiEntrySetText(d.entry, "");
return;
}
uiEntrySetText(d.entry, filename);
d.globals.sourceFileStr = std::string(filename);
uiFreeText(filename);
d.globals.sourceFile = true;
uiCheckboxSetChecked(d.device, !d.globals.sourceFile);
uiCheckboxSetChecked(d.file, d.globals.sourceFile);
};
uiEntryOnChanged(fileEntry, [](uiEntry* e, void* data) -> void {
auto& globals = *reinterpret_cast<Globals*>(data);
globals.sourceFileStr = std::string(uiEntryText(e));
}, &globals);
uiEntrySetReadOnly(fileEntry, 0);
uiButtonOnClicked(fileButton, onOpenFileClicked, &selectFileData);
uiGridAppend(grid, uiControl(fileButton),
0, 0, 1, 1,
0, uiAlignFill, 0, uiAlignFill);
uiGridAppend(grid, uiControl(fileEntry),
1, 0, 1, 1,
1, uiAlignFill, 0, uiAlignFill);
}
///=====================================================================================================================
static void widgetsSelectDestination(uiWindow* mainwin, uiBox* box) {
const auto group = uiNewGroup("Select destination");
uiGroupSetMargined(group, 1);
uiBoxAppend(box, uiControl(group), 0);
uiBoxAppend(box, uiControl(uiNewHorizontalSeparator()), 0);
const auto cboxServe = uiNewCheckbox("Serve on http://localhost:8080/");
const auto cboxFile = uiNewCheckbox("Save to folder");
static struct CBoxData {
Globals& globals;
uiCheckbox* serve;
uiCheckbox* file;
} cboxData{globals, cboxServe, cboxFile};
uiBoxAppend(box, uiControl(cboxServe), 0);
uiCheckboxOnToggled(cboxServe, [](uiCheckbox* cbox, void* data) -> void {
auto& d = *reinterpret_cast<CBoxData*>(data);
d.globals.destinationServe = uiCheckboxChecked(cbox);
uiCheckboxSetChecked(d.file, !d.globals.destinationServe);
}, &cboxData);
uiBoxAppend(box, uiControl(cboxFile), 0);
uiCheckboxOnToggled(cboxFile, [](uiCheckbox* cbox, void* data) -> void {
auto& d = *reinterpret_cast<CBoxData*>(data);
d.globals.destinationFile = uiCheckboxChecked(cbox);
uiCheckboxSetChecked(d.serve, !d.globals.destinationFile);
}, &cboxData);
const auto grid = uiNewGrid();
uiGridSetPadded(grid, 1);
uiBoxAppend(box, uiControl(grid), 0);
const auto fileButton = uiNewButton("Select Folder");
const auto fileEntry = uiNewEntry();
static struct SelectFileData {
uiWindow* mainwin;
Globals& globals;
uiCheckbox* serve;
uiCheckbox* file;
uiEntry* entry;
} selectFileData{mainwin, globals, cboxServe, cboxFile, fileEntry};
const auto onOpenFileClicked = [](uiButton *b, void *data) -> void {
auto& d = *reinterpret_cast<SelectFileData*>(data);
const auto filename = uiOpenFile(d.mainwin);
if (filename == NULL) {
uiEntrySetText(d.entry, "");
return;
}
if (!folderIsValid(filename)) {
uiMsgBoxError(d.mainwin,
"Select folder error",
"You must select a valid folder, not a file!");
uiEntrySetText(d.entry, "");
return;
}
uiEntrySetText(d.entry, filename);
d.globals.destinationFileStr = std::string(filename);
uiFreeText(filename);
d.globals.destinationFile = true;
uiCheckboxSetChecked(d.serve, !d.globals.destinationFile);
uiCheckboxSetChecked(d.file, d.globals.destinationFile);
};
uiEntryOnChanged(fileEntry, [](uiEntry* e, void* data) -> void {
auto& globals = *reinterpret_cast<Globals*>(data);
globals.destinationFileStr = std::string(uiEntryText(e));
}, &globals);
uiEntrySetReadOnly(fileEntry, 0);
uiButtonOnClicked(fileButton, onOpenFileClicked, &selectFileData);
uiGridAppend(grid, uiControl(fileButton),
0, 0, 1, 1,
0, uiAlignFill, 0, uiAlignFill);
uiGridAppend(grid, uiControl(fileEntry),
1, 0, 1, 1,
1, uiAlignFill, 0, uiAlignFill);
}
///=====================================================================================================================
static void widgets(uiWindow* mainwin) {
const auto box = uiNewVerticalBox();
uiBoxSetPadded(box, 1);
uiWindowSetChild(mainwin, uiControl(box));
widgetsSelectSource(mainwin, box);
widgetsSelectDestination(mainwin, box);
uiBoxAppend(box, uiControl(uiNewHorizontalSeparator()), 0);
auto status = uiNewLabel("Press start to begin");
uiBoxAppend(box, uiControl(status), 0);
auto progressbar = uiNewProgressBar();
uiProgressBarSetValue(progressbar, 0);
uiBoxAppend(box, uiControl(progressbar), 0);
auto buttonGrid = uiNewGrid();
uiGridSetPadded(buttonGrid, 1);
static struct StatusData {
uiWindow* mainwin;
Globals& globals;
uiProgressBar* progress;
uiLabel* label;
} statusData{mainwin, globals, progressbar, status};
auto button = uiNewButton("Start");
uiButtonOnClicked(button, [](uiButton *b, void *data) -> void {
const auto callback = [=]() {
auto& d = *reinterpret_cast<StatusData*>(data);
uiProgressBarSetValue(d.progress, 0);
uiButtonSetText(b, "Start");
};
auto& d = *reinterpret_cast<StatusData*>(data);
if (!d.globals.context || d.globals.context->isStopped()) {
try {
d.globals.context = std::make_unique<Context>(d.globals, callback);
uiProgressBarSetValue(d.progress, -1);
uiButtonSetText(b, "Stop");
} catch (std::exception& e) {
uiMsgBoxError(d.mainwin, "Error", e.what());
}
} else {
d.globals.context.reset();
uiProgressBarSetValue(d.progress, 0);
uiButtonSetText(b, "Start");
}
}, &statusData);
uiGridAppend(buttonGrid, uiControl(button),
1, 0, 1, 1,
1, uiAlignCenter, 0, uiAlignFill);
uiBoxAppend(box, uiControl(buttonGrid), 0);
}
///=====================================================================================================================
int main (const int argc, char* argv[]) {
#ifdef _WIN32
......@@ -134,6 +514,26 @@ int main (const int argc, char* argv[]) {
#endif
try {
uiInitOptions o = {0};
const char* err;
if ((err = uiInit(&o)) != nullptr) {
const auto e = std::string(err);
uiFreeInitError(err);
throw std::runtime_error(e);
}
const auto mainwin = uiNewWindow("Decoder", 640, 400, false);
uiWindowSetMargined(mainwin, 1);
uiWindowOnClosing(mainwin, onClosing, NULL);
uiOnShouldQuit(onShouldQuit, mainwin);
widgets(mainwin);
uiControlShow(uiControl(mainwin));
uiMain();
uiUninit();
return 0;
return EXIT_SUCCESS;
}
catch (const std::exception& e) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment