Compare commits
4 Commits
feature/gt
...
feature/ui
| Author | SHA1 | Date | |
|---|---|---|---|
| 35663df15c | |||
| 2590b03756 | |||
| 8e838c61e6 | |||
| 5c9a37b8d4 |
@@ -90,7 +90,9 @@ qt_add_executable(metabolus
|
||||
set_target_properties(metabolus PROPERTIES AUTOUIC ON)
|
||||
|
||||
target_include_directories(metabolus PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/src/
|
||||
${CMAKE_SOURCE_DIR}/src/ui
|
||||
${CMAKE_SOURCE_DIR}/src/synth
|
||||
${CMAKE_SOURCE_DIR}/src/ui/widgets
|
||||
)
|
||||
|
||||
|
||||
@@ -48,11 +48,11 @@ Linux: GCC
|
||||
|
||||
Clone repository
|
||||
```PowerShell
|
||||
git clone https://github.com/Blitblank/metabalus.git --recursive
|
||||
git clone https://git.vxbard.net/homeburger/metabalus.git --recursive
|
||||
```
|
||||
or if you forgot to --recursive:
|
||||
```PowerShell
|
||||
git clone https://github.com/Blitblank/metabalus.git
|
||||
git clone https://git.vxbard.net/homeburger/metabalus.git
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
\
|
||||
|
||||
@@ -14,6 +14,10 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
MainWindow window; // entry point goes to MainWindow::MainWindow()
|
||||
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
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
#include <stdint.h>
|
||||
#include <atomic>
|
||||
|
||||
#include "../ConfigInterface.h"
|
||||
#include "ConfigInterface.h"
|
||||
#include "Synth.h"
|
||||
#include "../KeyboardController.h"
|
||||
#include "KeyboardController.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define AUDIO_API RtAudio::WINDOWS_WASAPI
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#define M_PI 3.14159265358979323846
|
||||
#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
|
||||
|
||||
// TODO: you get it, also in a yml config
|
||||
|
||||
@@ -11,13 +11,9 @@ void ScopeBuffer::push(float 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
|
||||
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);
|
||||
for (size_t i = 0; i < out.size(); i++) {
|
||||
size_t idx = (w + trigger_ + i * wavelength_ / out.size()) % buffer_.size();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../ParameterStore.h"
|
||||
#include "../NoteQueue.h"
|
||||
#include "ParameterStore.h"
|
||||
#include "NoteQueue.h"
|
||||
#include "Envelope.h"
|
||||
#include "ScopeBuffer.h"
|
||||
#include "Filter.h"
|
||||
|
||||
@@ -101,7 +101,7 @@ float Voice::process(float* params, bool& scopeTrigger) {
|
||||
|
||||
// TODO: implement controls for noise
|
||||
//float scale = static_cast<float>(rand()) / static_cast<float>(RAND_MAX); // Range [0.0, 1.0]
|
||||
//float noise = -1.0f + 2.0f * scale;
|
||||
//float noise = (-1.0f + 2.0f * scale) * 0.2f;
|
||||
// these values didn't sound good so I commented them out before I get controls for them
|
||||
|
||||
// mix oscillators
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Oscillator.h"
|
||||
#include "Envelope.h"
|
||||
#include "Filter.h"
|
||||
#include "../ParameterStore.h"
|
||||
#include "ParameterStore.h"
|
||||
|
||||
#ifndef M_PI // I hate my stupid chungus life
|
||||
#define M_PI 3.14159265358979323846
|
||||
|
||||
@@ -6,12 +6,10 @@
|
||||
#include <fstream>
|
||||
|
||||
WavetableController::WavetableController() {
|
||||
// load from files
|
||||
|
||||
|
||||
// load from files
|
||||
init();
|
||||
|
||||
//std::cout << "wavetable init" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
void WavetableController::init() {
|
||||
@@ -23,11 +21,11 @@ void WavetableController::init() {
|
||||
wavetableFiles.push_back(entry.path());
|
||||
}
|
||||
}
|
||||
uint32_t wavetableCount = wavetableFiles.size();
|
||||
wavetables_.resize(wavetableCount);
|
||||
wavetableCount_ = wavetableFiles.size();
|
||||
wavetables_.resize(wavetableCount_);
|
||||
|
||||
// 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::ifstream inputFile(wavetableFiles[i], std::ios::in | std::ios::binary);
|
||||
if(!inputFile) std::cout << "error opening file" << std::endl;
|
||||
@@ -56,8 +54,8 @@ float WavetableController::sample(uint8_t wavetableIndex, float phase) {
|
||||
uint32_t index = static_cast<uint32_t>(round(scaledPhase));
|
||||
if(index >= SYNTH_WAVETABLE_SIZE) index = SYNTH_WAVETABLE_SIZE - 1;
|
||||
|
||||
if(wavetableIndex >= 4) {
|
||||
wavetableIndex = 3;
|
||||
if(wavetableIndex >= wavetableCount_) {
|
||||
wavetableIndex = wavetableCount_ - 1;
|
||||
} else if(wavetableIndex < 0) {
|
||||
wavetableIndex = 0;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
private:
|
||||
|
||||
std::vector<Wavetable> wavetables_;
|
||||
uint32_t wavetableCount_;
|
||||
|
||||
const std::filesystem::path wavetablesRoot_ = "./config/wavetables";
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "MainWindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
#include "SmartSlider/SmartSlider.h"
|
||||
#include "../ParameterStore.h"
|
||||
#include "ParameterStore.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
@@ -59,67 +58,19 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// rogue sliders, TODO: clean these up in a package
|
||||
connect(ui_->sliderMasterOctave, &SmartSlider::valueChanged,
|
||||
this, [this](float value) {
|
||||
audio_->parameters()->set(ParamId::MasterOctaveOffset, value);
|
||||
ui_->sliderMasterOctave->setResolution();
|
||||
});
|
||||
connect(ui_->sliderMasterSemitone, &SmartSlider::valueChanged,
|
||||
this, [this](float value) {
|
||||
audio_->parameters()->set(ParamId::MasterSemitoneOffset, value);
|
||||
ui_->sliderMasterSemitone->setResolution();
|
||||
});
|
||||
connect(ui_->sliderMasterPitch, &SmartSlider::valueChanged,
|
||||
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);
|
||||
});
|
||||
bindSlider(ui_->sliderMasterOctave, ParamId::MasterOctaveOffset, true);
|
||||
bindSlider(ui_->sliderMasterSemitone, ParamId::MasterSemitoneOffset, true);
|
||||
bindSlider(ui_->sliderMasterPitch, ParamId::MasterPitchOffset);
|
||||
bindSlider(ui_->sliderOsc1Octave, ParamId::Osc1OctaveOffset, true);
|
||||
bindSlider(ui_->sliderOsc1Semitone, ParamId::Osc1SemitoneOffset, true);
|
||||
bindSlider(ui_->sliderOsc1Pitch, ParamId::Osc1PitchOffset);
|
||||
bindSlider(ui_->sliderOsc2Octave, ParamId::Osc2OctaveOffset, true);
|
||||
bindSlider(ui_->sliderOsc2Semitone, ParamId::Osc2SemitoneOffset, true);
|
||||
bindSlider(ui_->sliderOsc2Pitch, ParamId::Osc2PitchOffset);
|
||||
bindSlider(ui_->sliderOsc3Octave, ParamId::Osc3OctaveOffset, true);
|
||||
bindSlider(ui_->sliderOsc3Semitone, ParamId::Osc3SemitoneOffset, true);
|
||||
bindSlider(ui_->sliderOsc3Pitch, ParamId::Osc3PitchOffset);
|
||||
|
||||
// synth business
|
||||
audio_->start();
|
||||
@@ -157,6 +108,7 @@ 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)
|
||||
// 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 osc1Node = configRoot["Osc1PitchOffset"];
|
||||
YAML::Node osc2Node = configRoot["Osc2PitchOffset"];
|
||||
@@ -209,3 +161,12 @@ void MainWindow::onResetClicked() {
|
||||
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,9 +4,10 @@
|
||||
#include <QMainWindow>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include "../ConfigInterface.h"
|
||||
#include "../synth/AudioEngine.h"
|
||||
#include "../MidiController.h"
|
||||
#include "ConfigInterface.h"
|
||||
#include "synth/AudioEngine.h"
|
||||
#include "MidiController.h"
|
||||
#include "SmartSlider/SmartSlider.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
@@ -29,6 +30,8 @@ private slots:
|
||||
|
||||
private:
|
||||
|
||||
void bindSlider(SmartSlider* slider, ParamId param, bool updateResolution = false);
|
||||
|
||||
Ui::MainWindow *ui_;
|
||||
|
||||
ParameterStore params_;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "../../ParameterStore.h"
|
||||
#include "ParameterStore.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class EnvelopeGenerator; }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "ui_Scope.h"
|
||||
|
||||
// TODO: fix include directories because what is this
|
||||
#include "../../../synth/ScopeBuffer.h"
|
||||
#include "synth/ScopeBuffer.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <iostream>
|
||||
|
||||
Reference in New Issue
Block a user