Skip to content

Instantly share code, notes, and snippets.

@petersalomonsen
Created September 29, 2020 20:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save petersalomonsen/068e011b94f9d6e2372b0d6fa756e831 to your computer and use it in GitHub Desktop.
Save petersalomonsen/068e011b94f9d6e2372b0d6fa756e831 to your computer and use it in GitHub Desktop.
/**
* Copyright 2020 - Peter Johan Salomonsen
*/
setBPM(120);
addInstrument('pad');
addInstrument('drums');
addInstrument('sawtap');
addInstrument('distlead');
addInstrument('bass');
addInstrument('organ');
// set reverb
createTrack(6).steps(4, [
controlchange(91, 50)
,,,,]);
// midi recording of organ
createTrack(5).play([[ 3.07, b5(0.86, 89) ],
[ 3.06, g5(0.96, 88) ],
[ 3.07, d5(4.30, 87) ],
[ 3.99, a5(3.59, 64) ],
[ 4.00, fs5(3.60, 76) ],
[ 11.01, d6(0.06, 84) ],
[ 11.03, ds6(0.12, 83) ],
[ 11.03, g6(0.44, 83) ],
[ 11.17, e6(0.50, 79) ],
[ 7.60, c5(4.55, 79) ],
[ 7.59, e5(4.60, 68) ],
[ 7.59, g5(4.62, 72) ],
[ 11.99, g6(0.31, 93) ],
[ 11.98, d6(0.38, 84) ],
[ 13.01, as5(0.14, 102) ],
[ 13.04, d6(0.35, 84) ],
[ 13.12, b5(0.43, 72) ],
[ 13.92, a5(0.52, 98) ],
[ 13.91, d6(0.58, 98) ],
[ 14.44, g5(0.16, 69) ],
[ 14.97, e5(0.56, 87) ],
[ 15.50, d5(0.35, 55) ],
[ 14.98, g5(0.89, 83) ]]);
// midi recording of distortion synth
createTrack(3).play([[ 0.02, g2(0.45, 62) ],
[ 0.55, g3(0.42, 63) ],
[ 0.54, g4(0.45, 57) ],
[ 1.05, g2(0.39, 59) ],
[ 1.01, d5(0.53, 70) ],
[ 1.54, g5(0.43, 90) ],
[ 1.57, g3(0.41, 65) ],
[ 2.03, g2(0.45, 60) ],
[ 2.01, g4(0.62, 64) ],
[ 2.53, g3(0.44, 64) ],
[ 2.53, d5(0.44, 64) ],
[ 3.03, g2(0.41, 68) ],
[ 2.99, g5(0.51, 87) ],
[ 3.50, g3(0.26, 72) ],
[ 3.52, g4(0.43, 67) ],
[ 4.00, d3(0.37, 70) ],
[ 4.01, g5(0.43, 88) ],
[ 4.43, d4(0.48, 62) ],
[ 4.42, a4(0.58, 64) ],
[ 4.99, d3(0.38, 70) ],
[ 4.97, d5(0.46, 60) ],
[ 5.47, d4(0.41, 68) ],
[ 5.45, g5(0.47, 79) ],
[ 5.96, d3(0.36, 74) ],
[ 5.92, a4(0.82, 59) ],
[ 6.40, d4(0.48, 67) ],
[ 6.43, d5(0.54, 55) ],
[ 6.97, d3(0.33, 75) ],
[ 6.94, a5(0.42, 90) ],
[ 7.41, d4(0.18, 67) ],
[ 7.37, a4(0.52, 72) ],
[ 7.92, a5(0.27, 89) ],
[ 7.91, a2(0.45, 74) ],
[ 8.48, a3(0.46, 58) ],
[ 8.50, g4(0.50, 59) ],
[ 9.02, a2(0.39, 68) ],
[ 8.96, c5(0.52, 72) ],
[ 9.50, a3(0.49, 67) ],
[ 9.47, g5(0.53, 89) ],
[ 10.05, a2(0.43, 70) ],
[ 10.01, g4(0.92, 74) ],
[ 10.54, a3(0.45, 69) ],
[ 10.52, c5(0.53, 68) ],
[ 11.03, a2(0.35, 67) ],
[ 11.01, g5(0.49, 83) ],
[ 11.48, a3(0.39, 70) ],
[ 11.49, g4(0.45, 75) ],
[ 11.98, c3(0.41, 70) ],
[ 12.00, g5(0.46, 84) ],
[ 12.47, c4(0.54, 58) ],
[ 12.46, g4(0.57, 64) ],
[ 13.04, c3(0.37, 74) ],
[ 13.01, c5(0.54, 77) ],
[ 13.48, g5(0.21, 74) ],
[ 13.54, c4(0.45, 60) ],
[ 14.04, c3(0.42, 77) ],
[ 14.02, c6(0.51, 79) ],
[ 14.52, c4(0.48, 69) ],
[ 14.48, b5(0.59, 77) ],
[ 15.04, c3(0.41, 74) ],
[ 15.00, a5(0.48, 90) ],
[ 15.51, c4(0.38, 77) ],
[ 15.47, g5(0.45, 93) ]].quantize(4));
// drums
await createTrack(1).steps(4, [
c5,,,,d5,,,,
c5,,,,d5,,,,
c5,,,,d5,,,,
c5,,,,d5,,d5,,
c5,,,,d5,,,,
c5,,,,d5,,,,
c5,,,,d5,,,,
c5,,,,d5,d5,d5,,
]);
loopHere();
import { cos, outputline, FFT, TriBandEQ, Pan, SineOscillator, IFFTOscillator, BiQuadFilter, FilterType, Q_BUTTERWORTH, Noise, DelayLine, BandPass,SawOscillator,softclip, midichannels, MidiChannel, MidiVoice, StereoSignal, Freeverb, SineOscillator, Envelope, notefreq } from '../mixes/globalimports';
import { SAMPLERATE } from '../environment';
const delayframes = (SAMPLERATE * (6/8) * 60 / 100) as usize;
let delayLeft: DelayLine = new DelayLine(delayframes);
let delayRight: DelayLine = new DelayLine(delayframes);
const echoline = new StereoSignal();
const eqleft = new TriBandEQ(20, 600, 6000, 19000);
const eqright = new TriBandEQ(20, 600, 6000, 19000);
export class Hihat extends MidiVoice {
private velocity: f32;
readonly envelope: Envelope = new Envelope(0.0, 0.07, 0, 0.1);
readonly noise: Noise = new Noise();
readonly filter: BiQuadFilter = new BiQuadFilter();
readonly signal: StereoSignal = new StereoSignal();
constructor(channel: MidiChannel) {
super(channel);
this.minnote = 66;
this.maxnote = 66;
}
noteon(note: u8, velocity: u8):void {
if(note > 1) {
this.velocity = velocity as f32 / 32;
this.envelope.attack();
}
}
noteoff(): void {
this.envelope.release();
}
isDone(): boolean {
return this.envelope.isDone();
}
nextframe(): void {
let env: f32 = this.envelope.next();
let osc: f32 = this.noise.next();
let signal = this.velocity * 2 * env * osc;
this.filter.update_coeffecients(FilterType.HighPass, SAMPLERATE,
10000 + 2000 * env, Q_BUTTERWORTH);
signal = this.filter.process(signal);
this.channel.signal.add(signal, signal);
}
}
export class Kick2 extends MidiVoice {
private velocity: f32;
readonly noise: Noise = new Noise();
readonly env2: Envelope = new Envelope(0.001, 0.01, 0.0, 0.0);
readonly bp2: BandPass = new BandPass(4000, 5000);
readonly env3: Envelope = new Envelope(0.001, 0.2, 0.1, 0.1);
readonly bp3: BandPass = new BandPass(10, 100);
constructor(channel: MidiChannel) {
super(channel);
this.minnote = 60;
this.maxnote = 60;
}
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
this.velocity = (velocity as f32) / 40;
this.env2.attack();
this.env3.attack();
}
noteoff(): void {
this.env2.release();
this.env3.release();
}
isDone(): boolean {
return this.env3.isDone();
}
nextframe(): void {
let env2: f32 = this.env2.next();
let env3: f32 = this.env3.next();
const osc: f32 = this.noise.next();
const sig = this.velocity * (
this.bp2.process(osc) * env2 +
this.bp3.process(osc) * env3 * 8);
this.channel.signal.add(sig, sig);
}
}
class SawSpread extends MidiVoice {
osc: SawOscillator = new SawOscillator();
osc2: SawOscillator = new SawOscillator();
osc3: SawOscillator = new SawOscillator();
osc4: SawOscillator = new SawOscillator();
osc5: SawOscillator = new SawOscillator();
env: Envelope = new Envelope(0.02, 0.4, 0.5, 1.0);
bp2: BandPass = new BandPass(20, 5000);
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const adjustednote = note;
this.osc.frequency = notefreq(adjustednote);
this.osc2.frequency = notefreq(adjustednote as f32 + 0.1);
this.osc3.frequency = notefreq(adjustednote as f32 - 0.1);
this.osc4.frequency = notefreq(adjustednote as f32 + 0.15);
this.osc5.frequency = notefreq(adjustednote as f32 - 0.15);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const osc1 = this.osc.next();
const osc2 = this.osc2.next();
const osc3 = this.osc3.next();
const osc4 = this.osc4.next();
const osc5 = this.osc5.next();
const left = this.bp2.process((
osc1 + osc2 + osc3 * 0.5 + osc4
)
* this.env.next()
* this.velocity * 0.01);
const right = this.bp2.process((
osc1 + osc2 *0.5 + osc3 + osc5
)
* this.env.next()
* this.velocity * 0.01);
this.channel.signal.add(left, right);
}
}
class SawTap extends MidiVoice {
osc: SawOscillator = new SawOscillator();
env: Envelope = new Envelope(0.001, 0.1, 0.05, 0.1);
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const adjustednote = note -12;
this.osc.frequency = notefreq(adjustednote);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const signal = this.osc.next() * this.env.next()
* this.velocity * 0.01;
this.channel.signal.add(signal, signal);
}
}
class SawDist extends MidiVoice {
osc: SawOscillator = new SawOscillator();
osc2: SawOscillator = new SawOscillator();
env: Envelope = new Envelope(0.01, 0.5, 0.7, 0.1);
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
this.osc.frequency = notefreq(note as f32-0.07);
this.osc2.frequency = notefreq(note as f32+0.07);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const signal = (this.osc.next() + this.osc2.next()) *
this.env.next()
* this.velocity * 0.01;
this.channel.signal.left += signal;
}
}
class SawTapChannel extends MidiChannel {
feedback: f32 = 0;
preprocess(): void {
let signal = this.signal.left * 0.25;
echoline.add(signal, signal);
}
}
class SawDistChannel extends MidiChannel {
feedback: f32 = 0;
preprocess(): void {
let signal = this.signal.left + this.feedback;
signal = softclip(signal *3) * 0.5;
this.feedback = signal * 0.8;
signal*=0.3;
this.signal.left = signal;
this.signal.right = signal;
echoline.add(signal, signal);
}
}
export class Snare2 extends MidiVoice {
private velocity: f32;
readonly noise: Noise = new Noise();
readonly env1: Envelope = new Envelope(0.001, 0.4, 0.0, 0.3);
readonly bp1: BandPass = new BandPass(200, 350);
readonly env2: Envelope = new Envelope(0.001, 0.08, 0.00, 0.2);
readonly bp2: BandPass = new BandPass(3000, 8000);
readonly env3: Envelope = new Envelope(0.001, 0.05, 0.00, 0.1);
readonly bp3: BandPass = new BandPass(10, 150);
constructor(channel: MidiChannel) {
super(channel);
this.minnote = 62;
this.maxnote = 62;
}
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
this.velocity = velocity as f32 / 64;
this.env1.attack();
this.env2.attack();
this.env3.attack();
}
noteoff(): void {
this.env1.release();
this.env2.release();
this.env3.release();
}
isDone(): boolean {
return this.env1.isDone();
}
nextframe(): void {
let env1: f32 = this.env1.next();
let env2: f32 = this.env2.next();
let env3: f32 = this.env3.next();
let osc: f32 = this.noise.next();
let sig1 = this.bp1.process(osc) * env1 * 6;
let sig2 = this.bp2.process(osc) * env2 * 2;
let sig3 = this.bp3.process(osc) * env3 * 4;
this.channel.signal.add(
this.velocity * (sig1 + sig2 * 0.8 + sig3),
this.velocity * (sig1 * 0.8 + sig2 + sig3)
);
}
}
export class SawBass3 extends MidiVoice {
readonly envelope: Envelope = new Envelope(0.01, 0.3, 0.8, 0.2);
readonly filterenv: Envelope = new Envelope(0.01, 0.2, 0.1, 0.2);
readonly sawoscillator: SawOscillator = new SawOscillator();
readonly filter: BiQuadFilter = new BiQuadFilter();
readonly lpfilter: BiQuadFilter = new BiQuadFilter();
readonly band1: BandPass = new BandPass(1000, 2000);
readonly signal: StereoSignal = new StereoSignal();
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
this.sawoscillator.frequency = notefreq(note);
this.envelope.attack();
this.filterenv.attack();
}
noteoff(): void {
this.envelope.release();
this.filterenv.release();
}
nextframe(): void {
let env: f32 = this.envelope.next();
if(env === 0) {
this.signal.clear();
return;
}
let filterenv = this.filterenv.next();
let signal = this.sawoscillator.next();
signal *= env;
this.lpfilter.update_coeffecients(FilterType.LowPass, SAMPLERATE,
this.sawoscillator.frequency + (16 * this.sawoscillator.frequency * filterenv), Q_BUTTERWORTH);
const band1freq = this.sawoscillator.frequency * 4;
this.band1.update_frequencies(band1freq, band1freq + env * this.sawoscillator.frequency);
let band1 = this.band1.process(signal);
signal = this.lpfilter.process(signal);
this.channel.signal.add(signal * 2 + band1,
signal * 2 - band1);
}
}
export class Organ extends MidiVoice {
readonly envelope: Envelope = new Envelope(0.01, 0.8, 0.5, 0.1);
readonly lfo: SineOscillator = new SineOscillator();
readonly lfo2: SineOscillator = new SineOscillator();
readonly lfo3: SineOscillator = new SineOscillator();
readonly oscleft: IFFTOscillator = new IFFTOscillator(4);
readonly oscright: IFFTOscillator = new IFFTOscillator(4);
pan: Pan = new Pan();
framecount: i32 = 0;
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
this.oscleft.frequency = notefreq(note);
this.oscright.frequency = notefreq(note);
this.lfo.frequency = 64;
this.lfo2.frequency = 128;
this.lfo3.frequency = 256;
this.pan.setPan(note as f32/ 127.0);
this.envelope.attack();
}
noteoff(): void {
this.envelope.release();
}
nextframe(): void {
const env: f32 = this.envelope.next();
if((this.framecount & 0xff) === 0) {
this.oscleft.createWave(
[0,0,this.lfo2.next() * env,0],
[
env,
this.lfo.next()* env,
this.lfo2.next() * env,
this.lfo3.next() * env
]);
this.oscleft.fft.calculateInverse();
this.oscright.createWave(
[0,0,0,0,this.lfo3.next() * env],
[env,
this.lfo.next()* env,
this.lfo3.next() * env,
this.lfo2.next() * env
]);
this.oscright.fft.calculateInverse();
}
this.framecount ++;
this.channel.signal.add(
0.29 * this.oscleft.next() * this.pan.leftLevel,
0.29 * this.oscright.next() * this.pan.rightLevel
);
}
}
export function initializeMidiSynth(): void {
midichannels[0] = new MidiChannel(10, (ch) => new SawSpread(ch));
midichannels[1] = new MidiChannel(3, (ch, ndx) => {
switch(ndx) {
case 0:
return new Snare2(ch);
case 1:
return new Hihat(ch);
default:
return new Kick2(ch);
}
});
midichannels[2] = new SawTapChannel(2, (ch) => new SawTap(ch));
midichannels[3] = new SawDistChannel(3, (ch) => new SawDist(ch));
midichannels[4] = new MidiChannel(1, (ch) => new SawBass3(ch));
midichannels[5] = new MidiChannel(10, (ch) => new Organ(ch));
}
export function postprocess(): void {
echoline.left += delayRight.read() * 0.7;
echoline.right += delayLeft.read() * 0.7;
delayLeft.write_and_advance(echoline.left);
delayRight.write_and_advance(echoline.right);
outputline.add(echoline.left, echoline.right);
outputline.left = eqleft.process(outputline.left, 0.7, 0.6, 0.7);
outputline.right = eqright.process(outputline.right, 0.7, 0.6, 0.7);
echoline.clear();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment