>400 subscribers
Share Dialog
Share Dialog


In last nights post I demonstrated how you can use external data (the blockchain) to control the events of a supercollider musical routine. But what that article had in technical insights, it lacked in musicality. So in this article we will remedy that by designing some instruments and testing them out with some musical patterns.
Any band worth listening to has a variety of instruments that play different roles and occupy different sonic ranges. The drums and bass guitar provide the backbone of the music by setting the tempo and energy levels, and giving a foundation for the melodic instruments to build on top of. The guitar and keys are both percussive instruments that occupy a more mid- to high-frequency sonic range.
However this isnt a band. This is all going to be synthesized. Its electronic music, so we can get more creative with our instrumentation.
Heres a short list of Percussion instruments I'd like to define with code for later use:
Soft and Hard Kick,
Snare,
High hat,
Toms,
Clap
And for melodic parts, we'll need a few more Synthdefs from which we can make different instruments:
Frequency Modulation (FM) Synth
Karplus-Strong (Plucked string) Synth
Granular synth (for textures)
Subtractive synth (like your usual classic synthesizer)
Additive synth (like an organ with different harmonic tones added together)
Drone synth with feedback
That is more than enough to start with. Realistically we dont need all of these - a well designed FM synthdef could alone possibly emulate the entire band. So for today, I'll focus on making a versatile FM synthesizer.
SynthDef(\mx_kick, {
arg out = 0, freq = 60, dur=0.3, pitchDur = 0.03, pitchDepth = 0.9, gate = 1, amp=0.6
, noiseAmp=0.03, drive=1;
var ampenv, pitchenv, sig;
ampenv = EnvGen.kr(Env.perc(0.01, dur, amp, -4), gate, doneAction: 2);
// main kick tone, with a pitch envelope
sig = LFPar.ar(
freq + Line.kr(pitchDepth * freq, 0, pitchDur),
0, ampenv);
// Adding a little click to the kick
sig = sig + (
WhiteNoise.ar(ampenv * noiseAmp)
* EnvGen.kr(Env.perc(0.005,0.01))
);
sig = sig * drive;
sig = sig.tanh;
Out.ar(out, sig ! 2);
}).add;A good kick drum synth has a few elements to it. A basic tone is the foundation. Rather than a clean sine-wave, I prefer a low-frequency LFPar to a SinOsc because it has more harmonic structure and can be filtered and overdriven with better results. A kick drum sound will also have that kick at the beginning, so we will need a pitch envelope and an amplitude envelope. In addition, lets add a little click for extra percussion, and handle overdriven sounds at the end with tanh.
Then we can use this single kick drum SynthDef to make several different types of kicks:
clicky clean short kick:
Synth(\mx_kick, [\dur,0.23, \pitchDepth, 4, \pitchDur, 0.02, \noiseAmp, 0.1])
Shallow pitched long kick:
Synth(\mx_kick, [\dur,1, \pitchDepth, 0.2, \pitchDur, 0.2])
Hardcore kick:
Synth(\mx_kick, [\dur,1, \pitchDepth, 0.2, \pitchDur, 0.4, \drive, 30])
SynthDef(\snare, {
|out=0, toneFreq=180, noiseMix=0.5, decayTime=0.2|
var env, tone, noise, sig;
env = Env.perc(0.005, decayTime, 1, -4).kr(2);
tone = SinOsc.ar(toneFreq, 0, env);
noise = WhiteNoise.ar(env);
sig = Mix([tone, noise * noiseMix]);
Out.ar(out, sig ! 2);
}).add;This snare is a simple mix of a sine tone and noise, with a controllable tone freq, mix, and decay time. You can test out different snare sounds with Synth like we did with the kick drums.
SynthDef(\hihat, {
|out=0, freq=7500, rq=0.2, decayTime=0.1|
var env, noise, sig;
env = Env.perc(0.001, decayTime, 1, -4).kr(2);
noise = WhiteNoise.ar(env);
sig = BPF.ar(noise, freq, rq);
Out.ar(out, sig ! 2);
}).add;SynthDef(\tom, {
|out=0, freq=70, decayTime=0.6, depth=0.2, pitchDur=0.2|
var env, sig;
env = Env.perc(0.01, decayTime, 1, -4).kr(2);
sig = LFCub.ar(
freq + Line.kr(depth * freq, 0, pitchDur),
0, env);
Out.ar(out, sig ! 2);
}).add;SynthDef(\clap, {
|out=0, decayTime=0.1|
var env, noise, sig;
env = Env.perc(0.001, decayTime, 1, -4).kr(2);
noise = WhiteNoise.ar(env);
sig = CombN.ar(noise, 0.2, [0.093, 0.04]);
Out.ar(out, sig ! 2);
}).add;The CombN is a delay line which simulates the clap by repeating the percussive noise sound. This is a very simple and not especially great clap sound to be honest, but its something to work with for now.
SynthDef(\simpleFM, { |out = 0, gate = 1, freq = 440, carAmp = 0.5, modFreqRatio=2, modAmp = 0.3, attackCar = 0.01, decayCar = 1, sustainCar = 0.3, releaseCar = 0.5, attackMod = 0.01, decayMod = 1, sustainMod = 0.3, releaseMod = 0.5|
var modulator, carrier, modEnv, carEnv, sig;
// Envelopes for modulator and carrier
modEnv = EnvGen.kr(Env.adsr(attackMod, decayMod, sustainMod, releaseMod), gate, doneAction: 2);
carEnv = EnvGen.kr(Env.adsr(attackCar, decayCar, sustainCar, releaseCar), gate, doneAction: 2);
// Modulator oscillator
modulator = SinOsc.ar(freq*modFreqRatio, 0, modEnv * modAmp* modFreqRatio); // Frequency is set to twice the base frequency for a harmonically related modulation
// Carrier oscillator
// The modulator is used to modulate the frequency of the carrier
carrier = SinOsc.ar(freq + modulator, 0, carEnv * carAmp);
// Combine signals
sig = carrier;
// Output
Out.ar(out, sig ! 2); // Stereo Output
}).add;This synth is a simple two oscillator FM synth with a carrier and a modulator. There are a lot of controls to it, but it boils down to controls for the amplitude envelopes for both oscillators, a frequency, and a ratio for the modulator (so if freq is 440 and ratio is 2, the modulator is 880).
Rather than percussive envelopes like we used in the drums, this SynthDef uses Env.adsr which sustains until the gate ≤ 0. Gate is sort of a special control name that allows a node to use the release method.
Heres an example of it in action:
(
// run this block to hear the FM synth
x = Synth(\simpleFM, [
\freq, 140,
\modIndex, 2,
\carAmp, 0.6,
\modAmp, 1008,
\attackCar, 0.01,
\decayCar, 0.5,
\sustainCar, 0.7,
\releaseCar, 1,
\attackMod, 0.02,
\decayMod, 0.4,
\sustainMod, 0.5,
\releaseMod, 1
]);
)
// run the following line to release it
x.release;Using Pattern classes, we can sequence several patterns in parallel that use our new instruments.
// Ensure all SynthDefs are loaded before running this.
(
Ppar([
// Kick pattern: plays 4 dotted quarter notes and then 4 quarter notes
Pbind(
\instrument, \mx_kick,
\dur, Pseq([0.25],inf),
\amp, 0.28,
\freq, Pseq(([60, \r, \r, 60, \r, \r, 60, \r, \r, 60, \r, \r, 50, \r, 50, \r]).flatten, inf),
\pitchDepth, 0.2,
\pitchDur, 0.4,
\drive, 30
),
// Snare pattern: plays on the 2nd and 4th beat of every measure
Pbind(
\instrument, \snare,
\dur, 1,
\amp, 0.5,
\toneFreq, 180,
\noiseMix, 0.5,
\decayTime, 0.2,
\freq, Pseq([\r, 180, \r, 180], inf)
),
// Hi-hat pattern: plays on every offbeat
Pbind(
\instrument, \hihat,
\dur, 0.5,
\amp, 0.3,
\freq, 7500,
\rq, 0.2,
\decayTime, 0.1
),
// Tom pattern: plays on the second beat of every measure
Pbind(
\instrument, \tom,
\dur, 0.5,
\amp, Pseq([\r, 1, \r, \r],inf),
\freq, 70,
\decayTime, 0.16,
\depth, 0.2,
\pitchDur, 0.2
),
// Clap pattern: plays on the 3rd beat of every measure
Pbind(
\instrument, \clap,
\dur, 0.5,
\amp, 0.5,
\decayTime, 0.051,
\freq, Pseq([\r, \r, 1, \r], inf)
),
// melody pattern plays a series of rising chords.
// the +.t adverb operator is some syntax sugar to get an array of arrays.
Pbind(
\instrument, \simpleFM,
\note, Pseq([0,2,4,5,8]+.t [0,4,7], inf),
\modRatio, 2,
\dur, 0.75,
\carAmp, 0.3,
\modAmp, 508,
\attackCar, 0.01,
\decayCar, 0.5,
\sustainCar, 0.7,
\releaseCar, 1,
\attackMod, 0.02,
\decayMod, 0.4,
\sustainMod, 0.1,
\releaseMod, 1
)
]).play;
)
// run this to speed it up a little bit.
TempoClock.default.tempo = 1.5We have used SynthDefs to prepare some instruments ahead of time for using in future compositions and experiments. Making a good synthdef can be time consuming, and its always good to have a few at the ready ahead of attempting any musical livecoding routines.
To learn more about this topic, take a look at the following help files:
See you tomorrow for the continued experiment in livecoding music!
In last nights post I demonstrated how you can use external data (the blockchain) to control the events of a supercollider musical routine. But what that article had in technical insights, it lacked in musicality. So in this article we will remedy that by designing some instruments and testing them out with some musical patterns.
Any band worth listening to has a variety of instruments that play different roles and occupy different sonic ranges. The drums and bass guitar provide the backbone of the music by setting the tempo and energy levels, and giving a foundation for the melodic instruments to build on top of. The guitar and keys are both percussive instruments that occupy a more mid- to high-frequency sonic range.
However this isnt a band. This is all going to be synthesized. Its electronic music, so we can get more creative with our instrumentation.
Heres a short list of Percussion instruments I'd like to define with code for later use:
Soft and Hard Kick,
Snare,
High hat,
Toms,
Clap
And for melodic parts, we'll need a few more Synthdefs from which we can make different instruments:
Frequency Modulation (FM) Synth
Karplus-Strong (Plucked string) Synth
Granular synth (for textures)
Subtractive synth (like your usual classic synthesizer)
Additive synth (like an organ with different harmonic tones added together)
Drone synth with feedback
That is more than enough to start with. Realistically we dont need all of these - a well designed FM synthdef could alone possibly emulate the entire band. So for today, I'll focus on making a versatile FM synthesizer.
SynthDef(\mx_kick, {
arg out = 0, freq = 60, dur=0.3, pitchDur = 0.03, pitchDepth = 0.9, gate = 1, amp=0.6
, noiseAmp=0.03, drive=1;
var ampenv, pitchenv, sig;
ampenv = EnvGen.kr(Env.perc(0.01, dur, amp, -4), gate, doneAction: 2);
// main kick tone, with a pitch envelope
sig = LFPar.ar(
freq + Line.kr(pitchDepth * freq, 0, pitchDur),
0, ampenv);
// Adding a little click to the kick
sig = sig + (
WhiteNoise.ar(ampenv * noiseAmp)
* EnvGen.kr(Env.perc(0.005,0.01))
);
sig = sig * drive;
sig = sig.tanh;
Out.ar(out, sig ! 2);
}).add;A good kick drum synth has a few elements to it. A basic tone is the foundation. Rather than a clean sine-wave, I prefer a low-frequency LFPar to a SinOsc because it has more harmonic structure and can be filtered and overdriven with better results. A kick drum sound will also have that kick at the beginning, so we will need a pitch envelope and an amplitude envelope. In addition, lets add a little click for extra percussion, and handle overdriven sounds at the end with tanh.
Then we can use this single kick drum SynthDef to make several different types of kicks:
clicky clean short kick:
Synth(\mx_kick, [\dur,0.23, \pitchDepth, 4, \pitchDur, 0.02, \noiseAmp, 0.1])
Shallow pitched long kick:
Synth(\mx_kick, [\dur,1, \pitchDepth, 0.2, \pitchDur, 0.2])
Hardcore kick:
Synth(\mx_kick, [\dur,1, \pitchDepth, 0.2, \pitchDur, 0.4, \drive, 30])
SynthDef(\snare, {
|out=0, toneFreq=180, noiseMix=0.5, decayTime=0.2|
var env, tone, noise, sig;
env = Env.perc(0.005, decayTime, 1, -4).kr(2);
tone = SinOsc.ar(toneFreq, 0, env);
noise = WhiteNoise.ar(env);
sig = Mix([tone, noise * noiseMix]);
Out.ar(out, sig ! 2);
}).add;This snare is a simple mix of a sine tone and noise, with a controllable tone freq, mix, and decay time. You can test out different snare sounds with Synth like we did with the kick drums.
SynthDef(\hihat, {
|out=0, freq=7500, rq=0.2, decayTime=0.1|
var env, noise, sig;
env = Env.perc(0.001, decayTime, 1, -4).kr(2);
noise = WhiteNoise.ar(env);
sig = BPF.ar(noise, freq, rq);
Out.ar(out, sig ! 2);
}).add;SynthDef(\tom, {
|out=0, freq=70, decayTime=0.6, depth=0.2, pitchDur=0.2|
var env, sig;
env = Env.perc(0.01, decayTime, 1, -4).kr(2);
sig = LFCub.ar(
freq + Line.kr(depth * freq, 0, pitchDur),
0, env);
Out.ar(out, sig ! 2);
}).add;SynthDef(\clap, {
|out=0, decayTime=0.1|
var env, noise, sig;
env = Env.perc(0.001, decayTime, 1, -4).kr(2);
noise = WhiteNoise.ar(env);
sig = CombN.ar(noise, 0.2, [0.093, 0.04]);
Out.ar(out, sig ! 2);
}).add;The CombN is a delay line which simulates the clap by repeating the percussive noise sound. This is a very simple and not especially great clap sound to be honest, but its something to work with for now.
SynthDef(\simpleFM, { |out = 0, gate = 1, freq = 440, carAmp = 0.5, modFreqRatio=2, modAmp = 0.3, attackCar = 0.01, decayCar = 1, sustainCar = 0.3, releaseCar = 0.5, attackMod = 0.01, decayMod = 1, sustainMod = 0.3, releaseMod = 0.5|
var modulator, carrier, modEnv, carEnv, sig;
// Envelopes for modulator and carrier
modEnv = EnvGen.kr(Env.adsr(attackMod, decayMod, sustainMod, releaseMod), gate, doneAction: 2);
carEnv = EnvGen.kr(Env.adsr(attackCar, decayCar, sustainCar, releaseCar), gate, doneAction: 2);
// Modulator oscillator
modulator = SinOsc.ar(freq*modFreqRatio, 0, modEnv * modAmp* modFreqRatio); // Frequency is set to twice the base frequency for a harmonically related modulation
// Carrier oscillator
// The modulator is used to modulate the frequency of the carrier
carrier = SinOsc.ar(freq + modulator, 0, carEnv * carAmp);
// Combine signals
sig = carrier;
// Output
Out.ar(out, sig ! 2); // Stereo Output
}).add;This synth is a simple two oscillator FM synth with a carrier and a modulator. There are a lot of controls to it, but it boils down to controls for the amplitude envelopes for both oscillators, a frequency, and a ratio for the modulator (so if freq is 440 and ratio is 2, the modulator is 880).
Rather than percussive envelopes like we used in the drums, this SynthDef uses Env.adsr which sustains until the gate ≤ 0. Gate is sort of a special control name that allows a node to use the release method.
Heres an example of it in action:
(
// run this block to hear the FM synth
x = Synth(\simpleFM, [
\freq, 140,
\modIndex, 2,
\carAmp, 0.6,
\modAmp, 1008,
\attackCar, 0.01,
\decayCar, 0.5,
\sustainCar, 0.7,
\releaseCar, 1,
\attackMod, 0.02,
\decayMod, 0.4,
\sustainMod, 0.5,
\releaseMod, 1
]);
)
// run the following line to release it
x.release;Using Pattern classes, we can sequence several patterns in parallel that use our new instruments.
// Ensure all SynthDefs are loaded before running this.
(
Ppar([
// Kick pattern: plays 4 dotted quarter notes and then 4 quarter notes
Pbind(
\instrument, \mx_kick,
\dur, Pseq([0.25],inf),
\amp, 0.28,
\freq, Pseq(([60, \r, \r, 60, \r, \r, 60, \r, \r, 60, \r, \r, 50, \r, 50, \r]).flatten, inf),
\pitchDepth, 0.2,
\pitchDur, 0.4,
\drive, 30
),
// Snare pattern: plays on the 2nd and 4th beat of every measure
Pbind(
\instrument, \snare,
\dur, 1,
\amp, 0.5,
\toneFreq, 180,
\noiseMix, 0.5,
\decayTime, 0.2,
\freq, Pseq([\r, 180, \r, 180], inf)
),
// Hi-hat pattern: plays on every offbeat
Pbind(
\instrument, \hihat,
\dur, 0.5,
\amp, 0.3,
\freq, 7500,
\rq, 0.2,
\decayTime, 0.1
),
// Tom pattern: plays on the second beat of every measure
Pbind(
\instrument, \tom,
\dur, 0.5,
\amp, Pseq([\r, 1, \r, \r],inf),
\freq, 70,
\decayTime, 0.16,
\depth, 0.2,
\pitchDur, 0.2
),
// Clap pattern: plays on the 3rd beat of every measure
Pbind(
\instrument, \clap,
\dur, 0.5,
\amp, 0.5,
\decayTime, 0.051,
\freq, Pseq([\r, \r, 1, \r], inf)
),
// melody pattern plays a series of rising chords.
// the +.t adverb operator is some syntax sugar to get an array of arrays.
Pbind(
\instrument, \simpleFM,
\note, Pseq([0,2,4,5,8]+.t [0,4,7], inf),
\modRatio, 2,
\dur, 0.75,
\carAmp, 0.3,
\modAmp, 508,
\attackCar, 0.01,
\decayCar, 0.5,
\sustainCar, 0.7,
\releaseCar, 1,
\attackMod, 0.02,
\decayMod, 0.4,
\sustainMod, 0.1,
\releaseMod, 1
)
]).play;
)
// run this to speed it up a little bit.
TempoClock.default.tempo = 1.5We have used SynthDefs to prepare some instruments ahead of time for using in future compositions and experiments. Making a good synthdef can be time consuming, and its always good to have a few at the ready ahead of attempting any musical livecoding routines.
To learn more about this topic, take a look at the following help files:
See you tomorrow for the continued experiment in livecoding music!
Max Jackson
Max Jackson
1 comment
Literally just under the wire, I've published an article on SuperCollider audio programming for the third day in a row. In this issue, I craft some SynthDefs for later use: A synthetic drum set and an FM Synthesizer. Then I demonstrate sequencing them altogether with patterns. https://paragraph.xyz/@mxjxn/knowvember-3