Faust: A Simple Envelope

Temporal envelopes are essential for many sound synthesis applications. Often, triggered envelopes are used, which can be started by a single trigger value. Faust offers a selection of useful envelopes in the envelopes library. The following example uses an attack-release envelope with exponential trajectories which can be handy for plucked sounds. The output of the sinusoid with fixed frequency is simply multiplied with the en.arfe() function.

Check the envelopes in the library list for more information and other envelopes:

https://faust.grame.fr/doc/libraries/#en.asr

// envelope.dsp
//
// A fixed frequency sine with
// a trigger and controllable release time.
//
// - mono (left channel only)
//
// Henrik von Coler
// 2020-05-07

import("stdfaust.lib");

// a simple trigger button
trigger  = button("Trigger");

// a slider for the release time
release  = hslider("Decay",0.5,0.01,5,0.01);

// generate a single sine and apply the arfe envelope
// the attack time is set to 0.01
process = os.osc(666) * 0.77 * en.arfe(0.01, release, 0,trigger) : _ ;

Additive & Spectral: Parabolic Interpolation

Quadratic Interpolation

The detection of local maxima in a spectrum is limited to the DFT support points without further processing. The following example shows this for a 25 Hz sinusoid at a sampling rate of 100 Hz.

Quadratic or parabolic interpolation can be used to estimate the true peak of the sinusoid. using the detected maximum $a$ and its upper and lower frequency bin.

$p = 0.5 (\alpha-\gamma)/(\alpha-2\beta+\gamma)$

$a^* = \beta-1/4(\alpha-\gamma)$

More details on JOS Website

Waveguide with Excitation Input

This example is a first step towards excitation-continuous instruments, such as wind instruments. Instead of initializing the waveguides with a single excitation function, they are fed with an input signal.

// waveguide_input.dsp
//
// waveguide with excitation by input signal
//
// - one-pole lowpass termination
//
// Henrik von Coler
// 2020-11-19

import("all.lib");

// use '(pm.)l2s' to calculate number of samples
// from length in meters:

segment(maxLength,length) = waveguide(nMax,n)
with{
    nMax = maxLength : l2s;
    n = length : l2s/2;
};



// one lowpass terminator
fc = hslider("lowpass",1000,10,10000,1);
rt = rTermination(basicBlock,*(-1) : si.smooth(1.0-2*(fc/ma.SR)));

// one gain terminator with control
gain = hslider("gain",0.5,0,1,0.01);
lt = lTermination(*(-1)* gain,basicBlock);

// a simple allpass (Smith Paper)
s = hslider("s",0.9,0,0.9,0.01);
c = hslider("c",0.9,0,0.9,0.01);
allpass = _ <: *(s),(*(c):(+:_)~(*(-s))):_, mem*c:+;


// another allpass
g = hslider("g",0.9, 0,0.9,0.01);
allp = allpass_comb(2,1,g);


scatter = pm.basicBlock(allpass);



idString(length,pos,excite) = endChain(wg)
with{

    nUp   = length*pos;
    nDown = length*(1-pos);

    wg = chain(lt : segment(6,nUp) : out : in(excite) : scatter : segment(6,nDown) :  rt); // waveguide chain
};

exc = select2(gain>0.9,1,0);

length = hslider("length",1,0.1,10,0.01):si.smoo;

process(in) = idString(length,0.15, in) <: _,_;

Envelopes: Exponential

For percussive, plucked or struck instrument sounds, the envelope needs to model an exponential decay. This is very useful for string-like sounds but most importantly for most electronic musicians, it is the very core of kick drum sounds.

In contrast to the ADSR envelope, the exponential one does not contain a sustain portion for holding a sound. The only parameter is the decay rate, allowing quick adjustment. Alternative to an actual exponential, a modified reciprocal function can be used for easier implementation. The factor $d$ controls the rate of the decay, respectively the decay time:

$$ e = \frac{1}{(1+(d t))} $$


The following example adds a short linear attack before the exponential decay. This minimizes clicks which otherwise occur through the rapid step from $0$ to $1$:

Your browser does not support the HTML5 canvas tag

Attack Time:

Decay Time:

Controlling SC with the Mouse

A quick way of control is often needed when testing and designing synthesis and processing algorithms in SuperCollider. One quick way is to map the mouse position to control rate buses. Combined with a touch display, this can even be an interesting means for expressive control. This example first creates a control bus with two channels. The node ~mouse uses the MouseX and MouseY UGens to influence the two channels of this bus:

// mouse xy controll with busses
~mouse_BUS = Bus.control(s,2);

~mouse   = {
  Out.kr(~mouse_BUS.index,   MouseX.kr(0,1));
  Out.kr(~mouse_BUS.index+1, MouseY.kr(0,1));
}.play;

Exercise

Exercise

Use the mouse example with the previous sawtooth-filter example to control pitch and filter characteristics.

Digital Waveguides: String with Losses

Introducing Losses

Real strings, however, introduce losses when reflecting the waves at either end. These losses are caused be the coupling between string and body, as well as the resonant behavior of the body itself. Thus, they contribute significantly to the individual sound of an instrument. In physical modeling, these losses can be implemented by inserting filters between the delay lines:


Plucked String Sound

The result of the waveguide synthesis has the characteristics of a plucked string with a crisp onset and a sinusoidal decay:


Smoothing

With an additional lowpass between the waveguides, the signal will get smoother with every iteration, resulting in a crisp onset with a sinusoidal decay. This example works with a basic moving average filter (FIR with boxcar frequency response) with a length of $N=20$. The slow version shows the smoothing of the excitation function for both delay lines even during the first iterations:



Once Loop Reflect