Last active
March 18, 2020 18:52
-
-
Save petersalomonsen/1327a361e1e0323de03936672ccc388c to your computer and use it in GitHub Desktop.
"4klang first attempt" remake for WASM livecode env
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
/** | |
* | |
* "4klang first attempt" - originally made for 4klang, remake for livecode wasm env. | |
* | |
* Copyright (c) 2019-2020 - Peter Johan Salomonsen - All rights reserved | |
* | |
*/ | |
global.bpm = 106; | |
global.pattern_size_shift = 4; | |
//global.latencyHint="playback"; | |
global.latencyHint=0.03; | |
// global.looptimes = 100; | |
//soloInstrument('bass'); | |
//soloInstrument('kick'); | |
// soloInstrument('pad1'); | |
// soloInstrument('pad2'); | |
// soloInstrument('pad3'); | |
// soloInstrument('padsvolume'); | |
// global.WASM_SYNTH_LOCATION = 'https://gist.githubusercontent.com/petersalomonsen/ea73551e352440d5f470c6af89d7fe7c/raw/b23b32ba55c1c15e972f39724ae164025f569c76/webchipmusic.wasm'; | |
addInstrument('flute', {type: 'note'}); | |
addInstrument('bass', {type: 'note'}); | |
addInstrument('pad1', {type: 'note'}); | |
addInstrument('pad2', {type: 'note'}); | |
addInstrument('pad3', {type: 'note'}); | |
addInstrument('lead', {type: 'note'}); | |
addInstrument('kick', {type: 'number'}); | |
addInstrument('snare', {type: 'number'}); | |
addInstrument('hihat', {type: 'number'}); | |
addPattern('kick', pattern(4,[c4,,,, ,,,,c4, ,,,, ])); | |
addPattern('snare1', pattern(4,[,,,,e3,,,e3,,e3,,,e3,,,])); | |
addPattern('hihat', pattern(4, [,,e3,,,,e3,,,,e3,,,,e3,,])); | |
addPattern('flute', pattern(4, [ | |
fs5,,,,,,b5,as5,,fs5,,,,,cs5,ds5, | |
e5,,,,,, e5,ds5,,cs5,,,,, , | |
])); | |
addPattern('pad1_1', pattern(1/4, [ cs5(2),cs5(2) ])); | |
addPattern('pad1_2', pattern(1/4, [ fs5(2),e5(2) ])); | |
addPattern('pad1_3', pattern(1/4, [ as5(2),b5(2) ])); | |
addPattern('lead', pattern(4, [ | |
,,as6,,as6,,gs6,as6,,as6,,gs6,as6,,cs7,, | |
b6,,,,,,,b6(1/2),,as6(1/2),,gs6(1/2),,fs6,, | |
cs6(1),,,,,,,,,fs6,gs6,,as6,,fs6(1/2),,gs6(2) | |
])); | |
addPattern('bass', pattern(4,[ | |
fs3(1/2),,,fs4,,,,,,,e4,,e4,fs4,,, | |
,,,,,,,b3,,b3,c4,,cs4,,e4 | |
])); | |
addPattern('pad2_1', pattern(1, [ b4(2),,, gs5(1),ds5(2),,,ds5(1),ds5(2),,cs5(2),,fs5(2) ])); | |
addPattern('pad2_2', pattern(1, [ ds5(2),,,f5(1),fs5(2),,, g5(1) ,gs5(2),,fs5(2),,b5(2) ])); | |
addPattern('pad2_3', pattern(1, [ fs5(2),,,cs5(1),as5(2),,,as5(1),b5(2) ,,as5(2),,ds6(2) ])); | |
addPattern('flute2', pattern(4, [ | |
,,ds5,,ds5,,cs5,ds5,,ds5,,cs5,fs5(1/2),,ds5,, | |
,,as5,,as5,,gs5,as5,,as5,,gs5,g5(1/2),,ds5,, | |
b5,as5,,gs5,,fs5,,as5,,gs5,,fs5,,cs5,ds5,, | |
,,,,,,,fs3,b3,ds4,fs4,b4,ds5,fs5,b4 | |
])); | |
addPattern('bass2', pattern(4,[ | |
b3(1/2),,,b4,,b4,b3(1/2),,,,,b4,cs4,,cs5,, | |
ds4,,,,,,,,ds5,ds4,,f4,,g4,,, | |
gs3(1/2),,,gs4,,gs4,gs3,,as3,,,as3,as4,,as3,, | |
b3(1),,,,,,,b4,,b4,b3,,ds4,,fs4(1/2) | |
])); | |
addPattern('leadafterintermission', pattern(4, [ | |
fs5,,,,,,fs5,cs6,,,,,,cs6,ds6,e6,,,,,,,,,ds6(1),,,,b5(1),,,, | |
fs6,cs6,fs6,cs6,,,,,,,,,,,,,e6(1),,,,ds6(1),,,,b5(1),,,,cs6(1) | |
])); | |
addPattern('leadintermission', pattern(1,[ds5(4),,,b5(1),as5(4),,,,b5(2),,cs6(2),,fs5(4)])); | |
addPattern('kick2', pattern(4, [c4,,,,c4,,,c4,c4,,,,c4])) | |
addPattern('pad3_1', pattern(1/2, [ cs6(3),,cs6(3),,b5(3),,a5(7/4), b5(7/4)])); | |
addPattern('pad3_2', pattern(1/2, [ fs6(3),,e6(3) ,,ds6(3),,d6(7/4),e6(7/4)])); | |
addPattern('pad3_3', pattern(1/2, [ as6(3),,a6(3) ,,fs6(4),,, gs6(7/4)])); | |
addPattern('bass3', pattern(1/2, [ | |
fs3(4),,a3(4),,b3(4),,d3(2),e3(2) | |
])); | |
addPattern('lead4', pattern(4, [ | |
fs6(5),,,,,,,,,,,,,,,,,, | |
,e6(4),,,,,,,,,,,cs6,e6, | |
fs6(4),,,,,,,,,,,,,,a6,b6, | |
cs7(1),,,,b6(1),,,,a6(1/2),,fs6(2) | |
])); | |
addPattern('flute3', pattern(4,[ | |
fs4,cs5,fs5,e5,fs5,,e5,fs5,,fs5,e5,cs5,e5,fs5 | |
])); | |
for(let n = 0; n<2; n++) { | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat', | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat', | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3', | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat', | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3', | |
lead: 'lead' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat', | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3', | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat', | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3', | |
lead: 'lead' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat', | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3', | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat', | |
bass: 'bass2', | |
flute: 'flute2', | |
pad1: 'pad2_1', | |
pad2: 'pad2_2', | |
pad3: 'pad2_3' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat', | |
bass: 'bass2', | |
flute: 'flute2', | |
pad1: 'pad2_1', | |
pad2: 'pad2_2', | |
pad3: 'pad2_3', | |
lead: 'leadintermission' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat', | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3', | |
lead: 'leadafterintermission' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3', | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3', | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3', | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
snare: 'snare1', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
bass: 'bass3', | |
pad1: 'pad3_1', | |
pad2: 'pad3_2', | |
pad3: 'pad3_3', | |
lead: 'lead4', | |
kick: 'kick2' | |
}); | |
playPatterns({ | |
kick: 'kick2' | |
}); | |
playPatterns({ | |
kick: 'kick2' | |
}); | |
playPatterns({ | |
kick: 'kick2' | |
}); | |
playPatterns({ | |
bass: 'bass3', | |
pad1: 'pad3_1', | |
pad2: 'pad3_2', | |
pad3: 'pad3_3', | |
lead: 'lead4', | |
kick: 'kick2', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick2', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick2', | |
hihat: 'hihat' | |
}); | |
playPatterns({ | |
kick: 'kick2', | |
hihat: 'hihat' | |
}); | |
// playFromHere(); | |
playPatterns({ | |
bass: 'bass3', | |
pad1: 'pad3_1', | |
pad2: 'pad3_2', | |
pad3: 'pad3_3', | |
lead: 'lead4', | |
kick: 'kick', | |
flute: 'flute3', | |
hihat: 'hihat', | |
snare: 'snare1' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
flute: 'flute3', | |
hihat: 'hihat', | |
snare: 'snare1' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
flute: 'flute3', | |
hihat: 'hihat', | |
snare: 'snare1' | |
}, 1, true); | |
playPatterns({ | |
kick: 'kick', | |
flute: 'flute3', | |
hihat: 'hihat', | |
snare: 'snare1' | |
}); | |
playPatterns({ | |
bass: 'bass3', | |
pad1: 'pad3_1', | |
pad2: 'pad3_2', | |
pad3: 'pad3_3', | |
lead: 'lead4', | |
kick: 'kick', | |
flute: 'flute3', | |
hihat: 'hihat', | |
snare: 'snare1' | |
}); | |
// Clipping occured here | |
playPatterns({ | |
kick: pp(4,[,,,, ,,,,c4, ,,,, ]), | |
flute: 'flute3', | |
hihat: 'hihat', | |
snare: 'snare1' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
flute: 'flute3', | |
hihat: 'hihat', | |
snare: 'snare1' | |
}); | |
playPatterns({ | |
kick: 'kick', | |
flute: 'flute3', | |
hihat: 'hihat', | |
snare: 'snare1' | |
}); | |
} | |
for(let n=0;n<2; n++) { | |
playPatterns({ | |
kick: 'kick2', | |
hihat: 'hihat', | |
flute: 'flute', | |
bass: 'bass', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3' | |
}); | |
playPatterns({ | |
kick: 'kick2', | |
hihat: 'hihat' | |
}); | |
} | |
playPatterns({ | |
flute: 'flute', | |
pad1: 'pad1_1', | |
pad2: 'pad1_2', | |
pad3: 'pad1_3' | |
},4); |
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
import { EQBand } from "../fx/eqband"; | |
import { Envelope } from '../synth/envelope.class'; | |
import { Rimshot } from "../instruments/drums/rimshot.class"; | |
import { SawBass3 } from "../instruments/bass/sawbass3"; | |
import { Eftang } from "../instruments/lead/eftang"; | |
import { StereoSignal } from "../synth/stereosignal.class"; | |
import { Kick2 } from "../instruments/drums/kick2.class"; | |
import { BrassyLead } from "../instruments/lead/brassy"; | |
import { Hihat } from "../instruments/hihat.class"; | |
import { WaveShaper } from '../synth/shaper'; | |
import { createInstrumentArray } from '../common/mixcommon'; | |
import { BandPass } from '../fx/bandpass'; | |
import { Freeverb } from "../fx/freeverb"; | |
import { DelayLine } from "../fx/delayline"; | |
import { SAMPLERATE } from "../environment"; | |
import { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad'; | |
import { notefreq } from '../synth/note'; | |
import { Noise } from '../synth/noise.class'; | |
import { SineOscillator } from '../synth/sineoscillator.class'; | |
import { SawOscillator } from '../synth/sawoscillator.class'; | |
import { SquareOscillator } from '../synth/squareoscillator.class'; | |
import { TriBandEQ } from "../fx/tribandeq"; | |
import { SubPiano } from "../instruments/piano/subpiano"; | |
import { softclip } from "../synth/softclip"; | |
export const PATTERN_SIZE_SHIFT: usize = 4; | |
export const BEATS_PER_PATTERN_SHIFT: usize = 2; | |
const tribandeqleft = new TriBandEQ(20,400,6500,19500); | |
const tribandeqright = new TriBandEQ(20,400,6500,19500); | |
const gain: f32 = 0.30; | |
const bass = new SawBass3(); | |
const lead = new Eftang(); | |
const kick = new Kick2(); | |
const snare = new Rimshot(); | |
const hihat = new Hihat(); | |
const masterlopassfilterleft = new BiQuadFilter(); | |
const masterlopassfilterright = new BiQuadFilter(); | |
masterlopassfilterleft.update_coeffecients( | |
FilterType.LowPass, SAMPLERATE, 20000.0, Q_BUTTERWORTH); | |
masterlopassfilterright.update_coeffecients( | |
FilterType.LowPass, SAMPLERATE, 20000.0, Q_BUTTERWORTH); | |
export class DeepBass { | |
private _note: f32; | |
readonly envelope: Envelope = new Envelope(0.01, 0.2, 0.70, 0.2); | |
readonly filterenv: Envelope = new Envelope(0.01, 0.4, 0.0, 0.2); | |
readonly sawoscillator: SawOscillator = new SawOscillator(); | |
readonly sawoscillator2: SawOscillator = new SawOscillator(); | |
readonly squareoscillator: SquareOscillator = new SquareOscillator(); | |
readonly filter: BiQuadFilter = new BiQuadFilter(); | |
readonly hpfilterl: BiQuadFilter = new BiQuadFilter(); | |
readonly hpfilterr: BiQuadFilter = new BiQuadFilter(); | |
readonly lpfilterl: BiQuadFilter = new BiQuadFilter(); | |
readonly lpfilterr: BiQuadFilter = new BiQuadFilter(); | |
readonly shaperl: WaveShaper = new WaveShaper(); | |
readonly shaperr: WaveShaper = new WaveShaper(); | |
readonly signal: StereoSignal = new StereoSignal(); | |
constructor() { | |
this.hpfilterl.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH); | |
this.hpfilterr.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH); | |
this.shaperl.drive = 0.3; | |
this.shaperr.drive = 0.3; | |
} | |
set note(note: f32) { | |
if(note > 1) { | |
this.sawoscillator.frequency = notefreq(note + 0.1) / 2; | |
this.sawoscillator2.frequency = notefreq(note - 0.1) / 2; | |
this.squareoscillator.frequency = notefreq(note); | |
this.envelope.attack(); | |
this.filterenv.attack(); | |
} else { | |
this.envelope.release(); | |
this.filterenv.release(); | |
} | |
this._note = note; | |
} | |
get note(): f32 { | |
return this._note; | |
} | |
next(): void { | |
let env: f32 = this.envelope.next(); | |
if(env === 0) { | |
this.signal.clear(); | |
return; | |
} | |
// this.signal.clear(); | |
let filterenv = this.filterenv.next(); | |
this.signal.left *= 0.9 * env; // feedback | |
this.signal.right *= 0.9 * env; // feedback | |
this.lpfilterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (150 * filterenv), Q_BUTTERWORTH); | |
this.lpfilterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (150 * filterenv), Q_BUTTERWORTH); | |
const squaresignal = this.squareoscillator.next() * 0.5; | |
this.signal.addMonoSignal( | |
this.lpfilterl.process(squaresignal + this.hpfilterl.process(this.sawoscillator.next() * env)), 0.3, 0.3 | |
); | |
this.signal.addMonoSignal( | |
this.lpfilterr.process(squaresignal + this.hpfilterr.process(this.sawoscillator2.next() * env)), 0.3, 0.7 | |
); | |
this.signal.left = this.shaperl.process(this.signal.left); | |
this.signal.right = this.shaperr.process(this.signal.right); | |
} | |
} | |
export class SoftPad { | |
private _note: f32; | |
readonly envelope: Envelope = new Envelope(0.5, 0.6, 0.75, 3.0); | |
readonly filterenvelope: Envelope = new Envelope(0.8, 1.0, 0.6, 3.0); | |
readonly hipassfilterenvelope: Envelope = new Envelope(0.02, 3, 0.2, 3.0); | |
readonly sawoscillator: SawOscillator = new SawOscillator(); | |
readonly sawoscillator2: SawOscillator = new SawOscillator(); | |
readonly sawoscillator3: SawOscillator = new SawOscillator(); | |
readonly sawoscillator4: SawOscillator = new SawOscillator(); | |
readonly sawoscillator5: SawOscillator = new SawOscillator(); | |
readonly lfo: SineOscillator = new SineOscillator(); | |
readonly filterl: BiQuadFilter = new BiQuadFilter(); | |
readonly filterr: BiQuadFilter = new BiQuadFilter(); | |
readonly signal: StereoSignal = new StereoSignal(); | |
set note(note: f32) { | |
if(note > 1) { | |
this.lfo.frequency = 1; | |
this.lfo.position = 0; | |
this.sawoscillator.frequency = notefreq(note); | |
this.sawoscillator2.frequency = notefreq(note + 0.03); | |
this.sawoscillator3.frequency = notefreq(note - 0.03); | |
this.sawoscillator4.frequency = notefreq(note + 0.06); | |
this.sawoscillator5.frequency = notefreq(note - 0.06); | |
this.envelope.attack(); | |
this.filterenvelope.attack(); | |
this.hipassfilterenvelope.attack(); | |
this._note = note; | |
} else { | |
this.envelope.release(); | |
this.filterenvelope.release(); | |
this.hipassfilterenvelope.release(); | |
} | |
} | |
get note(): f32 { | |
return this._note; | |
} | |
next(): void { | |
let env: f32 = this.envelope.next(); | |
if(env === 0) { | |
this.signal.clear(); | |
return; | |
} | |
const lfo: f32 = this.lfo.next(); | |
const note = this.note; | |
if(note<2) { | |
return; | |
} | |
this.sawoscillator2.frequency = notefreq(note + 0.05 + (0.02 * lfo)); | |
this.sawoscillator3.frequency = notefreq(note - 0.05 - (0.02 * lfo)); | |
this.sawoscillator4.frequency = notefreq(note + 0.1 + (0.03 * lfo)); | |
this.sawoscillator5.frequency = notefreq(note - 0.1 - (0.03 * lfo)); | |
let osc: f32 = this.sawoscillator.next(); | |
let osc2: f32 = this.sawoscillator2.next(); | |
let osc3: f32 = this.sawoscillator3.next(); | |
let osc4: f32 = this.sawoscillator4.next(); | |
let osc5: f32 = this.sawoscillator5.next(); | |
let left = env * (osc + osc2 + osc5); | |
let right = env * (osc + osc3 + osc4 ); | |
const filterlfo = lfo + 1; | |
this.filterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, | |
200 + this.filterenvelope.next() * filterlfo * 2000 + 20 * (127 - this.note), Q_BUTTERWORTH); | |
this.filterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, | |
200 + this.filterenvelope.next() * filterlfo * 2000 + 20 * (this.note), Q_BUTTERWORTH); | |
this.signal.left = this.filterl.process(left ); | |
this.signal.right = this.filterr.process(right ); | |
} | |
} | |
const pads: SoftPad[] = createInstrumentArray<SoftPad>(10, () => new SoftPad()); | |
let padsVolume: f32 = 1.0; | |
class SineLead { | |
private _note: f32; | |
readonly osc: SineOscillator = new SineOscillator(); | |
readonly lfo: SineOscillator = new SineOscillator(); | |
readonly env1: Envelope = new Envelope(0.02, 0.10, 0.2, 0.3); | |
readonly noiseenv: Envelope = new Envelope(0.01, 0.02, 0.1, 0.3); | |
readonly signal: StereoSignal = new StereoSignal(); | |
private noise: Noise = new Noise(); | |
hpfilterl: BiQuadFilter = new BiQuadFilter(); | |
hpfilterr: BiQuadFilter = new BiQuadFilter(); | |
private bandpass: BandPass = new BandPass(400,2000); | |
private shaper: WaveShaper = new WaveShaper(); | |
constructor() { | |
this.hpfilterl.update_coeffecients(FilterType.HighPass, SAMPLERATE, 7000, 0.5); | |
this.hpfilterr.update_coeffecients(FilterType.HighPass, SAMPLERATE, 7000, 0.5); | |
} | |
set note(note: f32) { | |
if(note > 1) { | |
this.osc.frequency = notefreq(note + 12); | |
this.lfo.frequency = 8; | |
this._note = note; | |
this.env1.attack(); | |
this.noiseenv.attack(); | |
} else { | |
this.env1.release(); | |
this.noiseenv.release(); | |
} | |
} | |
get note(): f32 { | |
return this._note; | |
} | |
next(): void { | |
if(this.env1.state === 4) { | |
this.signal.clear(); | |
return; | |
} | |
const env1: f32 = this.env1.next(); | |
const noiseenv: f32 = this.noiseenv.next(); | |
let lfo: f32 = this.lfo.next(); | |
let osc: f32 = this.osc.next(); | |
osc *= env1; | |
let noiseleft: f32 = this.noise.next() * noiseenv; | |
let noiseright: f32 = this.noise.next() * noiseenv; | |
noiseleft = this.hpfilterl.process(noiseleft); | |
noiseright = this.hpfilterr.process(noiseright); | |
const pan = this._note / 127; | |
this.bandpass.update_frequencies(300,2000 + 1300 * lfo); | |
osc = this.bandpass.process(osc); | |
osc = this.shaper.process(osc); | |
let left = osc * pan; | |
let right = osc * (1 - pan); | |
this.signal.left = left + noiseleft; | |
this.signal.right = right + noiseright; | |
} | |
} | |
export class DriveLead { | |
private _note: f32; | |
readonly envelope: Envelope = new Envelope(0.03, 1.0, 0.6, 0.2); | |
readonly sawoscillatorl: SawOscillator = new SawOscillator(); | |
readonly sawoscillatorr: SawOscillator = new SawOscillator(); | |
readonly shaper: WaveShaper = new WaveShaper(); | |
readonly signal: StereoSignal = new StereoSignal(); | |
readonly lfoenvelope: Envelope = new Envelope(1.0, 0, 1.0, 0.1); | |
readonly lfo: SineOscillator = new SineOscillator(); | |
private baseFrequency : f32; | |
private pitchbend: f32 = 0; | |
set note(note: f32) { | |
if(note > 1) { | |
this.shaper.drive = 0.5; | |
this.baseFrequency = notefreq(note -12 + this.pitchbend); | |
this.lfo.frequency = 8; | |
this.envelope.attack(); | |
this.lfoenvelope.attack(); | |
this._note = note; | |
} else { | |
this.envelope.release(); | |
this.lfoenvelope.release(); | |
} | |
} | |
get note(): f32 { | |
return this._note; | |
} | |
setPitchbend(bend: f32): void { | |
this.pitchbend = bend; | |
this.baseFrequency = notefreq(this._note + bend); | |
} | |
next(): void { | |
let env: f32 = this.envelope.next(); | |
if(env===0) { | |
this.signal.clear(); | |
return; | |
} | |
let lfo: f32 = this.lfo.next() * 3 * this.lfoenvelope.next(); | |
this.sawoscillatorl.frequency = this.baseFrequency + lfo + 0.5; | |
this.sawoscillatorr.frequency = this.baseFrequency + lfo - 0.5; | |
let left = env* this.sawoscillatorl.next() + this.signal.right * 0.5; | |
left = this.shaper.process(left); | |
let right = env* this.sawoscillatorr.next() + this.signal.left * 0.5; | |
right = this.shaper.process(right); | |
this.signal.left = left * 0.5 + right; | |
this.signal.right = right * 0.5 + left; | |
} | |
} | |
const sinelead = new SineLead(); | |
const drivelead = new DriveLead(); | |
const deepbass = new DeepBass(); | |
const pianos: SubPiano[] = createInstrumentArray<SubPiano>(5, () => new SubPiano()); | |
export function setChannelValue(channel: usize, value: f32): void { | |
const setChannelValueFunctions: usize[] = [ | |
changetype<usize>((value:f32): void => {sinelead.note = value;}), | |
changetype<usize>((value:f32): void => {deepbass.note = value;}), | |
changetype<usize>((value:f32): void => {pads[0].note = value;}), | |
changetype<usize>((value:f32): void => {pads[1].note = value;}), | |
changetype<usize>((value:f32): void => {pads[2].note = value;}), | |
changetype<usize>((value:f32): void => {drivelead.note = value;}), | |
changetype<usize>((value:f32): void => {kick.note = value;}), | |
changetype<usize>((value:f32): void => {snare.note = value;}), | |
changetype<usize>((value:f32): void => {hihat.note = value;}), | |
changetype<usize>((value:f32): void => { | |
if(value > 0) { | |
padsVolume = value / 100.0; | |
} | |
}), | |
changetype<usize>((value:f32): void => { | |
if(value > 0) { | |
drivelead.setPitchbend((value - 64) / 32); | |
} | |
}), | |
changetype<usize>((value:f32): void => { | |
if(value > 0) { | |
masterlopassfilterleft.update_coeffecients( | |
FilterType.LowPass, SAMPLERATE, ((value - 1)/ 127.0) * 20000.0, Q_BUTTERWORTH); | |
masterlopassfilterright.update_coeffecients( | |
FilterType.LowPass, SAMPLERATE, ((value - 1 )/ 127.0) * 20000.0, Q_BUTTERWORTH); | |
} | |
}), | |
changetype<usize>((value:f32): void => {pianos[0].note = value;}), | |
changetype<usize>((value:f32): void => {pianos[1].note = value;}), | |
changetype<usize>((value:f32): void => {pianos[2].note = value;}), | |
changetype<usize>((value:f32): void => {pianos[3].note = value;}), | |
changetype<usize>((value:f32): void => {pianos[4].note = value;}), | |
]; | |
changetype<(val: f32) => void>(setChannelValueFunctions[channel])(value); | |
} | |
const mainline = new StereoSignal(); | |
const reverbline = new StereoSignal(); | |
const freeverb = new Freeverb(); | |
const delayframes = (SAMPLERATE * (6/8) * 60 / 120) as usize; | |
let delayLeft: DelayLine = new DelayLine(delayframes); | |
let delayRight: DelayLine = new DelayLine(delayframes); | |
let echoline = new StereoSignal(); | |
export function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { | |
let left: f32 = 0; | |
let right: f32 = 0; | |
mainline.clear(); | |
reverbline.clear(); | |
echoline.clear(); | |
bass.next(); | |
mainline.addStereoSignal(bass.signal, 1.3, 0.5); | |
reverbline.addStereoSignal(bass.signal, 0.3, 0.5); | |
deepbass.next(); | |
mainline.addStereoSignal(deepbass.signal, 1.2, 0.5); | |
echoline.addStereoSignal(deepbass.signal, 0.3, 0.5); | |
lead.next(); | |
mainline.addStereoSignal(lead.signal, 1.4, 0.5); | |
echoline.addStereoSignal(lead.signal, 1.0, 0.5); | |
drivelead.next(); | |
mainline.addStereoSignal(drivelead.signal, 0.2, 0.3); | |
echoline.addStereoSignal(drivelead.signal, 0.45, 0.7); | |
sinelead.next(); | |
mainline.addStereoSignal(sinelead.signal, 1.6, 0.6); | |
echoline.addStereoSignal(sinelead.signal, 0.8, 0.5); | |
kick.next(); | |
mainline.addStereoSignal(kick.signal, 1.6, 0.5); | |
reverbline.addStereoSignal(snare.signal, 0.1, 0.5); | |
snare.next(); | |
mainline.addStereoSignal(snare.signal, 1.0, 0.5); | |
reverbline.addStereoSignal(snare.signal, 0.1, 0.5); | |
hihat.next(); | |
mainline.addStereoSignal(hihat.signal, 1.0, 0.5); | |
reverbline.addStereoSignal(hihat.signal, 0.1, 0.5); | |
pads.forEach(pad => { | |
pad.next(); | |
mainline.addStereoSignal(pad.signal, 0.45 * padsVolume, 0.5); | |
reverbline.addStereoSignal(pad.signal, 0.2, 0.5); | |
}); | |
pianos.forEach(piano => { | |
piano.next(); | |
mainline.addStereoSignal(piano.signal, 0.3, 0.5); | |
echoline.addStereoSignal(piano.signal, 0.1, 0.5); | |
}); | |
echoline.left += delayRight.read() * 0.7; | |
echoline.right += delayLeft.read() * 0.7; | |
delayLeft.write_and_advance(echoline.left); | |
delayRight.write_and_advance(echoline.right); | |
freeverb.tick(reverbline); | |
left = gain * (mainline.left + reverbline.left + echoline.left); | |
right = gain * (mainline.right + reverbline.right + echoline.right); | |
left = masterlopassfilterleft.process(left); | |
right = masterlopassfilterright.process(right); | |
left = tribandeqleft.process(left,1.0, 0.7, 1.0); | |
right = tribandeqright.process(right,1.0, 0.7, 1.0); | |
left = softclip(left); | |
right = softclip(right); | |
store<f32>(leftSampleBufferPtr, left); | |
store<f32>(rightSampleBufferPtr, right); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment