Showcase panel 21: silent until clicked: a Synth note (x sets the pitch), a Pluck, and a bar of Kick, Snare and HiHat in a Sequencer with its playhead and a Reverb on the master, with master.spectrum() and master.level() drawn live; needs kiln-gl[sound].
Try it live: run uv run python examples/showcase.py, then click panel 21, or see the showcase.
Effects turn a plain synth into a sound with a place and a character: echoes that bounce from left to right, a plate reverb’s shimmering tail, the wide chorus of a 1980s Juno, a flanger’s whoosh, a phaser’s swirl, warm or fuzzy drive, lo-fi crunch.
Effect
What it does
Its knobs (and mix)
kiln.Delay
echoes, stereo or ping-pong
time, feedback, tone, ping_pong
kiln.Reverb
a plate reverb (Dattorro’s)
size, decay, damping
kiln.Chorus
the Roland Juno-60’s chorus
rate, depth
kiln.Flanger
a very short, sweeping delay
rate, depth, feedback
kiln.Phaser
notches that sweep the spectrum
rate, depth, feedback
kiln.Drive
saturation, warm to fuzzy
drive
kiln.Bitcrush
fewer bits, a lower sample rate
bits, rate
You need the sound extra (pip install "kiln-gl[sound]"). As on the Sound page, the examples are recorded with with record(): and wait(seconds), and each recording is raised to a comfortable listening level. Most are mono; the ones where left and right matter are stereo, with the left channel drawn above the right.
Effects in a list
Give an instrument a list of effects with fx. Here a short pluck goes through a delay that echoes a dotted eighth note later, at 122 beats per minute:
import kilnwith record(): synth = kiln.Synth() synth.sustain, synth.decay =0.0, 0.15# a short pluck synth.fx = [kiln.Delay(time=60/122*0.75, feedback=0.45, mix=0.4)]for freq in (220, 262, 330, 392): synth.note_on(freq) wait(0.25) synth.note_off() wait(1.4) # the echoes ring on
Times are in seconds, so a tempo is one line of arithmetic: 60 / bpm is a beat, * 0.75 makes it a dotted eighth. feedback is how much of each echo comes back (each one is that much quieter), and mix goes from 0, the dry sound alone, to 1, the effect alone.
The first effect of each kind is compiled the first time you create one: a few seconds, once (it is cached after that). In a sketch, create your effects in setup(), not in draw() or when a key is pressed.
Effects run in list order: synth.fx = [kiln.Drive(), kiln.Delay()] drives the sound, then echoes it. Assign a new list whenever you like, even while notes play: effects that leave fade out and new ones fade in, over 20 ms, so it never clicks. synth.fx = [] takes them all off.
Ping-pong
With ping_pong=True the echoes bounce between the speakers: left, right, left. tone darkens each repeat, as tape and analog delays do (1 keeps them bright):
kiln.Reverb is a plate, the studio classic: Jon Dattorro’s design from 1997, a web of short delays that smears each note into a dense, smooth tail. decay is how many seconds the tail takes to die away (60 dB down), size how big the plate sounds, and damping how fast its highs fade:
The Roland Juno-60’s chorus is the sound of 1980s pads: a delay of a few milliseconds that a slow triangle wave sweeps, read in opposite directions for the left and the right, so the sound shimmers and spreads wide. rate 0.513 Hz is the Juno’s mode I, 0.863 Hz its mode II:
Both sweep notches through the spectrum. A flanger mixes the sound with a copy delayed by 0.3 to 4 ms, so the notches are evenly spaced, like a comb, and feedback makes them ring: the jet plane. A phaser runs the sound through four all-pass filters, so it has just two notches, spread wider: the swirl. In the pictures (spectrograms: time across, pitch up), watch the notches move. First the flanger, on a buzzy drone:
kiln.Drive pushes the sound into a soft curve, the way an overdriven amplifier does: a little drive warms it up, a lot makes it fuzzy, and either way it adds harmonics. Like every effect knob, drive glides when you change it, so you can turn it while the sound plays. Here a bass line gets dirtier note by note:
Kiln runs the drive at four times the sample rate with an anti-aliasing trick (antiderivative anti-aliasing), so even at full drive the new harmonics stay musical instead of folding back as harsh, out-of-tune grit.
Bitcrush
kiln.Bitcrush sounds like an old sampler or a game console: bits rounds every sample to fewer levels (4 bits is 16 levels), and rate holds each one for longer (no filter, so it aliases: that is the sound). Here the bits go from 8 down to 3:
synth.fx processes only that synth. kiln.master.fx processes everything you hear, after the instruments are mixed: one reverb for the whole sketch puts every instrument in the same room. Each instrument’s pan places it from left (-1) to right (1), with equal power, so a sound is as loud at the side as in the centre:
import kilnwith record(stereo=True): bass, lead = kiln.Synth(), kiln.Synth() bass.pan, bass.cutoff =-0.6, 500.0 lead.pan, lead.sustain, lead.decay =0.6, 0.0, 0.15 kiln.master.fx = [kiln.Reverb(decay=1.5, mix=0.25)] bass.note_on(110)for freq in (440, 523, 659, 523): lead.note_on(freq) wait(0.25) lead.note_off() bass.note_off() wait(1.0) kiln.master.fx = [] # (the next example is dry)
When a sketch’s window closes, kiln.master.fx empties, like the sequencers stop, so nothing a sketch started outlives it. kiln.master.gain, kiln.master.volume and the limiter’s settings also return to their defaults, so every run starts from the same sound. Settings made before kiln.run apply to that run; the next run in the same process sets them again (or sets them in setup).
Which volume knob?
Knob
Where it sits
Use it for
instrument.volume (0 to 1)
One instrument, before the mix
Balancing instruments against each other.
kiln.master.gain (dB)
The whole mix, before the limiter
Making the mix louder: push it into the limiter.
kiln.master.volume (0 to 1)
The whole mix, after the limiter
A final fader: turning everything down without changing how the limiter acts.
master.gain and master.volume reset when a run ends, as described above.
The limiter
After the master effects, every sound goes through Kiln’s limiter, which is always on. It watches the sound 2 ms ahead (its lookahead) and, just before a peak that would go over the ceiling (-1 dBFS: just under full scale), turns the volume down smoothly, just enough. It holds that gain through the rest of the note and lets it back up over its release, so a loud chord is turned down evenly, not distorted. It recovers fast, in about a tenth of a second, so a mix with heavy kicks gets a gentle pump on the beat: the sound dips with each kick and comes straight back, which is part of the sound. However many instruments you stack, nothing clips, and below the ceiling the sound passes through untouched, only 2 ms late.
Here a kick, a clap, a driven bass and two four-note pads all play at full volume, which is too loud: their peaks would go over full scale. The limiter keeps every one at -1 dBFS, and reduction says how much it turned the sound down (since you last asked):
import numpy as npimport kilnfrom kiln.sound.offline import renderkick, clap, bass = kiln.Kick(), kiln.Clap(), kiln.Synth(polyphony=1)pads = [kiln.Synth(), kiln.Synth()]for instrument in (kick, clap, bass, *pads): instrument.volume =1.0bass.drive =1.0bass.note_on(55)for pad, octave inzip(pads, (1, 2)):for freq in (110, 131, 165, 196): pad.note_on(freq * octave)for beat inrange(4): kick.hit()if beat %2: clap.hit() audio = render(60/122) peak =20* np.log10(np.abs(audio).max())print(f"beat {beat +1}: peak {peak:.2f} dBFS, turned down {-kiln.master.limiter.reduction:.1f} dB")bass.note_off()for pad in pads: pad.note_off()_ = render(0.5) # let them fade
beat 1: peak -1.00 dBFS, turned down 0.5 dB
beat 2: peak -1.00 dBFS, turned down 1.2 dB
beat 3: peak -1.00 dBFS, turned down 2.5 dB
beat 4: peak -1.00 dBFS, turned down 1.3 dB
Its settings are on kiln.master.limiter: ceiling in dBFS, release and lookahead in seconds (at most 5 ms; it is also the latency it adds).
A limiter is also how you make a mix loud. kiln.master.gain raises the whole mix by up to 24 dB just before the limiter (and lowers it by as much), and the limiter holds the peaks at the ceiling. A mix that peaks near -11 dBFS, pushed in by 12 dB, comes out at the ceiling with the limiter turning it down a little. The gain glides over 20 ms, so you can move it like a knob:
synth = kiln.Synth()synth.volume =0.6for freq in (110, 165, 220, 277): synth.note_on(freq)for gain in (0, 12): kiln.master.gain = gain # push the mix into the limiter _ = render(0.1) # let the gain settle kiln.master.limiter.reduction # (start the meter afresh) peak =20* np.log10(np.abs(render(0.3)).max())print(f"gain {gain:+d} dB: peak {peak:.2f} dBFS, turned down {-kiln.master.limiter.reduction:.1f} dB")kiln.master.gain =0synth.note_off()_ = render(0.5)
gain +0 dB: peak -11.04 dBFS, turned down 0.0 dB
gain +12 dB: peak -1.00 dBFS, turned down 2.8 dB
Try this
Play the effects with the mouse: across the screen, the delay’s feedback; up and down, how much reverb.