From 69a507d57b64eed6eed9a3e00c7a272939de8a6a Mon Sep 17 00:00:00 2001 From: Bliblank Date: Sat, 24 Jan 2026 14:07:38 -0600 Subject: [PATCH] make basic audio engine parameters configurable --- scripts/build.ps1 | 13 +++---- scripts/install_dependencies.ps1 | 15 ++++++-- src/ConfigInterface.cpp | 63 +++++++++++++++----------------- src/ConfigInterface.h | 14 ++++++- src/main.cpp | 4 +- src/synth/AudioEngine.cpp | 12 ++++-- src/synth/AudioEngine.h | 4 +- src/synth/ScopeBuffer.cpp | 5 ++- src/ui/MainWindow.cpp | 2 +- src/ui/MainWindow.h | 2 + 10 files changed, 78 insertions(+), 56 deletions(-) diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 74408b3..aa98e78 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -47,7 +47,6 @@ if (-not ($dependencies_found -eq $libraries.Count)) { # configure Write-Host "Configuring metabolus..." cmake -S . -B $BUILD_DIR -G "Visual Studio 17 2022" ` - -DCMAKE_BUILD_TYPE=Release ` -DQt6_ROOT="$QT_ROOT\lib\cmake\Qt6" ` -DRtAudio_ROOT="$RTAUDIO_ROOT" ` -DRtMidi_ROOT="$RTMIDI_ROOT" ` @@ -56,7 +55,7 @@ cmake -S . -B $BUILD_DIR -G "Visual Studio 17 2022" ` # build Write-Host "Building metabolus..." -cmake --build $BUILD_DIR +cmake --build $BUILD_DIR --config $CONFIG # TODO: install @@ -64,14 +63,14 @@ cmake --build $BUILD_DIR Write-Host "Deploying metabolus..." cd $BUILD_DIR -& "$QT_ROOT\bin\windeployqt6.exe" .\Debug\metabolus.exe +& "$QT_ROOT\bin\windeployqt6.exe" .\$CONFIG\metabolus.exe # copy dlls -Copy-Item -Path "$RTAUDIO_ROOT\bin\rtaudio.dll" -Destination .\Debug -Copy-Item -Path "$RTMIDI_ROOT\bin\rtmidi.dll" -Destination .\Debug -Copy-Item -Path "$YAMLCPP_ROOT\bin\yaml-cpp.dll" -Destination .\Debug +Copy-Item -Path "$RTAUDIO_ROOT\bin\rtaudio.dll" -Destination .\$CONFIG +Copy-Item -Path "$RTMIDI_ROOT\bin\rtmidi.dll" -Destination .\$CONFIG +Copy-Item -Path "$YAMLCPP_ROOT\bin\yaml-cpp.dll" -Destination .\$CONFIG # copy configs, but don't overwrite -Copy-Item -Path "$CONFIG_ROOT" -Destination ".\Debug\" -Recurse -ErrorAction SilentlyContinue +Copy-Item -Path "$CONFIG_ROOT" -Destination ".\$CONFIG\" -Recurse -ErrorAction SilentlyContinue cd $PROJECT_ROOT diff --git a/scripts/install_dependencies.ps1 b/scripts/install_dependencies.ps1 index c885611..1e6478b 100644 --- a/scripts/install_dependencies.ps1 +++ b/scripts/install_dependencies.ps1 @@ -1,6 +1,8 @@ echo "Installing dependencies ... " +# TODO: add a clean (like delete build dirs) script + $project_root = $PWD if (-not (Test-Path -Path "$PWD\build\lib")) { @@ -12,21 +14,28 @@ $build_lib_dir = "$PWD\build\lib" # rtaudio mkdir "$build_lib_dir\rtaudio" -Force cd $project_root\lib\rtaudio -cmake -S . -B build -G "Visual Studio 17 2022" -DRTDUIO_API_WASAPI=ON -DRTAUDIO_API_DS=OFF -DRT_AUDIO_API_ASIO=OFF -DRTAUDIO_BUILD_SHARED_LIBS=ON +cmake -S . -B build -G "Visual Studio 17 2022" ` + -DRTDUIO_API_WASAPI=ON ` + -DRTAUDIO_API_DS=OFF ` + -DRT_AUDIO_API_ASIO=OFF ` + -DRTAUDIO_BUILD_SHARED_LIBS=ON cmake --build build --config Release cmake --install build --prefix "$build_lib_dir\rtaudio" # rtmidi mkdir "$build_lib_dir\rtmidi" -Force cd $project_root\lib\rtmidi -cmake -S . -B build -G "Visual Studio 17 2022" -DRT_MIDI_API_WINMM=ON -DRTMIDI_BUILD_SHARED_LIBS=ON +cmake -S . -B build -G "Visual Studio 17 2022" ` + -DRT_MIDI_API_WINMM=ON ` + -DRTMIDI_BUILD_SHARED_LIBS=ON cmake --build build --config Release cmake --install build --prefix "$build_lib_dir\rtmidi" # yaml-cpp mkdir "$build_lib_dir\yaml-cpp" -Force cd $project_root\lib\yaml-cpp -cmake -S . -B build -G "Visual Studio 17 2022" -DYAML_BUILD_SHARED_LIBS=ON +cmake -S . -B build -G "Visual Studio 17 2022" ` + -DYAML_BUILD_SHARED_LIBS=ON cmake --build build --config Release cmake --install build --prefix "$build_lib_dir\yaml-cpp" diff --git a/src/ConfigInterface.cpp b/src/ConfigInterface.cpp index 22e6451..4c209ef 100644 --- a/src/ConfigInterface.cpp +++ b/src/ConfigInterface.cpp @@ -11,39 +11,34 @@ namespace fs = std::filesystem; ConfigInterface::ConfigInterface() { - std::string audioConfig = configRoot + "/" + filename; - - std::cout << "CWD: " << fs::current_path() << std::endl; - std::cout << "Audio config: " << fs::absolute(audioConfig).string() << std::endl; - - // opening the file myself because YAML::LoadFile didn't seem to work on windows - std::ifstream file(fs::absolute(audioConfig).string()); - if(file.good()) { - std::cout << "File exists" << std::endl; - } else { - std::cout << "File does not exist" << std::endl; - } - - //YAML::Node config; - /* - try { - YAML::Node config = YAML::Load("{sampleRate: 44100}"); - std::cout << "Loaded config file" << std::endl; - - std::cout << "Type enum: " << static_cast(config.Type()) << std::endl; - - if(config["sampleRate"]) { - //int sampleRate = config["sampleRate"].as(); - //std::cout << sampleRate << std::endl; - } else { - std::cout << "Key does not exist" << std::endl; - } - } catch(const std::exception& e) { - std::cerr << e.what() << '\n'; - } - */ - - YAML::Node n = YAML::Load("{sampleRate: 44100}"); - std::cout << n["sampleRate"].as() << "\n"; + //std::cout << "Config constructor" << std::endl; + +} + +int ConfigInterface::getValue(ConfigFile file, std::string key, int defaultVal) { + + // assemble filepath + std::string filepath = configRoot + "/" + filePaths[static_cast(file)]; + filepath = fs::absolute(filepath).string(); + + // attempt to open file + YAML::Node config; + try { + YAML::Node config = YAML::LoadFile(filepath); + + // read key if it exists + if(config[key]) { + return config[key].as(defaultVal); + } else { + return -1; // key does not exist + } + + } catch(const std::exception& e) { + std::cerr << e.what() << std::endl; + return -1; + } + + // unreachable + return -1; } diff --git a/src/ConfigInterface.h b/src/ConfigInterface.h index 82da440..6bd15bd 100644 --- a/src/ConfigInterface.h +++ b/src/ConfigInterface.h @@ -2,6 +2,17 @@ #pragma once #include +#include + +enum class ConfigFile { + Audio = 0 + // other files here +}; + +// might have a config file for specifying paths to other config files instead of this +const std::vector filePaths = { + "audio.yaml" +}; class ConfigInterface { @@ -10,9 +21,10 @@ public: ConfigInterface(); ~ConfigInterface() = default; + int getValue(ConfigFile file, std::string key, int defaultVal); + private: const std::string configRoot = "config"; - const std::string filename = "audio.yaml"; }; diff --git a/src/main.cpp b/src/main.cpp index d12d7fb..7d68bee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,9 +9,7 @@ int main(int argc, char *argv[]) { // std::cout << "Main()" << std::endl; - - ConfigInterface config = ConfigInterface(); - + QApplication app(argc, argv); MainWindow window; // entry point goes to MainWindow::MainWindow() diff --git a/src/synth/AudioEngine.cpp b/src/synth/AudioEngine.cpp index 44cab86..4b29f7d 100644 --- a/src/synth/AudioEngine.cpp +++ b/src/synth/AudioEngine.cpp @@ -3,14 +3,11 @@ #include -AudioEngine::AudioEngine() : synth_(params_) { +AudioEngine::AudioEngine(ConfigInterface* config) : synth_(params_), config_(config) { if(audio_.getDeviceCount() < 1) { throw std::runtime_error("No audio devices found"); } - // TODO: get audio configurations - synth_.setSampleRate(sampleRate_); - synth_.setScopeBuffer(&scope_); } @@ -21,6 +18,13 @@ AudioEngine::~AudioEngine() { bool AudioEngine::start() { + // get config values + sampleRate_ = config_->getValue(ConfigFile::Audio, "sampleRate", sampleRate_); + bufferFrames_ = config_->getValue(ConfigFile::Audio, "bufferSize", bufferFrames_); + channels_ = config_->getValue(ConfigFile::Audio, "channels", channels_); + + synth_.setSampleRate(sampleRate_); + // initialize the audio engine RtAudio::StreamParameters params; params.deviceId = audio_.getDefaultOutputDevice(); diff --git a/src/synth/AudioEngine.h b/src/synth/AudioEngine.h index b1c6b7d..ae673fc 100644 --- a/src/synth/AudioEngine.h +++ b/src/synth/AudioEngine.h @@ -7,6 +7,7 @@ #include "Synth.h" #include "../KeyboardController.h" +#include "../ConfigInterface.h" #if defined(_WIN32) #define AUDIO_API RtAudio::WINDOWS_WASAPI @@ -17,7 +18,7 @@ class AudioEngine { public: - AudioEngine(); + AudioEngine(ConfigInterface* config); ~AudioEngine(); // starts the audio stream. returns true on success and false on failure @@ -43,6 +44,7 @@ private: NoteQueue noteQueue_; // stores note events for passing between threads Synth synth_; // generates audio ScopeBuffer scope_ { 1024 }; // stores audio samples for visualization + ConfigInterface* config_; // access to config files RtAudio audio_{AUDIO_API}; // audio device // TODO: id like a yml config file or something for these diff --git a/src/synth/ScopeBuffer.cpp b/src/synth/ScopeBuffer.cpp index d94d452..4c6682e 100644 --- a/src/synth/ScopeBuffer.cpp +++ b/src/synth/ScopeBuffer.cpp @@ -11,11 +11,12 @@ void ScopeBuffer::push(float sample) { buffer_[w % buffer_.size()] = sample; } -// TODO: needs a mutex to prevent flickering +// TODO: needs a mutex/spinlock to prevent flickering // outputs value from the scope buffer, called by the scope widget void ScopeBuffer::read(std::vector& out) const { - while(!spinLock_) { int x = 1 + 1; } + // yeah this didn't work, maybe it needs to be atomic or something + //while(!spinLock_) { int x = 1 + 1; } size_t w = writeIndex_.load(std::memory_order_relaxed); for (size_t i = 0; i < out.size(); i++) { diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index 36d8f41..4a942eb 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -8,7 +8,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui_(new Ui::MainWindow), - audio_(new AudioEngine()), + audio_(new AudioEngine(&config_)), keyboard_(audio_->noteQueue()), midi_(audio_->noteQueue()) { diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index fe17f42..ff71068 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -6,6 +6,7 @@ #include "../synth/AudioEngine.h" #include "../MidiController.h" +#include "../ConfigInterface.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -32,5 +33,6 @@ private: AudioEngine* audio_ = nullptr; KeyboardController keyboard_; MidiController midi_; + ConfigInterface config_; };