164 lines
3.9 KiB
C++
164 lines
3.9 KiB
C++
/*
|
|
Peacock-8 VA polysynth
|
|
|
|
Copyright 2024 Gordon JC Pearce <gordonjcp@gjcp.net>
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
|
|
#define NUM_VOICES 8
|
|
class LFO {
|
|
public:
|
|
LFO();
|
|
void run();
|
|
int16_t lfoOut;
|
|
uint8_t rate;
|
|
|
|
private:
|
|
uint8_t
|
|
phase;
|
|
uint16_t holdoff;
|
|
uint16_t envelope;
|
|
enum { LFO_RUN,
|
|
LFO_HOLDOFF,
|
|
LFO_RAMP } delayPhase;
|
|
static const uint16_t lfoRateTable[128];
|
|
};
|
|
|
|
class Envelope {
|
|
public:
|
|
Envelope();
|
|
|
|
void run();
|
|
void on() {
|
|
phase = ENV_ATK;
|
|
}
|
|
|
|
void off() {
|
|
phase = ENV_RLS;
|
|
}
|
|
|
|
bool inRelease() {
|
|
return phase == ENV_RLS;
|
|
}
|
|
|
|
static uint16_t atk, dcy, stn, rls;
|
|
|
|
uint16_t level;
|
|
|
|
private:
|
|
static const uint16_t atkTable[128];
|
|
static const uint16_t dcyTable[128];
|
|
|
|
enum {
|
|
ENV_ATK,
|
|
ENV_DCY,
|
|
ENV_RLS,
|
|
ENV_IDLE
|
|
} phase;
|
|
};
|
|
|
|
class Voice {
|
|
public:
|
|
Voice();
|
|
uint8_t note = 0x3c; // middle C
|
|
void run(float *buffer, uint32_t pos, uint32_t samples);
|
|
void filter(float *buffer, uint32_t pos, uint32_t samples);
|
|
|
|
void update();
|
|
void on(uint8_t note);
|
|
void off();
|
|
|
|
// private:
|
|
Envelope env; // calculated envelope value
|
|
uint16_t pitch = 0x1818; // calculated pitch value with porta and master pitch etc
|
|
float delay = 0; // delay slot for polyblep
|
|
bool pulseStage = 0;
|
|
float pw = 0, lastpw = 0, pwrc = 0;
|
|
float subosc = -1;
|
|
float sub = 0, saw = 0;
|
|
float phase = 0, omega = 0;
|
|
enum { V_DONE,
|
|
V_OFF,
|
|
V_ON } voiceState;
|
|
|
|
void calcPitch();
|
|
|
|
float fb = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, cut = 0.1, reso = 4;
|
|
};
|
|
|
|
class Synth {
|
|
friend Envelope;
|
|
friend Voice;
|
|
|
|
public:
|
|
Synth();
|
|
void run();
|
|
void voiceOn(uint8_t voice, uint8_t note);
|
|
void voiceOff(uint8_t voice);
|
|
void sustainSwitch(uint8_t val);
|
|
void buildTables(double sampleRate);
|
|
|
|
double sampleRate;
|
|
uint32_t bufferSize;
|
|
uint16_t masterPitch; // sum of bend and LFO, plus any other pitch-setting value
|
|
// protected:
|
|
uint16_t envAtk, envDcy, envStn, envRls;
|
|
int8_t portaCoeff;
|
|
bool sustained;
|
|
double pitchTable[104];
|
|
double filterTable[256];
|
|
|
|
float *noise;
|
|
|
|
// private:
|
|
uint8_t vcoBend = 42;
|
|
uint8_t vcfBend = 42;
|
|
|
|
Voice voices[NUM_VOICES];
|
|
LFO lfo;
|
|
uint16_t pitchBend = 0x2000;
|
|
uint8_t modWheel = 0x00;
|
|
|
|
float pwm;
|
|
uint32_t tr21;
|
|
|
|
struct {
|
|
uint8_t lfoRate = 0x3f;
|
|
uint8_t lfoDelay = 0x00;
|
|
uint8_t vcoLfoMod = 0x00;
|
|
uint8_t pwmLfoMod = 0x27;
|
|
uint8_t noiseLevel = 0x00;
|
|
uint8_t vcfCutoff = 0x4d;
|
|
uint8_t vcfReso = 0x14;
|
|
uint8_t vcfEnvMod = 0x04;
|
|
uint8_t vcfLfoMod = 0x00;
|
|
uint8_t vcfKeyTrk = 0x6f;
|
|
uint8_t vcaLevel = 0x22;
|
|
uint8_t attack = 0x0d;
|
|
uint8_t decay = 0x57;
|
|
uint8_t sustain = 0x58;
|
|
uint8_t release = 0x23;
|
|
uint8_t subLevel = 0x0e;
|
|
uint8_t switch1 = 0x1a;
|
|
uint8_t switch2 = 0x10;
|
|
} patchRam;
|
|
const static uint16_t lfoDelayTable[8];
|
|
const static uint8_t lfoDepthTable[128];
|
|
const static uint8_t portaTable[128];
|
|
};
|