add wavetables
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
|
||||
#include "Oscillator.h"
|
||||
|
||||
Oscillator::Oscillator(WavetableController* wavetable) : wavetable_(wavetable) {
|
||||
|
||||
}
|
||||
|
||||
void Oscillator::setWavetable(uint8_t waveTableId) {
|
||||
activeWavetable_ = waveTableId;
|
||||
}
|
||||
@@ -20,33 +24,10 @@ float Oscillator::process(uint8_t note, bool& scopeTrigger) {
|
||||
|
||||
float Oscillator::process(float frequency, bool& scopeTrigger) {
|
||||
|
||||
float sampleOut = 0.0f;
|
||||
float pitchOffset = 0.5f;
|
||||
float phaseInc = pitchOffset * 2.0f * M_PI * frequency / sampleRate_;
|
||||
|
||||
switch (activeWavetable_) {
|
||||
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;
|
||||
}
|
||||
float sampleOut = wavetable_->sample(activeWavetable_, phase_);
|
||||
|
||||
phase_ += phaseInc;
|
||||
if (phase_ > 2.0f * M_PI) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WavetableController.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
@@ -13,12 +15,12 @@
|
||||
#define SYNTH_PITCH_STANDARD 440.0f // frequency of home pitch
|
||||
#define SYNTH_MIDI_HOME 69 // midi note index of home pitch
|
||||
#define SYNTH_NOTES_PER_OCTAVE 12
|
||||
#define SYNTH_WAVETABLE_SIZE 2048
|
||||
|
||||
class Oscillator {
|
||||
public:
|
||||
|
||||
Oscillator() = default;
|
||||
Oscillator(WavetableController* wavetable);
|
||||
~Oscillator() = default;
|
||||
|
||||
void setWavetable(uint8_t waveTableId);
|
||||
@@ -39,12 +41,7 @@ private:
|
||||
uint8_t activeWavetable_;
|
||||
float frequency_ = 220.0f;
|
||||
|
||||
// TODO: implement
|
||||
// TODO: wavetable class that can load from files
|
||||
// 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_;
|
||||
// wavetables
|
||||
WavetableController* wavetable_;
|
||||
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#endif
|
||||
|
||||
Synth::Synth(const ParameterStore& params) : paramStore_(params) {
|
||||
voices_.fill(Voice(params_.data()));
|
||||
voices_.fill(Voice(params_.data(), &wavetable_));
|
||||
}
|
||||
|
||||
void Synth::updateParams() {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ScopeBuffer.h"
|
||||
#include "Filter.h"
|
||||
#include "Voice.h"
|
||||
#include "WavetableController.h"
|
||||
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
@@ -54,4 +55,7 @@ private:
|
||||
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> lastTime;
|
||||
|
||||
// waveforms
|
||||
WavetableController wavetable_;
|
||||
|
||||
};
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
#include <cmath>
|
||||
#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
|
||||
@@ -82,9 +83,17 @@ float Voice::process(float* params, bool& scopeTrigger) {
|
||||
|
||||
// sample generation
|
||||
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
|
||||
float baseFreq = oscillators_[0].frequency();
|
||||
|
||||
@@ -25,7 +25,7 @@ class Voice {
|
||||
public:
|
||||
|
||||
Voice() = default;
|
||||
Voice(SmoothedParam* params);
|
||||
Voice(SmoothedParam* params, WavetableController* wavetable);
|
||||
~Voice() = default;
|
||||
|
||||
void setSampleRate(float sampleRate);
|
||||
@@ -67,6 +67,9 @@ private:
|
||||
// paramstore pointer
|
||||
SmoothedParam* params_;
|
||||
|
||||
// wavetables
|
||||
WavetableController* wavetable_;
|
||||
|
||||
// TODO: add a parameter in the paramstore for this
|
||||
float velocitySensitivity = 0.7f;
|
||||
float velocityCenter = 2.0f;
|
||||
|
||||
Reference in New Issue
Block a user