Skip to content

Instantly share code, notes, and snippets.

@oshibka404
Created May 10, 2020 13:31
Show Gist options
  • Save oshibka404/3bd74981fc2674a598b4a0ddc0ff2589 to your computer and use it in GitHub Desktop.
Save oshibka404/3bd74981fc2674a598b4a0ddc0ff2589 to your computer and use it in GitHub Desktop.
Perfect First Synthesizer MVP
declare name "Perfect First Synth";
declare author "Andrey Ozornin";
declare copyright "Aesthetics Engineering";
declare version "0.01";
declare license "BSD";
declare options "[midi:on][nvoices:5]";
import("stdfaust.lib");
hide(x) = tgroup("Hidden", x);
gate = hide(button("gate"));
f = hide(nentry("freq",200,50,1000,0.01));
bend = nentry("bend[midi:pitchwheel]",1,0,10,0.01) : si.polySmooth(gate,0.999,1);
freq = f*bend;
gain = hide(nentry("gain",0.5,0,1,0.01));
/**
UI
**/
rootGroup(x) = hgroup("Perfect First Synth", x);
oscGroup(x) = rootGroup(vgroup("[0]Oscillators", x));
filterGroup(x) = rootGroup(hgroup("[1]Filters", x));
fxGroup(x) = rootGroup(vgroup("[2]Effects", x));
// Oscillators
squareGroup(x) = oscGroup(hgroup("[0]Square", x));
sawGroup(x) = oscGroup(hgroup("[1]Saw", x));
noiseGroup(x) = oscGroup(hgroup("[2]Noise", x));
squareSwitch = squareGroup(1 - checkbox("[0]Disable"));
squareAttackSlider = squareGroup(hslider("[1]Attack[unit:sec.][style:knob][scale:log]", 0.2, 0.01, 10, 0.01));
squareDecaySlider = squareGroup(hslider("[2]Decay[unit:sec.][style:knob][scale:log]", 0.8, 0.01, 10, 0.01));
squareSustainSlider = squareGroup(hslider("[3]Sustain[unit:%][style:knob]", 20, 0, 100, 1) / 100);
squareReleaseSlider = squareGroup(hslider("[4]Release[unit:sec.][style:knob][scale:log]", 0.2, 0.01, 10, 0.01));
squareLevelSlider = squareGroup(hslider("[5]Level[style:knob]", 50, 0, 100, 1) / 100);
sawSwitch = sawGroup(1 - checkbox("[0]Disable"));
sawAttackSlider = sawGroup(hslider("[1]Attack[unit:sec.][style:knob][scale:log]", 1, 0.01, 10, 0.01));
sawDecaySlider = sawGroup(hslider("[2]Decay[unit:sec.][style:knob][scale:log]", 1, 0.01, 10, 0.01));
sawSustainSlider = sawGroup(hslider("[3]Sustain[unit:%][style:knob]", 40, 0, 100, 1) / 100);
sawReleaseSlider = sawGroup(hslider("[4]Release[unit:sec.][style:knob][scale:log]", 0.5, 0.01, 10, 0.01));
sawLevelSlider = sawGroup(hslider("[5]Level[style:knob][style:knob]", 50, 0, 100, 1) / 100);
noiseSwitch = noiseGroup(1 - checkbox("[0]Disable"));
noiseAttackSlider = noiseGroup(hslider("[1]Attack[unit:sec.][style:knob][scale:log]", 0.01, 0.01, 10, 0.01));
noiseDecaySlider = noiseGroup(hslider("[2]Decay[unit:sec.][style:knob][scale:log]", 0.4, 0.01, 10, 0.01));
noiseSustainSlider = noiseGroup(hslider("[3]Sustain[unit:%][style:knob]", 0, 0, 100, 1) / 100);
noiseReleaseSlider = noiseGroup(hslider("[4]Release[unit:sec.][style:knob][scale:log]", 0.2, 0.01, 10, 0.01));
noiseLevelSlider = noiseGroup(hslider("[5]Level[style:knob][style:knob]", 30, 0, 100, 1) / 100);
// Filters
lpfGroup(x) = filterGroup(hgroup("[0]Low pass", x));
hpfGroup(x) = filterGroup(hgroup("[1]High pass", x));
// lpf
lpfLeftColumn(x) = lpfGroup(vgroup("[0]level", x));
lpfRightColumn(x) = lpfGroup(vgroup("[1]envelope", x));
lpfSwitch = lpfLeftColumn(1 - checkbox("[0]Disable"));
lpfCutFreq = lpfLeftColumn(vslider("[1]Cutoff frequency[unit:Hz.][scale:log]", 2000, 20, 20000, 1));
lpfAttackSlider = lpfRightColumn(hslider("[0]Attack[unit:sec.][style:knob][scale:log]", 1, 0.01, 10, 0.01));
lpfDecaySlider = lpfRightColumn(hslider("[1]Decay[unit:sec.][style:knob][scale:log]", 2, 0.01, 10, 0.01));
lpfSustainSlider = lpfRightColumn(hslider("[2]Sustain[unit:%][style:knob]", 50, 0, 100, 1) / 100);
lpfReleaseSlider = lpfRightColumn(hslider("[3]Release[unit:sec.][style:knob][scale:log]", 1, 0.01, 10, 0.01));
// hpf
hpfLeftColumn(x) = hpfGroup(vgroup("[0]level", x));
hpfRightColumn(x) = hpfGroup(vgroup("[1]envelope", x));
hpfSwitch = hpfLeftColumn(1 - checkbox("[0]Disable"));
hpfCutFreq = hpfLeftColumn(vslider("[1]Cutoff frequency[unit:Hz.][scale:log]", 50, 20, 20000, 1));
hpfAttackSlider = hpfRightColumn(hslider("[0]Attack[unit:sec.][style:knob][scale:log]", 3, 0.01, 10, 0.01));
hpfDecaySlider = hpfRightColumn(hslider("[1]Decay[unit:sec.][style:knob][scale:log]", 2, 0.01, 10, 0.01));
hpfSustainSlider = hpfRightColumn(hslider("[2]Sustain[unit:%][style:knob]", 50, 0, 100, 1) / 100);
hpfReleaseSlider = hpfRightColumn(hslider("[3]Release[unit:sec.][style:knob][scale:log]", 1, 0.01, 10, 0.01));
// FX
reverbSlider = fxGroup(hslider("[0]Reverb[style:knob]", 0.5,0,1,0.01) : si.smoo);
delayTimeSlider = fxGroup(hslider("[1]Delay time[style:knob][scale:log]", 1, 0, 6, 0.01));
delayLevelSlider = fxGroup(hslider("[2]Delay level[style:knob]", 0.5, 0, 1, 0.01));
/**
DSP
**/
// set to 0 when disabled
squareLevel = (squareLevelSlider * squareSwitch);
sawLevel = (sawLevelSlider * sawSwitch);
noiseLevel = (noiseLevelSlider * noiseSwitch);
totalOscLevel = (sawLevel + squareLevel + noiseLevel + .001); // +.001 to avoid division by zero
// Oscillators
squareOsc = os.square(freq);
sawOsc = os.sawtooth(freq);
noiseOsc = no.noise;
// Envelopes
squareEnvelope = en.adsr(squareAttackSlider, squareDecaySlider, squareSustainSlider, squareReleaseSlider, gate) * gain;
sawEnvelope = en.adsr(sawAttackSlider, sawDecaySlider, sawSustainSlider, sawReleaseSlider, gate) * gain;
noiseEnvelope = en.adsr(noiseAttackSlider, noiseDecaySlider, noiseSustainSlider, noiseReleaseSlider, gate) * gain;
// Osc leveling
squareOutput = (squareOsc * squareLevel * squareEnvelope);
sawOutput = (sawOsc * sawLevel * sawEnvelope);
noiseOutput = (noiseOsc * noiseLevel * noiseEnvelope);
// Filters
lpf = fi.lowpass(1, lpfCutFreq);
lpfEnvelope = en.adsr(lpfAttackSlider, lpfDecaySlider, lpfSustainSlider, lpfReleaseSlider, gate) * lpfSwitch;
lpfBlock = _ <: (lpf, _) : (*(lpfEnvelope), *(1 - lpfEnvelope)) :> _;
hpf = fi.highpass(1, hpfCutFreq);
hpfEnvelope = en.adsr(hpfAttackSlider, hpfDecaySlider, hpfSustainSlider, hpfReleaseSlider, gate) * hpfSwitch;
hpfBlock = _ <: (hpf, _) : (*(hpfEnvelope), *(1 - hpfEnvelope)) :> _;
delay = ef.echo(100, delayTimeSlider, delayLevelSlider);
reverb = _ <: _,_ <: re.zita_rev1_stereo(60,200,6000,3,2,48000.0), _,_ :> *(reverbSlider), *(reverbSlider), *(1 - reverbSlider), *(1 - reverbSlider) :> _,_; // TODO: refactor this line
oscOutput = ((squareOutput + sawOutput + noiseOutput) / totalOscLevel);
filters = lpfBlock : hpfBlock;
fx = delay <: reverb;
process = oscOutput : filters : fx;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment