Compare commits
1 Commits
feature/ui
...
feature/gt
| Author | SHA1 | Date | |
|---|---|---|---|
| a6e15c4853 |
@@ -90,9 +90,7 @@ qt_add_executable(metabolus
|
|||||||
set_target_properties(metabolus PROPERTIES AUTOUIC ON)
|
set_target_properties(metabolus PROPERTIES AUTOUIC ON)
|
||||||
|
|
||||||
target_include_directories(metabolus PRIVATE
|
target_include_directories(metabolus PRIVATE
|
||||||
${CMAKE_SOURCE_DIR}/src/
|
|
||||||
${CMAKE_SOURCE_DIR}/src/ui
|
${CMAKE_SOURCE_DIR}/src/ui
|
||||||
${CMAKE_SOURCE_DIR}/src/synth
|
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/widgets
|
${CMAKE_SOURCE_DIR}/src/ui/widgets
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -48,11 +48,11 @@ Linux: GCC
|
|||||||
|
|
||||||
Clone repository
|
Clone repository
|
||||||
```PowerShell
|
```PowerShell
|
||||||
git clone https://git.vxbard.net/homeburger/metabalus.git --recursive
|
git clone https://github.com/Blitblank/metabalus.git --recursive
|
||||||
```
|
```
|
||||||
or if you forgot to --recursive:
|
or if you forgot to --recursive:
|
||||||
```PowerShell
|
```PowerShell
|
||||||
git clone https://git.vxbard.net/homeburger/metabalus.git
|
git clone https://github.com/Blitblank/metabalus.git
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
```
|
```
|
||||||
\
|
\
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ int main(int argc, char *argv[]) {
|
|||||||
MainWindow window; // entry point goes to MainWindow::MainWindow()
|
MainWindow window; // entry point goes to MainWindow::MainWindow()
|
||||||
window.show();
|
window.show();
|
||||||
|
|
||||||
// TODO: logging
|
|
||||||
// TODO: separate app from the window
|
|
||||||
// i made a good debug filtering setup in ouros so could probably improt that into this project
|
|
||||||
|
|
||||||
int status = app.exec(); // app execution; blocks until window close
|
int status = app.exec(); // app execution; blocks until window close
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#include "ConfigInterface.h"
|
#include "../ConfigInterface.h"
|
||||||
#include "Synth.h"
|
#include "Synth.h"
|
||||||
#include "KeyboardController.h"
|
#include "../KeyboardController.h"
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define AUDIO_API RtAudio::WINDOWS_WASAPI
|
#define AUDIO_API RtAudio::WINDOWS_WASAPI
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: if the amount of notes per octave is changed via config then this constant needs to be calculated at startup
|
|
||||||
// as SYNTH_Xth_ROOT_TWO
|
|
||||||
#define SYNTH_TWELFTH_ROOT_TWO 1.05946309435929526463
|
#define SYNTH_TWELFTH_ROOT_TWO 1.05946309435929526463
|
||||||
|
|
||||||
// TODO: you get it, also in a yml config
|
// TODO: you get it, also in a yml config
|
||||||
|
|||||||
@@ -11,9 +11,13 @@ void ScopeBuffer::push(float sample) {
|
|||||||
buffer_[w % buffer_.size()] = sample;
|
buffer_[w % buffer_.size()] = sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: needs a mutex/spinlock to prevent flickering
|
||||||
// outputs value from the scope buffer, called by the scope widget
|
// outputs value from the scope buffer, called by the scope widget
|
||||||
void ScopeBuffer::read(std::vector<float>& out) const {
|
void ScopeBuffer::read(std::vector<float>& out) const {
|
||||||
|
|
||||||
|
// 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);
|
size_t w = writeIndex_.load(std::memory_order_relaxed);
|
||||||
for (size_t i = 0; i < out.size(); i++) {
|
for (size_t i = 0; i < out.size(); i++) {
|
||||||
size_t idx = (w + trigger_ + i * wavelength_ / out.size()) % buffer_.size();
|
size_t idx = (w + trigger_ + i * wavelength_ / out.size()) % buffer_.size();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ParameterStore.h"
|
#include "../ParameterStore.h"
|
||||||
#include "NoteQueue.h"
|
#include "../NoteQueue.h"
|
||||||
#include "Envelope.h"
|
#include "Envelope.h"
|
||||||
#include "ScopeBuffer.h"
|
#include "ScopeBuffer.h"
|
||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ float Voice::process(float* params, bool& scopeTrigger) {
|
|||||||
|
|
||||||
// TODO: implement controls for noise
|
// TODO: implement controls for noise
|
||||||
//float scale = static_cast<float>(rand()) / static_cast<float>(RAND_MAX); // Range [0.0, 1.0]
|
//float scale = static_cast<float>(rand()) / static_cast<float>(RAND_MAX); // Range [0.0, 1.0]
|
||||||
//float noise = (-1.0f + 2.0f * scale) * 0.2f;
|
//float noise = -1.0f + 2.0f * scale;
|
||||||
// these values didn't sound good so I commented them out before I get controls for them
|
// these values didn't sound good so I commented them out before I get controls for them
|
||||||
|
|
||||||
// mix oscillators
|
// mix oscillators
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "Oscillator.h"
|
#include "Oscillator.h"
|
||||||
#include "Envelope.h"
|
#include "Envelope.h"
|
||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
#include "ParameterStore.h"
|
#include "../ParameterStore.h"
|
||||||
|
|
||||||
#ifndef M_PI // I hate my stupid chungus life
|
#ifndef M_PI // I hate my stupid chungus life
|
||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
|
|||||||
@@ -6,10 +6,12 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
WavetableController::WavetableController() {
|
WavetableController::WavetableController() {
|
||||||
|
|
||||||
// load from files
|
// load from files
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
//std::cout << "wavetable init" << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WavetableController::init() {
|
void WavetableController::init() {
|
||||||
@@ -21,11 +23,11 @@ void WavetableController::init() {
|
|||||||
wavetableFiles.push_back(entry.path());
|
wavetableFiles.push_back(entry.path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wavetableCount_ = wavetableFiles.size();
|
uint32_t wavetableCount = wavetableFiles.size();
|
||||||
wavetables_.resize(wavetableCount_);
|
wavetables_.resize(wavetableCount);
|
||||||
|
|
||||||
// load the wavetable files
|
// load the wavetable files
|
||||||
for(int i = 0; i < wavetableCount_; i++) {
|
for(int i = 0; i < wavetableCount; i++) {
|
||||||
std::cout << "loading wavetable file [" << i << "]: " << wavetableFiles[i] << std::endl;
|
std::cout << "loading wavetable file [" << i << "]: " << wavetableFiles[i] << std::endl;
|
||||||
std::ifstream inputFile(wavetableFiles[i], std::ios::in | std::ios::binary);
|
std::ifstream inputFile(wavetableFiles[i], std::ios::in | std::ios::binary);
|
||||||
if(!inputFile) std::cout << "error opening file" << std::endl;
|
if(!inputFile) std::cout << "error opening file" << std::endl;
|
||||||
@@ -54,8 +56,8 @@ float WavetableController::sample(uint8_t wavetableIndex, float phase) {
|
|||||||
uint32_t index = static_cast<uint32_t>(round(scaledPhase));
|
uint32_t index = static_cast<uint32_t>(round(scaledPhase));
|
||||||
if(index >= SYNTH_WAVETABLE_SIZE) index = SYNTH_WAVETABLE_SIZE - 1;
|
if(index >= SYNTH_WAVETABLE_SIZE) index = SYNTH_WAVETABLE_SIZE - 1;
|
||||||
|
|
||||||
if(wavetableIndex >= wavetableCount_) {
|
if(wavetableIndex >= 4) {
|
||||||
wavetableIndex = wavetableCount_ - 1;
|
wavetableIndex = 3;
|
||||||
} else if(wavetableIndex < 0) {
|
} else if(wavetableIndex < 0) {
|
||||||
wavetableIndex = 0;
|
wavetableIndex = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
std::vector<Wavetable> wavetables_;
|
std::vector<Wavetable> wavetables_;
|
||||||
uint32_t wavetableCount_;
|
|
||||||
|
|
||||||
const std::filesystem::path wavetablesRoot_ = "./config/wavetables";
|
const std::filesystem::path wavetablesRoot_ = "./config/wavetables";
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "ui_MainWindow.h"
|
#include "ui_MainWindow.h"
|
||||||
|
|
||||||
#include "ParameterStore.h"
|
#include "SmartSlider/SmartSlider.h"
|
||||||
|
#include "../ParameterStore.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
@@ -58,19 +59,67 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// rogue sliders, TODO: clean these up in a package
|
// rogue sliders, TODO: clean these up in a package
|
||||||
bindSlider(ui_->sliderMasterOctave, ParamId::MasterOctaveOffset, true);
|
connect(ui_->sliderMasterOctave, &SmartSlider::valueChanged,
|
||||||
bindSlider(ui_->sliderMasterSemitone, ParamId::MasterSemitoneOffset, true);
|
this, [this](float value) {
|
||||||
bindSlider(ui_->sliderMasterPitch, ParamId::MasterPitchOffset);
|
audio_->parameters()->set(ParamId::MasterOctaveOffset, value);
|
||||||
bindSlider(ui_->sliderOsc1Octave, ParamId::Osc1OctaveOffset, true);
|
ui_->sliderMasterOctave->setResolution();
|
||||||
bindSlider(ui_->sliderOsc1Semitone, ParamId::Osc1SemitoneOffset, true);
|
});
|
||||||
bindSlider(ui_->sliderOsc1Pitch, ParamId::Osc1PitchOffset);
|
connect(ui_->sliderMasterSemitone, &SmartSlider::valueChanged,
|
||||||
bindSlider(ui_->sliderOsc2Octave, ParamId::Osc2OctaveOffset, true);
|
this, [this](float value) {
|
||||||
bindSlider(ui_->sliderOsc2Semitone, ParamId::Osc2SemitoneOffset, true);
|
audio_->parameters()->set(ParamId::MasterSemitoneOffset, value);
|
||||||
bindSlider(ui_->sliderOsc2Pitch, ParamId::Osc2PitchOffset);
|
ui_->sliderMasterSemitone->setResolution();
|
||||||
bindSlider(ui_->sliderOsc3Octave, ParamId::Osc3OctaveOffset, true);
|
});
|
||||||
bindSlider(ui_->sliderOsc3Semitone, ParamId::Osc3SemitoneOffset, true);
|
connect(ui_->sliderMasterPitch, &SmartSlider::valueChanged,
|
||||||
bindSlider(ui_->sliderOsc3Pitch, ParamId::Osc3PitchOffset);
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::MasterPitchOffset, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui_->sliderOsc1Octave, &SmartSlider::valueChanged,
|
||||||
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::Osc1OctaveOffset, value);
|
||||||
|
ui_->sliderOsc1Octave->setResolution();
|
||||||
|
});
|
||||||
|
connect(ui_->sliderOsc1Semitone, &SmartSlider::valueChanged,
|
||||||
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::Osc1SemitoneOffset, value);
|
||||||
|
ui_->sliderOsc1Semitone->setResolution();
|
||||||
|
});
|
||||||
|
connect(ui_->sliderOsc1Pitch, &SmartSlider::valueChanged,
|
||||||
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::Osc1PitchOffset, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui_->sliderOsc2Octave, &SmartSlider::valueChanged,
|
||||||
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::Osc2OctaveOffset, value);
|
||||||
|
ui_->sliderOsc2Octave->setResolution();
|
||||||
|
});
|
||||||
|
connect(ui_->sliderOsc2Semitone, &SmartSlider::valueChanged,
|
||||||
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::Osc2SemitoneOffset, value);
|
||||||
|
ui_->sliderOsc2Semitone->setResolution();
|
||||||
|
});
|
||||||
|
connect(ui_->sliderOsc2Pitch, &SmartSlider::valueChanged,
|
||||||
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::Osc2PitchOffset, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui_->sliderOsc3Octave, &SmartSlider::valueChanged,
|
||||||
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::Osc3OctaveOffset, value);
|
||||||
|
ui_->sliderOsc3Octave->setResolution();
|
||||||
|
});
|
||||||
|
connect(ui_->sliderOsc3Semitone, &SmartSlider::valueChanged,
|
||||||
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::Osc3SemitoneOffset, value);
|
||||||
|
ui_->sliderOsc3Semitone->setResolution();
|
||||||
|
});
|
||||||
|
connect(ui_->sliderOsc3Pitch, &SmartSlider::valueChanged,
|
||||||
|
this, [this](float value) {
|
||||||
|
audio_->parameters()->set(ParamId::Osc3PitchOffset, value);
|
||||||
|
});
|
||||||
|
|
||||||
// synth business
|
// synth business
|
||||||
audio_->start();
|
audio_->start();
|
||||||
@@ -108,7 +157,6 @@ void MainWindow::onResetClicked() {
|
|||||||
|
|
||||||
// TODO: clean these up, maybe put them in a package like the envelope generators (it'll help encapsulate the int-snapping business)
|
// TODO: clean these up, maybe put them in a package like the envelope generators (it'll help encapsulate the int-snapping business)
|
||||||
// what I might do is make a variable-length slider-package object
|
// what I might do is make a variable-length slider-package object
|
||||||
// TODO: the oscillator things also need an amplitude parameter too
|
|
||||||
YAML::Node masterNode = configRoot["MasterPitchOffset"];
|
YAML::Node masterNode = configRoot["MasterPitchOffset"];
|
||||||
YAML::Node osc1Node = configRoot["Osc1PitchOffset"];
|
YAML::Node osc1Node = configRoot["Osc1PitchOffset"];
|
||||||
YAML::Node osc2Node = configRoot["Osc2PitchOffset"];
|
YAML::Node osc2Node = configRoot["Osc2PitchOffset"];
|
||||||
@@ -161,12 +209,3 @@ void MainWindow::onResetClicked() {
|
|||||||
ui_->comboOsc1WaveSelector2->setCurrentIndex(configRoot["OscWaveSelector2"].as<int>());
|
ui_->comboOsc1WaveSelector2->setCurrentIndex(configRoot["OscWaveSelector2"].as<int>());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::bindSlider(SmartSlider* slider, ParamId param, bool updateResolution)
|
|
||||||
{
|
|
||||||
connect(slider, &SmartSlider::valueChanged, this,
|
|
||||||
[this](float value, ParamId param, SmartSlider* slider, bool updateResolution) {
|
|
||||||
audio_->parameters()->set(param, value);
|
|
||||||
if (updateResolution) slider->setResolution();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,10 +4,9 @@
|
|||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
|
||||||
#include "ConfigInterface.h"
|
#include "../ConfigInterface.h"
|
||||||
#include "synth/AudioEngine.h"
|
#include "../synth/AudioEngine.h"
|
||||||
#include "MidiController.h"
|
#include "../MidiController.h"
|
||||||
#include "SmartSlider/SmartSlider.h"
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
namespace Ui { class MainWindow; }
|
namespace Ui { class MainWindow; }
|
||||||
@@ -30,8 +29,6 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void bindSlider(SmartSlider* slider, ParamId param, bool updateResolution = false);
|
|
||||||
|
|
||||||
Ui::MainWindow *ui_;
|
Ui::MainWindow *ui_;
|
||||||
|
|
||||||
ParameterStore params_;
|
ParameterStore params_;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "ParameterStore.h"
|
#include "../../ParameterStore.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
namespace Ui { class EnvelopeGenerator; }
|
namespace Ui { class EnvelopeGenerator; }
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "ui_Scope.h"
|
#include "ui_Scope.h"
|
||||||
|
|
||||||
// TODO: fix include directories because what is this
|
// TODO: fix include directories because what is this
|
||||||
#include "synth/ScopeBuffer.h"
|
#include "../../../synth/ScopeBuffer.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|||||||
Reference in New Issue
Block a user