basic profile loading
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
|
||||
#include "ConfigInterface.h"
|
||||
|
||||
#include "yaml-cpp/yaml.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
@@ -14,6 +12,11 @@ ConfigInterface::ConfigInterface() {
|
||||
|
||||
}
|
||||
|
||||
ConfigInterface::ConfigInterface(ParameterStore* params): params_(params) {
|
||||
|
||||
}
|
||||
|
||||
// lots of checking in this to make this safe
|
||||
int ConfigInterface::getValue(ConfigFile file, std::string key, int defaultVal) {
|
||||
|
||||
// assemble filepath
|
||||
@@ -42,3 +45,69 @@ int ConfigInterface::getValue(ConfigFile file, std::string key, int defaultVal)
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
// ugly but if it works it works
|
||||
void ConfigInterface::loadProfile(std::string filename) {
|
||||
|
||||
// load file
|
||||
std::string filepath = "config/profiles/" + filename + ".yaml";
|
||||
filepath = std::filesystem::absolute(filepath).string();
|
||||
YAML::Node config;
|
||||
try {
|
||||
config = YAML::LoadFile(filepath);
|
||||
} catch(const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// check version
|
||||
int version = config["version"].as<int>(); // yaml-cpp parses unquoted hex as integers
|
||||
if(version < CONFIG_VERSION) {
|
||||
std::cout << "Parameter profile version " << version << "is outdated below the compatible version " << CONFIG_VERSION << std::endl;
|
||||
return;
|
||||
} else {
|
||||
std::cout << version << std::endl;
|
||||
}
|
||||
|
||||
// extract values from the config file
|
||||
std::array<ParamDefault, 5> osc1VolumeProfile = loadEnvProfile(&config, "Osc1Volume");
|
||||
std::array<ParamDefault, 5> fCutoffProfile = loadEnvProfile(&config, "FilterCutoff");
|
||||
std::array<ParamDefault, 5> fResonanceProfile = loadEnvProfile(&config, "FilterResonance");
|
||||
|
||||
// TODO: remove this once all the parameters are set properly
|
||||
params_->resetToDefaults();
|
||||
|
||||
// set the values in the paramstore
|
||||
params_->set(EnvelopeId::Osc1Volume, osc1VolumeProfile[0].def, osc1VolumeProfile[1].def, osc1VolumeProfile[2].def, osc1VolumeProfile[3].def, osc1VolumeProfile[4].def);
|
||||
params_->set(EnvelopeId::FilterCutoff, fCutoffProfile[0].def, fCutoffProfile[1].def, fCutoffProfile[2].def, fCutoffProfile[3].def, fCutoffProfile[4].def);
|
||||
params_->set(EnvelopeId::FilterResonance, fResonanceProfile[0].def, fResonanceProfile[1].def, fResonanceProfile[2].def, fResonanceProfile[3].def, fResonanceProfile[4].def);
|
||||
// TODO: why do I bother passing in 5 values independently when I can just do an array ?
|
||||
// VVV look down there its so easy
|
||||
|
||||
// TODO:
|
||||
// load wavetable settings
|
||||
// load oscillator pitch settings
|
||||
|
||||
}
|
||||
|
||||
std::array<ParamDefault, 5> ConfigInterface::loadEnvProfile(YAML::Node* node, std::string profile) {
|
||||
|
||||
YAML::Node envelopeNode = (*node)[profile];
|
||||
|
||||
std::array<ParamDefault, 5> paramProfile;
|
||||
|
||||
for(int i = 0; i < paramProfile.size(); i++) {
|
||||
paramProfile[i] = { envelopeNode[i][0].as<float>(), envelopeNode[i][1].as<float>(), envelopeNode[i][2].as<float>() };
|
||||
}
|
||||
|
||||
return paramProfile;
|
||||
}
|
||||
|
||||
std::array<ParamDefault, 5> ConfigInterface::loadEnvProfile(std::string filename, std::string profile) {
|
||||
|
||||
std::string filepath = "config/profiles/" + filename + ".yaml";
|
||||
filepath = std::filesystem::absolute(filepath).string();
|
||||
YAML::Node config = YAML::LoadFile(filepath);
|
||||
|
||||
return loadEnvProfile(&config, profile);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include "yaml-cpp/yaml.h"
|
||||
|
||||
#include "ParameterStore.h"
|
||||
|
||||
#define CONFIG_VERSION 0x0002
|
||||
|
||||
enum class ConfigFile {
|
||||
Audio = 0
|
||||
@@ -15,17 +20,27 @@ const std::vector<std::string> filePaths = {
|
||||
"audio.yaml"
|
||||
};
|
||||
|
||||
// Reads from yaml config files
|
||||
// Handles things like profile loading
|
||||
class ConfigInterface {
|
||||
|
||||
public:
|
||||
|
||||
ConfigInterface();
|
||||
ConfigInterface(ParameterStore* params);
|
||||
~ConfigInterface() = default;
|
||||
|
||||
int getValue(ConfigFile file, std::string key, int defaultVal);
|
||||
|
||||
void loadProfile(std::string filename);
|
||||
std::array<ParamDefault, 5> loadEnvProfile(YAML::Node* node, std::string profile);
|
||||
std::array<ParamDefault, 5> loadEnvProfile(std::string filename, std::string profile);
|
||||
|
||||
private:
|
||||
|
||||
const std::string configRoot = "config";
|
||||
|
||||
// loading parameters
|
||||
ParameterStore* params_;
|
||||
|
||||
};
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "yaml-cpp/yaml.h" // TODO: using yaml.h outside of ConfigInterface feels spaghetti to me
|
||||
#include <filesystem>
|
||||
|
||||
ParameterStore::ParameterStore(ConfigInterface* config) : config_(config) {
|
||||
resetToDefaults();
|
||||
ParameterStore::ParameterStore() {
|
||||
//resetToDefaults();
|
||||
}
|
||||
|
||||
// set parameter value
|
||||
@@ -31,45 +31,9 @@ float ParameterStore::get(ParamId id) const {
|
||||
}
|
||||
|
||||
void ParameterStore::resetToDefaults() {
|
||||
|
||||
for(size_t i = 0; i < PARAM_COUNT; i++) {
|
||||
values_[i].store(PARAM_DEFS[i].def, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
loadParameterProfile("config/profiles/default.yaml");
|
||||
|
||||
}
|
||||
|
||||
void ParameterStore::loadParameterProfile(std::string filepath) {
|
||||
|
||||
// TODO: abstract the actual yaml interfacing to the ConfigInterface instead of here
|
||||
// TODO: update ui based on changes that happen not in the ui
|
||||
// it will require some architecture rework :(
|
||||
|
||||
// load file
|
||||
filepath = std::filesystem::absolute(filepath).string();
|
||||
YAML::Node config;
|
||||
try {
|
||||
config = YAML::LoadFile(filepath);
|
||||
} catch(const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// check version
|
||||
int version = config["version"].as<int>(); // yaml-cpp parses unquoted hex as integers
|
||||
if(version < CONFIG_VERSION) {
|
||||
std::cout << "Parameter profile version " << version << "is outdated below the compatible version " << CONFIG_VERSION << std::endl;
|
||||
return;
|
||||
} else {
|
||||
//std::cout << version << std::endl;
|
||||
}
|
||||
|
||||
// start setting some values
|
||||
YAML::Node osc1Volume = config["Osc1Volume"];
|
||||
YAML::Node fCutoff = config["FilterCutoff"];
|
||||
YAML::Node fResonance = config["FilterResonance"];
|
||||
set(EnvelopeId::Osc1Volume, osc1Volume[0][0].as<float>(), osc1Volume[1][0].as<float>(), osc1Volume[2][0].as<float>(), osc1Volume[3][0].as<float>(), osc1Volume[4][0].as<float>());
|
||||
set(EnvelopeId::FilterCutoff, fCutoff[0][0].as<float>(), fCutoff[1][0].as<float>(), fCutoff[2][0].as<float>(), fCutoff[3][0].as<float>(), fCutoff[4][0].as<float>());
|
||||
set(EnvelopeId::FilterResonance, fResonance[0][0].as<float>(), fResonance[1][0].as<float>(), fResonance[2][0].as<float>(), fResonance[3][0].as<float>(), fResonance[4][0].as<float>());
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ConfigInterface.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
|
||||
#define CONFIG_VERSION 0x0001
|
||||
|
||||
enum class ParamId : uint16_t {
|
||||
Osc1Frequency,
|
||||
Osc1WaveSelector1,
|
||||
@@ -111,7 +107,7 @@ class ParameterStore {
|
||||
|
||||
public:
|
||||
|
||||
ParameterStore(ConfigInterface* config);
|
||||
ParameterStore();
|
||||
~ParameterStore() = default;
|
||||
|
||||
void set(ParamId id, float value);
|
||||
@@ -123,10 +119,6 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void loadParameterProfile(std::string filepath);
|
||||
|
||||
std::array<std::atomic<float>, PARAM_COUNT> values_;
|
||||
|
||||
ConfigInterface* config_;
|
||||
|
||||
};
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
AudioEngine::AudioEngine(ConfigInterface* config) : params_(ParameterStore(config)), synth_(params_), config_(config) {
|
||||
AudioEngine::AudioEngine(ConfigInterface* config, ParameterStore* params) : params_(params), synth_(params), config_(config) {
|
||||
|
||||
if(audio_.getDeviceCount() < 1) {
|
||||
throw std::runtime_error("No audio devices found");
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
#include <stdint.h>
|
||||
#include <atomic>
|
||||
|
||||
#include "../ConfigInterface.h"
|
||||
#include "Synth.h"
|
||||
#include "../KeyboardController.h"
|
||||
#include "../ConfigInterface.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define AUDIO_API RtAudio::WINDOWS_WASAPI
|
||||
@@ -18,7 +18,9 @@
|
||||
class AudioEngine {
|
||||
|
||||
public:
|
||||
AudioEngine(ConfigInterface* config);
|
||||
|
||||
AudioEngine() = default;
|
||||
AudioEngine(ConfigInterface* config, ParameterStore* params);
|
||||
~AudioEngine();
|
||||
|
||||
// starts the audio stream. returns true on success and false on failure
|
||||
@@ -28,7 +30,7 @@ public:
|
||||
void stop();
|
||||
|
||||
// getters
|
||||
ParameterStore* parameters() { return ¶ms_; }
|
||||
ParameterStore* parameters() { return params_; }
|
||||
NoteQueue& noteQueue() { return noteQueue_; }
|
||||
ScopeBuffer& scopeBuffer() { return scope_; }
|
||||
|
||||
@@ -41,7 +43,7 @@ private:
|
||||
int32_t process(float* out, uint32_t nFrames);
|
||||
|
||||
ConfigInterface* config_; // access to config files
|
||||
ParameterStore params_; // stores the control parameters
|
||||
ParameterStore* params_; // stores the control parameters
|
||||
NoteQueue noteQueue_; // stores note events for passing between threads
|
||||
Synth synth_; // generates audio
|
||||
ScopeBuffer scope_ { 1024 }; // stores audio samples for visualization
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
Synth::Synth(const ParameterStore& params) : paramStore_(params) {
|
||||
Synth::Synth(ParameterStore* params) : paramStore_(params) {
|
||||
voices_.fill(Voice(params_.data(), &wavetable_));
|
||||
}
|
||||
|
||||
void Synth::updateParams() {
|
||||
for(size_t i = 0; i < PARAM_COUNT; i++) {
|
||||
params_[i].target = paramStore_.get(static_cast<ParamId>(i));
|
||||
params_[i].target = paramStore_->get(static_cast<ParamId>(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
class Synth {
|
||||
|
||||
public:
|
||||
Synth(const ParameterStore& params);
|
||||
Synth() = default;
|
||||
Synth(ParameterStore* params);
|
||||
~Synth() = default;
|
||||
|
||||
// generates a buffer of audio samples nFrames long
|
||||
@@ -39,7 +40,7 @@ private:
|
||||
Voice* findFreeVoice();
|
||||
Voice* findVoiceByNote(uint8_t note);
|
||||
|
||||
const ParameterStore& paramStore_;
|
||||
ParameterStore* paramStore_;
|
||||
// smoothed params creates a buffer in case the thread controlling paramStore gets blocked
|
||||
std::array<SmoothedParam, PARAM_COUNT> params_;
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui_(new Ui::MainWindow),
|
||||
audio_(new AudioEngine(&config_)),
|
||||
config_(ConfigInterface(¶ms_)),
|
||||
audio_(new AudioEngine(&config_, ¶ms_)),
|
||||
keyboard_(audio_->noteQueue()),
|
||||
midi_(audio_->noteQueue()) {
|
||||
|
||||
@@ -74,12 +75,13 @@ void MainWindow::onResetClicked() {
|
||||
|
||||
// initialize to defaults
|
||||
|
||||
// envelopeGenerators
|
||||
ui_->envelopeOsc1Volume->init(EnvelopeId::Osc1Volume);
|
||||
ui_->envelopeFilterCutoff->init(EnvelopeId::FilterCutoff);
|
||||
ui_->envelopeFilterResonance->init(EnvelopeId::FilterResonance);
|
||||
config_.loadProfile("default");
|
||||
|
||||
// update ui from the paramstore
|
||||
ui_->envelopeOsc1Volume->init(EnvelopeId::Osc1Volume, config_.loadEnvProfile("default", "Osc1Volume"));
|
||||
ui_->envelopeFilterCutoff->init(EnvelopeId::FilterCutoff, config_.loadEnvProfile("default", "FilterCutoff"));
|
||||
ui_->envelopeFilterResonance->init(EnvelopeId::FilterResonance, config_.loadEnvProfile("default", "FilterResonance"));
|
||||
|
||||
// comboBoxes
|
||||
ui_->comboOsc1WaveSelector1->setCurrentIndex(static_cast<int>(PARAM_DEFS[static_cast<size_t>(ParamId::Osc1WaveSelector1)].def));
|
||||
ui_->comboOsc1WaveSelector2->setCurrentIndex(static_cast<int>(PARAM_DEFS[static_cast<size_t>(ParamId::Osc1WaveSelector2)].def));
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
#include <QMainWindow>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include "../ConfigInterface.h"
|
||||
#include "../synth/AudioEngine.h"
|
||||
#include "../MidiController.h"
|
||||
#include "../ConfigInterface.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
@@ -28,8 +28,10 @@ private slots:
|
||||
void onResetClicked();
|
||||
|
||||
private:
|
||||
|
||||
Ui::MainWindow *ui_;
|
||||
|
||||
ParameterStore params_;
|
||||
ConfigInterface config_;
|
||||
AudioEngine* audio_ = nullptr;
|
||||
KeyboardController keyboard_;
|
||||
|
||||
@@ -92,3 +92,21 @@ void EnvelopeGenerator::init(EnvelopeId id) {
|
||||
setRelease(PARAM_DEFS[static_cast<size_t>(params.r)].def);
|
||||
|
||||
}
|
||||
|
||||
void EnvelopeGenerator::init(EnvelopeId id, std::array<ParamDefault, 5> profile) {
|
||||
|
||||
EnvelopeParam params = ENV_PARAMS[static_cast<size_t>(id)];
|
||||
|
||||
ui_->sliderDepth->setRange(profile[0].min, profile[0].max);
|
||||
ui_->sliderAttack->setRange(profile[1].min, profile[1].max);
|
||||
ui_->sliderDecay->setRange(profile[2].min, profile[2].max);
|
||||
ui_->sliderSustain->setRange(profile[3].min, profile[3].max);
|
||||
ui_->sliderRelease->setRange(profile[4].min, profile[4].max);
|
||||
|
||||
setDepth(profile[0].def);
|
||||
setAttack(profile[1].def);
|
||||
setDecay(profile[2].def);
|
||||
setSustain(profile[3].def);
|
||||
setRelease(profile[4].def);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
|
||||
// connects signals, sets parameters to the defaults defined in paramStore
|
||||
void init(EnvelopeId id);
|
||||
void init(EnvelopeId id, std::array<ParamDefault, 5> profile);
|
||||
|
||||
// setters
|
||||
void setDepth(float v);
|
||||
|
||||
Reference in New Issue
Block a user