Created
February 21, 2021 16:05
-
-
Save jjylik/053daad19bb758b8bc1c497a4eb2433a to your computer and use it in GitHub Desktop.
SOUL patch with a simple sine synth with LFO detune
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
== SOUL example code == | |
== Author: Jules == | |
*/ | |
/// Title: A simple MPE sine-wave synthesiser example | |
/// | |
/// A simple sine-wave synthesiser featuring pitch-bend support, using a basic | |
/// envelope and voice-allocator. | |
// Modified from the example to add a detune LFO https://github.com/soul-lang/SOUL/tree/master/examples/patches/SineSynth | |
graph SineSynth [[ main ]] | |
{ | |
input smoothedGain.volume [[ name: "Volume", min: -40, max: 0, init: -6, step: 1 ]]; | |
input event soul::midi::Message midiIn; | |
input DetuneParamProcessor.detuneDepth [[ name: "Detune amount", min: 0, max: 100, init: 1, step: 1 ]]; | |
output stream float audioOut; | |
let | |
{ | |
voices = Voice[8]; | |
voiceAllocator = soul::voice_allocators::Basic(8); | |
smoothedGain = soul::gain::SmoothedGainParameter (0.5f); | |
gainProcessor = soul::gain::DynamicGain (float); | |
} | |
connection | |
{ | |
DetuneParamProcessor.detuneDepthOut -> SineOsc.detuneDepth; | |
midiIn -> soul::midi::MPEParser -> voiceAllocator; | |
// Plumb the voice allocator to the voices array | |
voiceAllocator.voiceEventOut -> voices.noteOn, | |
voices.noteOff, | |
voices.pitchBend; | |
DetuneParamProcessor.detuneDepthOut -> voices.detuneDepth; | |
// Sum the voices audio out to the output | |
voices -> gainProcessor.in; | |
smoothedGain -> gainProcessor.gain; | |
gainProcessor -> audioOut; | |
} | |
} | |
processor DetuneParamProcessor | |
{ | |
input event float detuneDepth; | |
output event float detuneDepthOut; | |
event detuneDepth (float newValue) | |
{ | |
detuneDepthScaled = newValue/10.0f; | |
onUpdate(); | |
} | |
float detuneDepthScaled = 0.0f; | |
void onUpdate() | |
{ | |
detuneDepthOut << detuneDepthScaled; | |
} | |
} | |
processor SineOsc | |
{ | |
input event | |
{ | |
soul::note_events::NoteOn noteOn; | |
soul::note_events::NoteOff noteOff; | |
soul::note_events::PitchBend pitchBend; | |
float detuneDepth; | |
} | |
input stream float detune; | |
output stream float audioOut; | |
event detuneDepth (float f) | |
{ | |
detuneAmountUsed = f; | |
} | |
event noteOn (soul::note_events::NoteOn e) | |
{ | |
notePitch = e.note; | |
bendSemitones = 0.0f; | |
calculatePhaseIncrement(); | |
} | |
event noteOff (soul::note_events::NoteOff e) {} | |
event pitchBend (soul::note_events::PitchBend e) | |
{ | |
bendSemitones = e.bendSemitones; | |
calculatePhaseIncrement(); | |
} | |
float notePitch, bendSemitones, phase, phaseIncrement; | |
float detuneAmountUsed = 1.0f; | |
void calculatePhaseIncrement() | |
{ | |
let noteFrequency = soul::noteNumberToFrequency (notePitch + bendSemitones); | |
phaseIncrement = float (noteFrequency * twoPi * processor.period); | |
} | |
void run() | |
{ | |
loop | |
{ | |
phase = addModulo2Pi (phase, phaseIncrement+(detune*detuneAmountUsed)); | |
audioOut << sin (phase); | |
advance(); | |
} | |
} | |
} | |
//============================================================================== | |
graph Voice | |
{ | |
input event | |
{ | |
soul::note_events::NoteOn noteOn; | |
soul::note_events::NoteOff noteOff; | |
soul::note_events::PitchBend pitchBend; | |
float detuneDepth; | |
} | |
output stream float audioOut; | |
namespace LFO = soul::oscillators::lfo; | |
let lfo = LFO::Processor (LFO::Shape::sine, LFO::Polarity::bipolar, 0.1f, 1.0f); | |
let | |
{ | |
amplitudeEnvelope = soul::envelope::FixedAttackReleaseEnvelope (0.2f, 0.02f, 0.1f); | |
attenuator = soul::gain::DynamicGain (float); | |
} | |
connection | |
{ | |
noteOn -> SineOsc.noteOn; | |
noteOff -> SineOsc.noteOff; | |
pitchBend -> SineOsc.pitchBend; | |
lfo.out -> SineOsc.detune; | |
noteOn, noteOff -> amplitudeEnvelope.noteIn; | |
SineOsc.audioOut -> attenuator.in; | |
amplitudeEnvelope.levelOut -> attenuator.gain; | |
attenuator -> audioOut; | |
detuneDepth -> SineOsc.detuneDepth; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment