add wavetables

This commit is contained in:
2026-01-17 15:56:39 -06:00
parent 198b7f0dde
commit be8cb0f890
7 changed files with 33 additions and 37 deletions

View File

@@ -86,6 +86,8 @@ qt_add_executable(metabolus
src/synth/Oscillator.h src/synth/Oscillator.h
src/synth/Voice.cpp src/synth/Voice.cpp
src/synth/Voice.h src/synth/Voice.h
src/synth/WavetableController.cpp
src/synth/WavetableController.h
resources/resources.qrc resources/resources.qrc
src/ui/widgets/SmartSlider/SmartSlider.cpp src/ui/widgets/SmartSlider/SmartSlider.cpp
src/ui/widgets/SmartSlider/SmartSlider.h src/ui/widgets/SmartSlider/SmartSlider.h

View File

@@ -1,6 +1,10 @@
#include "Oscillator.h" #include "Oscillator.h"
Oscillator::Oscillator(WavetableController* wavetable) : wavetable_(wavetable) {
}
void Oscillator::setWavetable(uint8_t waveTableId) { void Oscillator::setWavetable(uint8_t waveTableId) {
activeWavetable_ = waveTableId; activeWavetable_ = waveTableId;
} }
@@ -20,33 +24,10 @@ float Oscillator::process(uint8_t note, bool& scopeTrigger) {
float Oscillator::process(float frequency, bool& scopeTrigger) { float Oscillator::process(float frequency, bool& scopeTrigger) {
float sampleOut = 0.0f;
float pitchOffset = 0.5f; float pitchOffset = 0.5f;
float phaseInc = pitchOffset * 2.0f * M_PI * frequency / sampleRate_; float phaseInc = pitchOffset * 2.0f * M_PI * frequency / sampleRate_;
switch (activeWavetable_) { float sampleOut = wavetable_->sample(activeWavetable_, phase_);
case 0: // sine
sampleOut = std::sin(phase_) / 0.707f;
break;
case 1: // square
sampleOut = (phase_ >= M_PI) ? 1.0f : -1.0f;
break;
case 2: // saw
sampleOut = ((phase_ / M_PI) - 1.0f) / 0.577f;
break;
case 3: // triangle
if(phase_ <= M_PI/2.0f) {
sampleOut = phase_ * 2.0f/M_PI;
} else if(phase_ <= 3.0f*M_PI/2.0f) {
sampleOut = phase_ * -2.0f/M_PI + 2.0f;
} else {
sampleOut = phase_ * 2.0f/M_PI - 4.0f;
}
sampleOut /= 0.577f;
break;
default: // unreachable
break;
}
phase_ += phaseInc; phase_ += phaseInc;
if (phase_ > 2.0f * M_PI) { if (phase_ > 2.0f * M_PI) {

View File

@@ -1,6 +1,8 @@
#pragma once #pragma once
#include "WavetableController.h"
#include <cstdint> #include <cstdint>
#include <cmath> #include <cmath>
#include <array> #include <array>
@@ -13,12 +15,12 @@
#define SYNTH_PITCH_STANDARD 440.0f // frequency of home pitch #define SYNTH_PITCH_STANDARD 440.0f // frequency of home pitch
#define SYNTH_MIDI_HOME 69 // midi note index of home pitch #define SYNTH_MIDI_HOME 69 // midi note index of home pitch
#define SYNTH_NOTES_PER_OCTAVE 12 #define SYNTH_NOTES_PER_OCTAVE 12
#define SYNTH_WAVETABLE_SIZE 2048
class Oscillator { class Oscillator {
public: public:
Oscillator() = default; Oscillator() = default;
Oscillator(WavetableController* wavetable);
~Oscillator() = default; ~Oscillator() = default;
void setWavetable(uint8_t waveTableId); void setWavetable(uint8_t waveTableId);
@@ -39,12 +41,7 @@ private:
uint8_t activeWavetable_; uint8_t activeWavetable_;
float frequency_ = 220.0f; float frequency_ = 220.0f;
// TODO: implement // wavetables
// TODO: wavetable class that can load from files WavetableController* wavetable_;
// TODO: wavetables should be shared among the entire synth
std::array<float, SYNTH_WAVETABLE_SIZE> wavetable1_;
std::array<float, SYNTH_WAVETABLE_SIZE> wavetable2_;
std::array<float, SYNTH_WAVETABLE_SIZE> wavetable3_;
std::array<float, SYNTH_WAVETABLE_SIZE> wavetable4_;
}; };

View File

@@ -9,7 +9,7 @@
#endif #endif
Synth::Synth(const ParameterStore& params) : paramStore_(params) { Synth::Synth(const ParameterStore& params) : paramStore_(params) {
voices_.fill(Voice(params_.data())); voices_.fill(Voice(params_.data(), &wavetable_));
} }
void Synth::updateParams() { void Synth::updateParams() {

View File

@@ -7,6 +7,7 @@
#include "ScopeBuffer.h" #include "ScopeBuffer.h"
#include "Filter.h" #include "Filter.h"
#include "Voice.h" #include "Voice.h"
#include "WavetableController.h"
#include <vector> #include <vector>
#include <atomic> #include <atomic>
@@ -54,4 +55,7 @@ private:
std::chrono::time_point<std::chrono::high_resolution_clock> lastTime; std::chrono::time_point<std::chrono::high_resolution_clock> lastTime;
// waveforms
WavetableController wavetable_;
}; };

View File

@@ -3,8 +3,9 @@
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
Voice::Voice(SmoothedParam* params) : params_(params) { Voice::Voice(SmoothedParam* params, WavetableController* wavetable) : params_(params), wavetable_(wavetable) {
oscillators_.fill(Oscillator(wavetable_));
} }
// cascade sample rate to all descendant objects // cascade sample rate to all descendant objects
@@ -82,9 +83,17 @@ float Voice::process(float* params, bool& scopeTrigger) {
// sample generation // sample generation
uint8_t osc1Wave = (static_cast<uint8_t>(std::round(getParam(ParamId::Osc1WaveSelector1)))); uint8_t osc1Wave = (static_cast<uint8_t>(std::round(getParam(ParamId::Osc1WaveSelector1))));
oscillators_[0].setWavetable(osc1Wave); for(Oscillator& o : oscillators_) {
o.setWavetable(osc1Wave);
}
float sampleOut = oscillators_[0].process(note_, scopeTrigger) * gain; // TODO: oscillator pitch offset
bool temp = false;
float osc1 = oscillators_[0].process(note_, scopeTrigger);
float osc2 = oscillators_[1].process(static_cast<uint8_t>(note_+12), temp);
float osc3 = oscillators_[2].process(static_cast<uint8_t>(note_+19), temp);
float sampleOut = (osc1 + osc2*0.5f + osc3*0.25f) * gain;
// filter sample // filter sample
float baseFreq = oscillators_[0].frequency(); float baseFreq = oscillators_[0].frequency();

View File

@@ -25,7 +25,7 @@ class Voice {
public: public:
Voice() = default; Voice() = default;
Voice(SmoothedParam* params); Voice(SmoothedParam* params, WavetableController* wavetable);
~Voice() = default; ~Voice() = default;
void setSampleRate(float sampleRate); void setSampleRate(float sampleRate);
@@ -67,6 +67,9 @@ private:
// paramstore pointer // paramstore pointer
SmoothedParam* params_; SmoothedParam* params_;
// wavetables
WavetableController* wavetable_;
// TODO: add a parameter in the paramstore for this // TODO: add a parameter in the paramstore for this
float velocitySensitivity = 0.7f; float velocitySensitivity = 0.7f;
float velocityCenter = 2.0f; float velocityCenter = 2.0f;