New slider design in GUI, LUT for filter frequency

main
Thor 1 year ago
parent 2f528ca33c
commit b933f936f8
  1. 5
      CMakeLists.txt
  2. 10
      include/ccslider.h
  3. 21
      include/synth/dsp/filter.h
  4. 2
      include/synthframe.h
  5. 8
      src/ccslider.cpp
  6. 30
      src/genluts.cpp
  7. 6
      src/synth/dsp/filterlut.cpp
  8. 6
      src/synth/preset.cpp
  9. 53
      src/synthframe.cpp

@ -20,6 +20,7 @@ endif()
add_executable(main
src/synthapp.cpp
src/synthframe.cpp
src/ccslider.cpp
src/synth/synth.cpp
src/synth/voicemanager.cpp
src/synth/channel.cpp
@ -27,9 +28,13 @@ add_executable(main
src/synth/voice.cpp
src/synth/dsp/oscillator.cpp
src/synth/dsp/filter.cpp
src/synth/dsp/filterlut.cpp
src/synth/dsp/adsr.cpp)
target_include_directories(main PRIVATE include)
add_executable(genluts src/genluts.cpp)
target_include_directories(genluts PRIVATE include)
if(MSVC)
target_compile_options(main PRIVATE /fp:fast)
else()

@ -0,0 +1,10 @@
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
class CCSlider : public wxPanel {
public:
CCSlider(wxWindow* parent, wxWindowID id, int value, const wxString& label);
};

@ -3,12 +3,28 @@
/* CEM3320/Oberheim/Phrophet-style filter as described here: https://arxiv.org/pdf/2111.05592.pdf */
#include <math.h>
#include <cmath>
#include <cfloat>
#include "util.h"
#define FILTER_K_BASE 6.214608098422192
#define KLUT_SIZE 64
extern float klut[KLUT_SIZE];
inline float freqToK(float x) {
float intPart;
float fracPart = modf(x * (KLUT_SIZE - 1), &intPart);
int index = (int) intPart;
if(fracPart < FLT_EPSILON) {
return klut[index];
} else {
return (1 - fracPart) * klut[index] + fracPart * klut[index + 1];
}
return klut[(int) roundf((KLUT_SIZE - 1) * x)];
}
inline float noteToK(float note) {
return ((note - 69) / 12.0) / (FILTER_K_BASE * M_LOG2E);
}
@ -71,7 +87,8 @@ public:
inline float tick(float in, float freqAdd) {
float freq = clamp(settings->freq + freqAdd, 0, 1);
float kK = tan(M_PI_4 * clamp(0.002 * exp(freq * FILTER_K_BASE), 0, 1));
//float kK = tan(M_PI_4 * clamp(0.002 * exp(freq * FILTER_K_BASE), 0, 1));
float kK = freqToK(freq);
float kQ = M_SQRT1_2 + settings->res;
SVF12::Output outA = fltA.tick(in, kK, kQ);

@ -38,6 +38,8 @@ private:
LFO_FILTER_SLIDER
};
wxSlider* addCCSlider(wxWindow* parent, wxSizer* sizer, wxWindowID id, const wxString& label, uint8_t value);
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);

@ -0,0 +1,8 @@
#include "ccslider.h"
CCSlider::CCSlider(wxWindow* parent, wxWindowID id, int value, const wxString& label) : wxPanel(parent) {
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
SetSizer(sizer);
sizer->Add(new wxSlider(this, id, value, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE), 1, wxEXPAND);
sizer->Add(new wxStaticText(this, wxID_ANY, label));
}

@ -0,0 +1,30 @@
#include <stdio.h>
#include <math.h>
#include "synth/dsp/filter.h"
int main(int argc, char** argv) {
FILE* f;
float klut[KLUT_SIZE];
for(int i = 0; i < KLUT_SIZE; ++i) {
klut[i] = tan(M_PI_4 * 0.002 * exp(i / (KLUT_SIZE - 1.0) * FILTER_K_BASE));
}
f = fopen("src/synth/dsp/filterlut.cpp", "w");
fputs("float klut[] = {\n", f);
for(int i = 0; i < KLUT_SIZE; ++i) {
if(i % 16 == 0) {
fputs(" ", f);
}
fprintf(f, "%.7f", klut[i]);
if(i < KLUT_SIZE - 1) {
fputs(", ", f);
}
if(i % 16 == 15) {
putc('\n', f);
}
}
fputs("};\n", f);
fclose(f);
}

@ -0,0 +1,6 @@
float klut[] = {
0.0015708, 0.0017336, 0.0019134, 0.0021118, 0.0023307, 0.0025723, 0.0028390, 0.0031333, 0.0034582, 0.0038167, 0.0042124, 0.0046491, 0.0051311, 0.0056631, 0.0062502, 0.0068982,
0.0076134, 0.0084028, 0.0092740, 0.0102355, 0.0112968, 0.0124681, 0.0137608, 0.0151877, 0.0167625, 0.0185007, 0.0204193, 0.0225369, 0.0248743, 0.0274544, 0.0303024, 0.0334462,
0.0369167, 0.0407480, 0.0449779, 0.0496483, 0.0548053, 0.0605004, 0.0667905, 0.0737388, 0.0814158, 0.0898997, 0.0992782, 0.1096492, 0.1211226, 0.1338222, 0.1478880, 0.1634790,
0.1807770, 0.1999912, 0.2213640, 0.2451794, 0.2717728, 0.3015462, 0.3349871, 0.3726965, 0.4154281, 0.4641461, 0.5201120, 0.5850177, 0.6611994, 0.7519926, 0.8623521, 1.0000000
};

@ -10,7 +10,7 @@ const Preset DEFAULT_PRESET = {
.filter = {
.type = Filter::TYPE_LP,
.slope = Filter::SLOPE_24,
.freq = 45,
.freq = 64,
.Q = 50,
},
@ -28,9 +28,9 @@ const Preset DEFAULT_PRESET = {
.release = 100
},
.modEnvFltGain = 40,
.modEnvFltGain = 56,
.keyTrack = 127,
.lfoFreq = 64,
.lfoPitchMod = 0,
.lfoPitchMod = 16,
.lfoFltMod = 64
};

@ -6,6 +6,8 @@
#include "synthframe.h"
#include "synthapp.h"
#include "ccslider.h"
wxDECLARE_APP(SynthApp);
SynthFrame::SynthFrame() : wxFrame(NULL, wxID_ANY, "Hello World") {
@ -28,30 +30,33 @@ SynthFrame::SynthFrame() : wxFrame(NULL, wxID_ANY, "Hello World") {
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
panel->SetSizer(sizer);
sizer->Add(new wxSlider(panel, OSC_DET_SLIDER, DEFAULT_PRESET.oscDetune, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, OSC2_PIT_SLIDER, DEFAULT_PRESET.osc2Pitch, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->AddSpacer(20);
sizer->Add(new wxSlider(panel, FLT_FREQ_SLIDER, DEFAULT_PRESET.filter.freq, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, FLT_Q_SLIDER, DEFAULT_PRESET.filter.Q, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->AddSpacer(20);
sizer->Add(new wxSlider(panel, KEY_TRACK_SLIDER, DEFAULT_PRESET.keyTrack, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->AddSpacer(20);
sizer->Add(new wxSlider(panel, AMP_ATTACK_SLIDER, DEFAULT_PRESET.ampEnv.attack, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, AMP_DECAY_SLIDER, DEFAULT_PRESET.ampEnv.decay, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, AMP_SUSTAIN_SLIDER, DEFAULT_PRESET.ampEnv.sustain, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, AMP_RELEASE_SLIDER, DEFAULT_PRESET.ampEnv.release, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->AddSpacer(20);
sizer->Add(new wxSlider(panel, MOD_ATTACK_SLIDER, DEFAULT_PRESET.modEnv.attack, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, MOD_DECAY_SLIDER, DEFAULT_PRESET.modEnv.decay, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, MOD_SUSTAIN_SLIDER, DEFAULT_PRESET.modEnv.sustain, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, MOD_RELEASE_SLIDER, DEFAULT_PRESET.modEnv.release, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->AddSpacer(20);
sizer->Add(new wxSlider(panel, MOD_ENV_FLT_SLIDER, DEFAULT_PRESET.modEnvFltGain, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->AddSpacer(20);
sizer->Add(new wxSlider(panel, LFO_FREQ_SLIDER, DEFAULT_PRESET.lfoFreq, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, LFO_PITCH_SLIDER, DEFAULT_PRESET.lfoPitchMod, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->Add(new wxSlider(panel, LFO_FILTER_SLIDER, DEFAULT_PRESET.lfoFltMod, 0, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE));
sizer->AddStretchSpacer();
sizer->Add(new CCSlider(panel, OSC_DET_SLIDER, DEFAULT_PRESET.oscDetune, "Det"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, OSC2_PIT_SLIDER, DEFAULT_PRESET.osc2Pitch, "2nd"), 1, wxEXPAND);
sizer->AddStretchSpacer();
sizer->Add(new CCSlider(panel, FLT_FREQ_SLIDER, DEFAULT_PRESET.filter.freq, "Frq"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, FLT_Q_SLIDER, DEFAULT_PRESET.filter.Q, "Res"), 1, wxEXPAND);
sizer->AddStretchSpacer();
sizer->Add(new CCSlider(panel, KEY_TRACK_SLIDER, DEFAULT_PRESET.keyTrack, "Key"), 1, wxEXPAND);
sizer->AddStretchSpacer();
sizer->Add(new CCSlider(panel, AMP_ATTACK_SLIDER, DEFAULT_PRESET.ampEnv.attack, "aA"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, AMP_DECAY_SLIDER, DEFAULT_PRESET.ampEnv.decay, "aD"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, AMP_SUSTAIN_SLIDER, DEFAULT_PRESET.ampEnv.sustain, "aS"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, AMP_RELEASE_SLIDER, DEFAULT_PRESET.ampEnv.release, "aR"), 1, wxEXPAND);
sizer->AddStretchSpacer();
sizer->Add(new CCSlider(panel, MOD_ATTACK_SLIDER, DEFAULT_PRESET.modEnv.attack, "mA"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, MOD_DECAY_SLIDER, DEFAULT_PRESET.modEnv.decay, "mD"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, MOD_SUSTAIN_SLIDER, DEFAULT_PRESET.modEnv.sustain, "mS"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, MOD_RELEASE_SLIDER, DEFAULT_PRESET.modEnv.release, "mR"), 1, wxEXPAND);
sizer->AddStretchSpacer();
sizer->Add(new CCSlider(panel, MOD_ENV_FLT_SLIDER, DEFAULT_PRESET.modEnvFltGain, "Env"), 1, wxEXPAND);
sizer->AddStretchSpacer();
sizer->Add(new CCSlider(panel, LFO_FREQ_SLIDER, DEFAULT_PRESET.lfoFreq, "LFO"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, LFO_PITCH_SLIDER, DEFAULT_PRESET.lfoPitchMod, "Pit"), 1, wxEXPAND);
sizer->Add(new CCSlider(panel, LFO_FILTER_SLIDER, DEFAULT_PRESET.lfoFltMod, "Flt"), 1, wxEXPAND);
sizer->AddStretchSpacer();
this->FitInside();
Bind(wxEVT_MENU, &SynthFrame::OnAbout, this, wxID_ABOUT);
Bind(wxEVT_MENU, &SynthFrame::OnExit, this, wxID_EXIT);

Loading…
Cancel
Save