diff --git a/wasmaudioworklet/synth1/assembly/__tests__/midi/midisynth.spec.ts b/wasmaudioworklet/synth1/assembly/__tests__/midi/midisynth.spec.ts index e7088069..1702a5b2 100644 --- a/wasmaudioworklet/synth1/assembly/__tests__/midi/midisynth.spec.ts +++ b/wasmaudioworklet/synth1/assembly/__tests__/midi/midisynth.spec.ts @@ -117,7 +117,7 @@ class UpperKeys extends MidiVoice { class LinearVoice extends MidiVoice { pos: f32 = 0.0; - nextframe(): void { + nextframe(): void { const val = this.pos / 128; this.channel.signal.add(val, val); this.pos++; @@ -686,17 +686,17 @@ describe("midisynth", () => { for (let n = 0; n < 64; n++) { expect(samplebuffer[n]).toBe((n / 128.0) as f32); } - + for (let n = 64; n < 128; n++) { expect(samplebuffer[n]).toBe(0); } fillSampleBufferWithNumSamples(64); - + for (let n = 0; n < 64; n++) { - expect(samplebuffer[n]).toBe(((n+64) / 128.0) as f32); + expect(samplebuffer[n]).toBe(((n + 64) / 128.0) as f32); } - + for (let n = 64; n < 128; n++) { expect(samplebuffer[n]).toBe(0); } diff --git a/wasmaudioworklet/synth1/assembly/midi/midisynth.ts b/wasmaudioworklet/synth1/assembly/midi/midisynth.ts index 6ebb6622..6465ba09 100644 --- a/wasmaudioworklet/synth1/assembly/midi/midisynth.ts +++ b/wasmaudioworklet/synth1/assembly/midi/midisynth.ts @@ -83,7 +83,7 @@ export class MidiChannel { if (voice.note === note) { if (this.controllerValues[CONTROL_SUSTAIN] >= 64) { this.sustainedVoices[note] = voice; - } else { + } else { voice.noteoff(); } break; @@ -142,15 +142,15 @@ export class MidiChannel { } if (oldestVoice !== null) { const voice = (oldestVoice as MidiVoice); - for (let n = 0;n(length: i32, factoryFunc: () => T): T[] {\n const arr = new Array(length);\n for(let n = 0; n < length;n++) {\n arr[n] = factoryFunc();\n }\n return arr;\n}\n","environment.ts":"// earlier this used to externally declared\nexport const SAMPLERATE: f32 = 44100;","fx/allpass.ts":"import { DelayLine } from \"./delayline\";\n\nexport class AllPass {\n readonly delay_line: DelayLine;\n\n constructor(delay_length: usize) {\n this.delay_line = new DelayLine(delay_length);\n }\n\n tick(input: f32): f32 {\n let delayed: f32 = this.delay_line.read();\n let output: f32 = -input + delayed;\n\n // in the original version of freeverb this is a member which is never modified\n const feedback: f32 = 0.5;\n\n this.delay_line\n .write_and_advance(input + delayed * feedback);\n\n return output;\n }\n}\n\nexport class AllPassFloat {\n coeff: f32;\n previousinput: f32;\n previousoutput: f32;\n\n setDelta(delta: f32): void {\n this.coeff = (1 - delta) / (1 + delta);\n }\n\n clearBuffers(): void {\n this.previousinput = 0;\n this.previousoutput = 0;\n }\n\n process(input: f32): f32 {\n const output = this.coeff * (input\n - this.previousoutput)\n + this.previousinput;\n this.previousoutput = output;\n this.previousinput = input;\n return output;\n }\n}\n","fx/bandpass.ts":"import { BiQuadFilter, FilterType, Q_BUTTERWORTH } from \"../synth/biquad\";\nimport { SAMPLERATE } from \"../environment\";\n\nexport class BandPass {\n lpfilter: BiQuadFilter = new BiQuadFilter();\n hpfilter: BiQuadFilter = new BiQuadFilter();\n \n constructor(lowfreq: f32, hifreq: f32) {\n this.update_frequencies(lowfreq, hifreq);\n }\n\n clearBuffers(): void {\n this.hpfilter.clearBuffers();\n this.lpfilter.clearBuffers();\n }\n\n update_frequencies(lowfreq: f32, hifreq: f32): void {\n this.lpfilter.update_coeffecients(FilterType.LowPass, SAMPLERATE, hifreq, Q_BUTTERWORTH);\n this.hpfilter.update_coeffecients(FilterType.HighPass, SAMPLERATE, lowfreq, Q_BUTTERWORTH);\n }\n\n process(sample: f32): f32 {\n return this.lpfilter.process(this.hpfilter.process(sample)); \n }\n}","fx/comb.ts":"import { DelayLine } from \"./delayline\";\n\nexport class Comb {\n readonly delay_line: DelayLine;\n feedback: f32;\n filter_state: f32;\n dampening: f32;\n dampening_inverse: f32;\n\n constructor(delay_length: usize) { \n this.delay_line = new DelayLine(delay_length);\n this.feedback= 0.5;\n this.filter_state = 0.0;\n this.dampening = 0.5;\n this.dampening_inverse = 0.5;\n \n }\n\n set_dampening(value: f32): void{\n this.dampening = value;\n this.dampening_inverse = 1.0 - value;\n }\n\n set_feedback(value: f32): void {\n this.feedback = value;\n }\n\n tick(input: f32): f32 {\n let output = this.delay_line.read();\n\n this.filter_state =\n output * this.dampening_inverse + this.filter_state * this.dampening;\n\n this.delay_line\n .write_and_advance(input + this.filter_state * this.feedback);\n\n return output;\n }\n}\n","fx/delayline.ts":"import { AllPassFloat } from \"./allpass\";\n\nexport class DelayLine {\n readonly bufferPointer: usize;\n index: usize = 0;\n length: usize = 0;\n currentPeak: f32 = 0;\n currentPeakSamplesToLive: usize = 0;\n\n private numsamplesf64: f64 = 0\n private meanSquared: f64 = 0;\n\n constructor(private numsamples: usize) {\n this.numsamplesf64 = numsamples as f64;\n this.length = numsamples * 4 as usize;\n this.bufferPointer = __new(this.length, 0);\n }\n\n read(): f32 {\n return load(this.bufferPointer + this.index);\n }\n\n calculateRMS(): f32 {\n let ndx = this.index;\n let bufferPointer = this.bufferPointer;\n\n let leastrecentsample: f64 = load(bufferPointer + ndx) as f64;\n if (ndx === 0) {\n ndx = this.length;\n }\n ndx -= 4;\n let mostrecentsample: f64 = load(bufferPointer + ndx) as f64;\n\n let meanSquared: f64 = this.meanSquared;\n let numSamples: f64 = this.numsamplesf64;\n meanSquared += ((mostrecentsample * mostrecentsample) / numSamples);\n meanSquared -= ((leastrecentsample * leastrecentsample) / numSamples);\n this.meanSquared = meanSquared;\n\n return Math.sqrt(meanSquared) as f32;\n }\n\n getPeakValue(): f32 {\n let ndx = this.index;\n if (ndx === 0) {\n ndx = this.length;\n }\n ndx -= 4;\n let mostrecentsample: f32 = load(this.bufferPointer + ndx) as f32;\n if (mostrecentsample < 0) {\n mostrecentsample = -mostrecentsample;\n }\n if (mostrecentsample > this.currentPeak) {\n this.currentPeak = mostrecentsample;\n this.currentPeakSamplesToLive = this.numsamples;\n } else if (this.currentPeakSamplesToLive > 0) {\n this.currentPeakSamplesToLive--;\n }\n if (this.currentPeakSamplesToLive == 0) {\n this.currentPeak = this.calculatePeakValue();\n }\n return this.currentPeak;\n }\n\n private calculatePeakValue(): f32 {\n let peak: f32 = 0.0;\n for (let i: usize = 0; i < this.length; i += 4) {\n let value = load(this.bufferPointer + i);\n if (value < 0) {\n value = -value;\n }\n if (value > peak) {\n peak = value;\n this.currentPeakSamplesToLive = ((i >= this.index) ? (i - this.index) : ((this.length) - this.index) + i) >> 2;\n }\n }\n return peak;\n }\n\n write_and_advance(value: f32): void {\n store(this.bufferPointer + this.index, value);\n\n if (this.index === this.length - 4) {\n this.index = 0;\n } else {\n this.index += 4;\n }\n }\n}\n\nexport class DelayLineFloat {\n buffer: StaticArray;\n frame: f64 = 0;\n numframes: f64 = 1;\n previous: f32;\n allpass: AllPassFloat = new AllPassFloat();\n\n constructor(private buffersizeframes: i32) {\n this.buffer = new StaticArray(buffersizeframes);\n }\n\n read(): f32 {\n const index = this.frame as i32 % this.buffer.length;\n return this.allpass.process(this.buffer[index]);\n }\n\n reset(): void {\n this.allpass.previousoutput = 0;\n this.allpass.previousinput = 0;\n for (let n = 0; n < this.numframes; n++) {\n this.buffer[n] = 0;\n }\n this.frame = 0;\n }\n\n setNumFramesAndClear(numframes: f64): void {\n this.numframes = Math.floor(numframes);\n this.allpass.setDelta((numframes - this.numframes) as f32);\n this.reset();\n }\n\n write_and_advance(value: f32): void {\n const index = ((this.frame++) + this.numframes) as i32 % this.buffer.length;\n this.buffer[index] = value;\n }\n}\n","fx/eqband.ts":"import { BiQuadFilter, FilterType, Q_BUTTERWORTH } from \"../synth/biquad\";\nimport { SAMPLERATE } from \"../environment\";\n\nexport class EQBand {\n lpfilter: BiQuadFilter = new BiQuadFilter();\n hpfilter: BiQuadFilter = new BiQuadFilter();\n lpfilter2: BiQuadFilter = new BiQuadFilter();\n hpfilter2: BiQuadFilter = new BiQuadFilter();\n \n \n constructor(lowfreq: f32, hifreq: f32) {\n this.lpfilter.update_coeffecients(FilterType.LowPass, SAMPLERATE, hifreq, Q_BUTTERWORTH);\n this.lpfilter2.update_coeffecients(FilterType.LowPass, SAMPLERATE, hifreq, Q_BUTTERWORTH);\n this.hpfilter.update_coeffecients(FilterType.HighPass, SAMPLERATE, lowfreq, Q_BUTTERWORTH);\n this.hpfilter2.update_coeffecients(FilterType.HighPass, SAMPLERATE, lowfreq, Q_BUTTERWORTH); \n }\n\n process(left: f32): f32 {\n return this.lpfilter2.process(this.lpfilter.process(this.hpfilter2.process(this.hpfilter.process(left)))); \n }\n}","fx/freeverb.ts":"\n/**\n * Freeverb implementation taken from Rust implementation here:\n * https://github.com/irh/freeverb-rs/blob/master/freeverb/src/freeverb.rs\n */\nimport { Comb } from './comb';\nimport { AllPass } from './allpass';\nimport { SAMPLERATE as SAMPLERATE_f32 } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\n\nlet SAMPLERATE = SAMPLERATE_f32 as usize;\nconst FIXED_GAIN: f32 = 0.015;\n\nconst SCALE_WET: f32 = 3.0;\nconst SCALE_DAMPENING: f32 = 0.4;\n\nconst SCALE_ROOM: f32 = 0.28;\nconst OFFSET_ROOM: f32 = 0.7;\n\nconst STEREO_SPREAD: usize = 23;\n\nconst COMB_TUNING_L1: usize = 1116;\nconst COMB_TUNING_R1: usize = 1116 + STEREO_SPREAD;\nconst COMB_TUNING_L2: usize = 1188;\nconst COMB_TUNING_R2: usize = 1188 + STEREO_SPREAD;\nconst COMB_TUNING_L3: usize = 1277;\nconst COMB_TUNING_R3: usize = 1277 + STEREO_SPREAD;\nconst COMB_TUNING_L4: usize = 1356;\nconst COMB_TUNING_R4: usize = 1356 + STEREO_SPREAD;\nconst COMB_TUNING_L5: usize = 1422;\nconst COMB_TUNING_R5: usize = 1422 + STEREO_SPREAD;\nconst COMB_TUNING_L6: usize = 1491;\nconst COMB_TUNING_R6: usize = 1491 + STEREO_SPREAD;\nconst COMB_TUNING_L7: usize = 1557;\nconst COMB_TUNING_R7: usize = 1557 + STEREO_SPREAD;\nconst COMB_TUNING_L8: usize = 1617;\nconst COMB_TUNING_R8: usize = 1617 + STEREO_SPREAD;\n\nconst ALLPASS_TUNING_L1: usize = 556;\nconst ALLPASS_TUNING_R1: usize = 556 + STEREO_SPREAD;\nconst ALLPASS_TUNING_L2: usize = 441;\nconst ALLPASS_TUNING_R2: usize = 441 + STEREO_SPREAD;\nconst ALLPASS_TUNING_L3: usize = 341;\nconst ALLPASS_TUNING_R3: usize = 341 + STEREO_SPREAD;\nconst ALLPASS_TUNING_L4: usize = 225;\nconst ALLPASS_TUNING_R4: usize = 225 + STEREO_SPREAD;\n\nfunction adjust_length(length: usize, sr: usize): usize {\n return ((length as f32) * (sr as f32) / SAMPLERATE_f32) as usize;\n}\n\nexport class Freeverb { \n readonly COMB1_L: Comb = new Comb(adjust_length(COMB_TUNING_L1, SAMPLERATE));\n readonly COMB1_R: Comb = new Comb(adjust_length(COMB_TUNING_L1, SAMPLERATE));\n readonly COMB2_L: Comb = new Comb(adjust_length(COMB_TUNING_R2, SAMPLERATE));\n readonly COMB2_R: Comb = new Comb(adjust_length(COMB_TUNING_L2, SAMPLERATE));\n readonly COMB3_L: Comb = new Comb(adjust_length(COMB_TUNING_R3, SAMPLERATE));\n readonly COMB3_R: Comb = new Comb(adjust_length(COMB_TUNING_L3, SAMPLERATE));\n readonly COMB4_L: Comb = new Comb(adjust_length(COMB_TUNING_R4, SAMPLERATE));\n readonly COMB4_R: Comb = new Comb(adjust_length(COMB_TUNING_L4, SAMPLERATE));\n readonly COMB5_L: Comb = new Comb(adjust_length(COMB_TUNING_R5, SAMPLERATE));\n readonly COMB5_R: Comb = new Comb(adjust_length(COMB_TUNING_L5, SAMPLERATE));\n readonly COMB6_L: Comb = new Comb(adjust_length(COMB_TUNING_R6, SAMPLERATE));\n readonly COMB6_R: Comb = new Comb(adjust_length(COMB_TUNING_L6, SAMPLERATE));\n readonly COMB7_L: Comb = new Comb(adjust_length(COMB_TUNING_R7, SAMPLERATE));\n readonly COMB7_R: Comb = new Comb(adjust_length(COMB_TUNING_L7, SAMPLERATE));\n readonly COMB8_L: Comb = new Comb(adjust_length(COMB_TUNING_R8, SAMPLERATE));\n readonly COMB8_R: Comb = new Comb(adjust_length(COMB_TUNING_L8, SAMPLERATE));\n\n readonly ALL1_L: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_L1, SAMPLERATE));\n readonly ALL1_R: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_R1, SAMPLERATE));\n readonly ALL2_L: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_L2, SAMPLERATE));\n readonly ALL2_R: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_R2, SAMPLERATE));\n readonly ALL3_L: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_L3, SAMPLERATE));\n readonly ALL3_R: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_R3, SAMPLERATE));\n readonly ALL4_L: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_L4, SAMPLERATE));\n readonly ALL4_R: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_R4, SAMPLERATE));\n\n wet_gain_left: f32 = 0;\n wet_gain_right: f32 = 0;\n \n wet: f32 = 0;\n width: f32 = 0;\n dry: f32 = 0;\n input_gain: f32 = 0;\n dampening: f32 = 0;\n room_size: f32 = 0;\n frozen: bool = 0;\n\n constructor() {\n this.set_wet(1.0);\n this.set_width(0.5);\n this.set_dampening(0.5);\n this.set_room_size(0.7);\n this.set_frozen(false); \n }\n\n tick(signal: StereoSignal): void {\n let input_mixed = (signal.left + signal.right) * FIXED_GAIN * this.input_gain;\n\n let leftoutput:f32 = 0;\n let rightoutput:f32 = 0;\n\n leftoutput += this.COMB1_L.tick(input_mixed);\n rightoutput+= this.COMB1_R.tick(input_mixed);\n leftoutput += this.COMB2_L.tick(input_mixed);\n rightoutput+= this.COMB2_R.tick(input_mixed);\n leftoutput += this.COMB3_L.tick(input_mixed);\n rightoutput+= this.COMB3_R.tick(input_mixed);\n leftoutput += this.COMB4_L.tick(input_mixed);\n rightoutput+= this.COMB4_R.tick(input_mixed);\n leftoutput += this.COMB5_L.tick(input_mixed);\n rightoutput+= this.COMB5_R.tick(input_mixed);\n leftoutput += this.COMB6_L.tick(input_mixed);\n rightoutput+= this.COMB6_R.tick(input_mixed);\n leftoutput += this.COMB7_L.tick(input_mixed);\n rightoutput+= this.COMB7_R.tick(input_mixed);\n leftoutput += this.COMB8_L.tick(input_mixed);\n rightoutput+= this.COMB8_R.tick(input_mixed);\n \n leftoutput= this.ALL1_L.tick(leftoutput);\n rightoutput = this.ALL1_R.tick(rightoutput);\n leftoutput= this.ALL2_L.tick(leftoutput);\n rightoutput = this.ALL2_R.tick(rightoutput);\n leftoutput= this.ALL3_L.tick(leftoutput);\n rightoutput = this.ALL3_R.tick(rightoutput);\n leftoutput= this.ALL4_L.tick(leftoutput);\n rightoutput = this.ALL4_R.tick(rightoutput);\n\n signal.left = leftoutput * this.wet_gain_left +\n rightoutput * this.wet_gain_right +\n signal.left * this.dry;\n signal.right = rightoutput * this.wet_gain_left +\n leftoutput * this.wet_gain_right +\n signal.right * this.dry; \n }\n\n update_combs(): void {\n let feedback: f32;\n let dampening: f32;\n\n if(this.frozen) {\n feedback =1.0;\n dampening = 0.0;\n } else {\n feedback = this.room_size;\n dampening = this.dampening;\n }\n \n this.COMB1_L.set_feedback(feedback);\n this.COMB1_R.set_feedback(feedback);\n this.COMB1_L.set_dampening(dampening);\n this.COMB1_R.set_dampening(dampening);\n this.COMB2_L.set_feedback(feedback);\n this.COMB2_R.set_feedback(feedback);\n this.COMB2_L.set_dampening(dampening);\n this.COMB2_R.set_dampening(dampening);\n this.COMB3_L.set_feedback(feedback);\n this.COMB3_R.set_feedback(feedback);\n this.COMB3_L.set_dampening(dampening);\n this.COMB3_R.set_dampening(dampening);\n this.COMB4_L.set_feedback(feedback);\n this.COMB4_R.set_feedback(feedback);\n this.COMB4_L.set_dampening(dampening);\n this.COMB4_R.set_dampening(dampening);\n this.COMB5_L.set_feedback(feedback);\n this.COMB5_R.set_feedback(feedback);\n this.COMB5_L.set_dampening(dampening);\n this.COMB5_R.set_dampening(dampening);\n this.COMB6_L.set_feedback(feedback);\n this.COMB6_R.set_feedback(feedback);\n this.COMB6_L.set_dampening(dampening);\n this.COMB6_R.set_dampening(dampening);\n this.COMB7_L.set_feedback(feedback);\n this.COMB7_R.set_feedback(feedback);\n this.COMB7_L.set_dampening(dampening);\n this.COMB7_R.set_dampening(dampening);\n this.COMB8_L.set_feedback(feedback);\n this.COMB8_R.set_feedback(feedback);\n this.COMB8_L.set_dampening(dampening);\n this.COMB8_R.set_dampening(dampening);\n }\n\n set_dampening(value: f32): void {\n this.dampening = value * SCALE_DAMPENING;\n this.update_combs();\n }\n\n set_freeze(frozen: bool): void {\n this.frozen = frozen;\n this.update_combs();\n }\n\n set_wet(value: f32): void {\n this.wet = value * SCALE_WET;\n this.update_wet_gains();\n }\n\n set_width(value: f32): void {\n this.width = value;\n this.update_wet_gains();\n }\n\n update_wet_gains(): void {\n this.wet_gain_left = this.wet * (this.width / 2.0 + 0.5);\n this.wet_gain_right = this.wet * ((1.0 - this.width) / 2.0); \n }\n\n set_frozen(frozen: bool): void {\n this.frozen = frozen;\n this.input_gain = frozen ? 0.0 : 1.0;\n this.update_combs();\n }\n\n set_room_size(value: f32): void {\n this.room_size = value * SCALE_ROOM + OFFSET_ROOM;\n this.update_combs();\n }\n\n set_dry(value: f32): void {\n this.dry = value;\n }\n}\n","fx/limiter.ts":"import { SAMPLERATE } from '../environment';\n\nexport class Limiter {\n attack: f32 = 0;\n release: f32 = 0;\n envelope: f32 = 0;\n\n constructor(attackMs: f32, releaseMs: f32) {\n this.attack = Mathf.pow(0.01, 1.0 / (attackMs * SAMPLERATE * 0.001));\n this.release = Mathf.pow(0.01, 1.0 / (releaseMs * SAMPLERATE * 0.001));\n }\n\n process(signal: f32): f32 {\n const v = Mathf.abs(signal);\n if (v > this.envelope) {\n this.envelope = this.attack * (this.envelope - v) + v;\n } else {\n this.envelope = this.release * (this.envelope - v) + v;\n }\n\n if (this.envelope > 1) {\n signal /= this.envelope;\n }\n return signal;\n }\n}\n","fx/midsideprocessor.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nexport class MidSideProcessor {\n signal: StereoSignal = new StereoSignal();\n\n constructor(private side_level: f32) {\n\n }\n\n process(left: f32, right: f32): void {\n // Mid-side processing\n let mid: f32 = (left + right) / 2.0;\n let side: f32 = (left - right) / 2.0;\n\n side *= this.side_level;\n this.signal.left = mid + side;\n this.signal.right = mid - side;\n }\n}","fx/monocompressor.ts":"import { DelayLine } from \"./delayline\";\nexport class MonoCompressor {\n delay: DelayLine;\n\n gain: f64 = 1.0;\n targetgain: f64 = 1.0;\n gainChangePerSample: f64 = 0;\n delaybuffersamplecount: f64;\n releasesamplecount: f64;\n\n constructor(numsamples: usize) {\n this.delay = new DelayLine(numsamples);\n this.delaybuffersamplecount = numsamples as f64;\n this.releasesamplecount = this.delaybuffersamplecount;\n }\n\n setRelaseSampleCount(releasesamplecount: f64): void {\n this.releasesamplecount = releasesamplecount;\n }\n\n process(signal: f32, threshold: f32, makeupgain: f32): f32 {\n this.delay.write_and_advance(signal);\n\n let currentTargetGain: f64 = this.targetgain;\n let currentGain: f64 = this.gain;\n\n let peak: f64 = this.delay.getPeakValue();\n\n if(peak > threshold) {\n let targetGain = threshold / peak;\n\n if(targetGain < currentTargetGain) {\n currentTargetGain = targetGain;\n this.targetgain = targetGain;\n\n let newGainChangePerSample = (currentTargetGain - currentGain) / this.delaybuffersamplecount;\n \n if(newGainChangePerSample < this.gainChangePerSample) {\n this.gainChangePerSample = newGainChangePerSample;\n }\n } \n } else if(currentTargetGain < 1.0) {\n currentTargetGain = 1.0;\n this.targetgain = currentTargetGain; \n this.gainChangePerSample = (currentTargetGain - currentGain) / this.releasesamplecount;\n }\n\n let gainChangePerSample: f64 = this.gainChangePerSample;\n if((gainChangePerSample < 0 && currentTargetGain < currentGain) ||\n (gainChangePerSample > 0 && currentTargetGain > currentGain)) {\n currentGain += gainChangePerSample;\n this.gain = currentGain;\n }\n\n return this.delay.read() * currentGain as f32 * makeupgain;\n }\n}\n\nexport class StereoCompressor {\n leftCompressor: MonoCompressor;\n rightCompressor: MonoCompressor;\n\n resultSignal: StereoSignal = new StereoSignal();\n \n constructor(numsamples: usize) {\n this.leftCompressor = new MonoCompressor(numsamples);\n this.rightCompressor = new MonoCompressor(numsamples);\n }\n\n process(left: f32, right: f32, threshold: f32, makeupgain: f32): void {\n this.resultSignal.left = this.leftCompressor.process(left, threshold, makeupgain);\n \tthis.resultSignal.right = this.rightCompressor.process(right, threshold, makeupgain); \n }\n}\n","fx/multibandeq.ts":"import { EQBand } from './eqband';\nexport class MultiBandEQ {\n bands: StaticArray;\n\n constructor(freqs: f32[]) {\n this.bands = new StaticArray(freqs.length - 1);\n for (let n = 1; n < freqs.length; n++) {\n this.bands[n - 1] = new EQBand(freqs[n - 1], freqs[n]);\n }\n }\n\n\n process(signal: f32, levels: f32[]): f32 {\n let ret: f32 = 0;\n const numbands = this.bands.length;\n for (let n = 0; n < numbands; n++) {\n ret += this.bands[n].process(signal) * levels[n];\n }\n return ret;\n }\n}\n","fx/stereocompressor.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\nimport { MonoCompressor } from \"./monocompressor\";\n\nexport class StereoCompressor {\n leftCompressor: MonoCompressor;\n rightCompressor: MonoCompressor;\n\n resultSignal: StereoSignal = new StereoSignal();\n \n constructor(numsamples: usize) {\n this.leftCompressor = new MonoCompressor(numsamples);\n this.rightCompressor = new MonoCompressor(numsamples);\n }\n\n process(left: f32, right: f32, threshold: f32, makeupgain: f32): void {\n this.resultSignal.left = this.leftCompressor.process(left, threshold, makeupgain);\n \tthis.resultSignal.right = this.rightCompressor.process(right, threshold, makeupgain); \n }\n}\n","fx/tribandeq.ts":"import { EQBand } from \"./eqband\";\n\nexport class TriBandEQ {\n \n lowerband: EQBand;\n midband: EQBand;\n hiband: EQBand;\n\n constructor(low: f32, midlo: f32, midhi: f32, high: f32) {\n this.lowerband = new EQBand(low, midlo);\n this.midband = new EQBand(midlo, midhi);\n this.hiband = new EQBand(midhi, high);\n }\n\n process(signal: f32, lolevel: f32, midlevel: f32, hilevel: f32): f32 {\n return this.lowerband.process(signal) * lolevel +\n this.midband.process(signal) * midlevel +\n this.hiband.process(signal) * hilevel;\n }\n}","fx/tribandstereocompressor.ts":"import { EQBand } from \"./eqband\";\nimport { StereoSignal } from \"../synth/stereosignal.class\";\nimport { StereoCompressor } from \"./stereocompressor\";\nimport { SAMPLERATE } from \"../environment\";\n\nexport class TriBandStereoCompressor {\n lowerbandl: EQBand; \n midbandl: EQBand; \n hibandl: EQBand;\n \n lowerbandr: EQBand; \n midbandr: EQBand; \n hibandr: EQBand;\n \n compressorLow: StereoCompressor;\n compressorMid: StereoCompressor;\n compressorHigh: StereoCompressor;\n\n stereosignal: StereoSignal = new StereoSignal();\n\n constructor(low: f32, midlo: f32, midhi: f32, high: f32, compressor_delay: f32 = 0.2) {\n this.compressorLow = new StereoCompressor((SAMPLERATE * compressor_delay) as usize);\n this.compressorMid = new StereoCompressor((SAMPLERATE * compressor_delay) as usize);\n this.compressorHigh = new StereoCompressor((SAMPLERATE * compressor_delay) as usize);\n\n this.lowerbandl = new EQBand(low, midlo);\n this.lowerbandr = new EQBand(low, midlo);\n \n this.midbandl = new EQBand(midlo, midhi);\n this.midbandr = new EQBand(midlo, midhi);\n \n this.hibandl = new EQBand(midhi, high);\n this.hibandr = new EQBand(midhi, high);\n }\n\n process(left: f32, right: f32, \n lolevel: f32, \n midlevel: f32, \n hilevel: f32,\n lomakeupgain: f32,\n midmakeupgain: f32,\n himakeupgain: f32): void {\n let lowleft = this.lowerbandl.process(left);\n let midleft = this.midbandl.process(left);\n let hileft = this.hibandl.process(left);\n\n let lowright = this.lowerbandr.process(right);\n let midright = this.midbandr.process(right);\n let hiright = this.hibandr.process(right);\n\n this.compressorLow.process(lowleft,lowright,lolevel,lomakeupgain);\n this.compressorMid.process(midleft,midright,midlevel,midmakeupgain);\n this.compressorHigh.process(hileft,hiright,hilevel,himakeupgain);\n \n this.stereosignal.left = this.compressorLow.resultSignal.left + this.compressorMid.resultSignal.left + this.compressorHigh.resultSignal.left;\n this.stereosignal.right = this.compressorLow.resultSignal.right + this.compressorMid.resultSignal.right + this.compressorHigh.resultSignal.right;\n }\n}","index.ts":"// The entry file of the synth WebAssembly module.\n\n// --- Replace with your own mix implementation here\nimport { mixernext, setChannelValue, PATTERN_SIZE_SHIFT, BEATS_PER_PATTERN_SHIFT } from './mixes/newyear.mix';\nexport { setChannelValue } from './mixes/newyear.mix';\n// -------------------------------------------------\n\nimport { SAMPLERATE } from './environment';\n\nconst PATTERN_LENGTH: f32 = (1 << PATTERN_SIZE_SHIFT) as f32;\n\nlet NUM_INSTRUMENTS: i32;\n\nlet holdChannelValuesBufferPtr: usize;\nlet currentChannelValuesBufferPtr: usize;\nlet patternsPtr: usize;\nlet instrumentPatternListsPtr: usize;\nlet sampleBufferPtr: usize;\nlet sampleBufferFrames: usize;\nlet songlength: usize = 0;\n\nlet patternIndexf64: f64 = 0;\nlet patternIndex: usize = 0; \nlet patternNoteIndex: usize = -1;\n\nlet tick: f64 = 0;\nlet ticksPerBeat: f32 = (1 << PATTERN_SIZE_SHIFT >> BEATS_PER_PATTERN_SHIFT) as f32;\nlet bpm: f32 = 120;\n\nlet ticksPerSec = ticksPerBeat * bpm / 60;\nlet ticksPerSample = ticksPerSec / SAMPLERATE;\n\nlet playOrPause: boolean = true;\n\nexport function setBPM(BPM: f32): void {\n bpm = BPM;\n ticksPerSec = ticksPerBeat * BPM / 60;\n ticksPerSample = ticksPerSec / SAMPLERATE;\n}\n\nexport function setTick(newtick: f64): void {\n tick = newtick;\n}\n\nexport function getTick(): f64 {\n return tick;\n}\n\nexport function setMilliSecondPosition(millis: f64): void {\n let newtick: f64 = millis * ticksPerSec / 1000;\n let ticklength = songlength as f64 * PATTERN_LENGTH;\n\n newtick -= (floor(newtick / ticklength) * ticklength);\n if(abs(newtick - tick) > 1) {\n tick = newtick;\n }\n}\n\nexport function getPatternIndex(): usize {\n return patternIndex;\n}\n\nexport function getPatternNoteIndex(): usize {\n return patternNoteIndex;\n}\n\nexport function toggleSongPlay(status: boolean): void {\n if(!status && playOrPause) {\n for(let n=0;n songlengthf64) {\n tick -= (songlengthf64 * PATTERN_LENGTH); \n }\n\n patternIndexf64 = (tick / PATTERN_LENGTH) as f64;\n patternIndex = patternIndexf64 as usize; \n let newPatternNoteIndex: usize = ((patternIndexf64 - (patternIndex as f64)) * PATTERN_LENGTH) as usize;\n\n if(newPatternNoteIndex===patternNoteIndex) {\n return;\n }\n\n patternNoteIndex = newPatternNoteIndex;\n \n for(let n=0;n(instrumentPatternListsPtr +\n n * songlength +\n patternIndex) as usize;\n \n let channelValue: f32 = load(patternsPtr + (instrumentPatternIndex << PATTERN_SIZE_SHIFT)\n + patternNoteIndex) as f32;\n \n let holdChannelValue: f32 = load(holdChannelValuesBufferPtr + n * 4);\n if(holdChannelValue > 0 && channelValue !== 1 && channelValue !== holdChannelValue) {\n // Hold value\n channelValue = 1;\n store(patternsPtr + (instrumentPatternIndex << PATTERN_SIZE_SHIFT)\n + patternNoteIndex, 1 as u8);\n }\n\n // 1 means HOLD value - no change to the visualizer \n if(channelValue !== 1) { \n // For external visualizer to monitor channel values currently been played by the sequencer \n store(currentChannelValuesBufferPtr + n*4, channelValue);\n setChannelValue(n, channelValue);\n } \n }\n}\n\nexport function getHoldChannelValuesBufferPtr(): usize {\n return holdChannelValuesBufferPtr;\n}\n\nexport function recordChannelValue(channel: usize, value: f32): void {\n store(holdChannelValuesBufferPtr + channel * 4, value);\n setChannelValue(channel, value);\n}\n\nexport function setPatternsPtr(ptr: usize): void {\n patternsPtr = ptr;\n}\n\nexport function allocatePatterns(numpatterns: i32): usize {\n patternsPtr = __new(numpatterns << PATTERN_SIZE_SHIFT, idof>());\n return patternsPtr;\n}\n\nexport function setInstrumentPatternListPtr(ptr: usize, songpatternslength: i32, numinstruments: i32): void {\n instrumentPatternListsPtr = ptr;\n NUM_INSTRUMENTS = numinstruments;\n songlength = songpatternslength;\n \n currentChannelValuesBufferPtr = __new(NUM_INSTRUMENTS * 4, idof>());\n holdChannelValuesBufferPtr = __new(NUM_INSTRUMENTS * 4, idof>());\n}\n\nexport function allocateInstrumentPatternList(songpatternslength: i32, numinstruments: i32): usize {\n NUM_INSTRUMENTS = numinstruments;\n songlength = songpatternslength;\n \n currentChannelValuesBufferPtr = __new(NUM_INSTRUMENTS * 4, idof>());\n holdChannelValuesBufferPtr = __new(NUM_INSTRUMENTS * 4, idof>());\n instrumentPatternListsPtr = __new(songpatternslength * NUM_INSTRUMENTS, idof>());\n\n return instrumentPatternListsPtr;\n}\n\nexport function allocateSampleBuffer(frames: usize): usize {\n sampleBufferFrames = frames;\n sampleBufferPtr = __new(frames * 2 * 4, idof>());\n return sampleBufferPtr;\n}\n\nexport function getCurrentChannelValuesBufferPtr(): usize {\n return currentChannelValuesBufferPtr;\n}\n\nexport function fillSampleBuffer(): void { \n updateInstrumentNotes();\n for(let n: usize = 0;n 1) { \n this.sawoscillator.frequency = notefreq(note + 0.1) / 2;\n this.sawoscillator2.frequency = notefreq(note - 0.1) / 2;\n this.envelope.attack(); \n this.filterenv.attack(); \n } else {\n this.envelope.release();\n this.filterenv.release();\n }\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n // this.signal.clear();\n let filterenv = this.filterenv.next();\n this.signal.left *= 0.9 * env; // feedback\n this.signal.right *= 0.9 * env; // feedback\n this.lpfilterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (100 * filterenv), Q_BUTTERWORTH);\n this.lpfilterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (100 * filterenv), Q_BUTTERWORTH);\n \n this.signal.addMonoSignal(\n this.lpfilterl.process(this.hpfilterl.process(this.sawoscillator.next() * env)), 0.3, 0.3\n );\n this.signal.addMonoSignal(\n this.lpfilterr.process(this.hpfilterr.process(this.sawoscillator2.next() * env)), 0.3, 0.7\n );\n } \n}\n ","instruments/bass/sawbass2.class.ts":"\nimport { SAMPLERATE } from '../../environment';\n\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\n\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { notefreq } from '../../synth/note';\n\n\nexport class SawBass2 {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.2, 0.8, 0.2);\n readonly filterenv: Envelope = new Envelope(0.01, 0.4, 0.0, 0.2);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly hpfilterl: BiQuadFilter = new BiQuadFilter();\n readonly hpfilterr: BiQuadFilter = new BiQuadFilter();\n \n readonly lpfilterl: BiQuadFilter = new BiQuadFilter();\n readonly lpfilterr: BiQuadFilter = new BiQuadFilter();\n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n this.hpfilterl.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH);\n this.hpfilterr.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH);\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = notefreq(note + 0.1);\n this.sawoscillator2.frequency = notefreq(note - 0.1);\n this.envelope.attack(); \n this.filterenv.attack(); \n } else {\n this.envelope.release();\n this.filterenv.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n // this.signal.clear();\n let filterenv = this.filterenv.next();\n this.signal.left /= 1.03; // feedback\n this.signal.right /= 1.03; // feedback\n this.lpfilterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (8000 * filterenv), Q_BUTTERWORTH);\n this.lpfilterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (8000 * filterenv), Q_BUTTERWORTH);\n \n this.signal.addMonoSignal(\n this.lpfilterl.process(this.hpfilterl.process(this.sawoscillator.next() * env)), 0.3, 0.3\n );\n this.signal.addMonoSignal(\n this.lpfilterr.process(this.hpfilterr.process(this.sawoscillator2.next() * env)), 0.3, 0.7\n );\n } \n}\n ","instruments/bass/sawbass3.ts":"\nimport { SAMPLERATE } from '../../environment';\n\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\n\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { notefreq } from '../../synth/note';\nimport { BandPass } from '../../fx/bandpass';\n\n\nexport class SawBass3 {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.3, 0.8, 0.2);\n readonly filterenv: Envelope = new Envelope(0.01, 0.2, 0.1, 0.2);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n \n readonly filter: BiQuadFilter = new BiQuadFilter();\n \n readonly lpfilter: BiQuadFilter = new BiQuadFilter();\n readonly band1: BandPass = new BandPass(1000, 2000);\n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = notefreq(note);\n \n this.envelope.attack(); \n this.filterenv.attack(); \n } else {\n this.envelope.release();\n this.filterenv.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n \n let filterenv = this.filterenv.next();\n \n let signal = this.sawoscillator.next();\n signal *= env;\n \n this.lpfilter.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n this.sawoscillator.frequency + (16 * this.sawoscillator.frequency * filterenv), Q_BUTTERWORTH);\n \n const band1freq = this.sawoscillator.frequency * 4;\n this.band1.update_frequencies(band1freq, band1freq + env * this.sawoscillator.frequency);\n\n let band1 = this.band1.process(signal);\n signal = this.lpfilter.process(signal);\n \n this.signal.left = signal * 2 + band1; \n this.signal.right = signal * 2 - band1;\n \n } \n}\n ","instruments/drivelead.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { Noise } from '../synth/noise.class';\nimport { WaveShaper } from '../synth/shaper';\nimport { notefreq } from '../synth/note';\n\n\nexport class DriveLead {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.1, 1.0, 0.6, 0.2);\n readonly sawoscillatorl: SawOscillator = new SawOscillator();\n readonly sawoscillatorr: SawOscillator = new SawOscillator();\n readonly shaper: WaveShaper = new WaveShaper();\n readonly signal: StereoSignal = new StereoSignal();\n readonly lfoenvelope: Envelope = new Envelope(1.0, 0, 1.0, 0.1);\n readonly lfo: SineOscillator = new SineOscillator();\n baseFrequency : f32;\n pitchbend: f32 = 0;\n\n set note(note: f32) { \n if(note > 1) { \n this.shaper.drive = 0.5; \n this.baseFrequency = notefreq(note);\n this.lfo.frequency = 8;\n this.envelope.attack(); \n this.lfoenvelope.attack(); \n this._note = note;\n } else {\n this.envelope.release();\n this.lfoenvelope.release();\n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n setPitchbend(bend: f32): void {\n this.pitchbend = bend; \n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env===0) {\n this.signal.clear();\n return;\n }\n \n const pitchbend: f32 = this.pitchbend;\n if (Math.abs(pitchbend) > 0.01) {\n // Simple pitchbend that always will return to base note\n this.baseFrequency = notefreq(this._note + pitchbend);\n this.pitchbend = pitchbend * 0.9999;\n } else if(pitchbend !==0 ) {\n this.pitchbend = 0;\n this.baseFrequency = notefreq(this._note);\n }\n \n let lfo: f32 = this.lfo.next() * 3 * this.lfoenvelope.next();\n this.sawoscillatorl.frequency = this.baseFrequency + lfo + 0.5;\n this.sawoscillatorr.frequency = this.baseFrequency + lfo - 0.5;\n \n let left = env* this.sawoscillatorl.next() + this.signal.right * 0.5;\n left = this.shaper.process(left);\n \n let right = env* this.sawoscillatorr.next() + this.signal.left * 0.5;\n right = this.shaper.process(right);\n \n this.signal.left = left * 0.5 + right;\n this.signal.right = right * 0.5 + left; \n } \n}\n ","instruments/drums/kick2.class.ts":"\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\nimport { Instrument } from '../instrument.class';\n\nexport class Kick2 extends Instrument {\n private velocity: f32;\n \n readonly noise: Noise = new Noise();\n \n readonly env2: Envelope = new Envelope(0.001, 0.01, 0.0, 1);\n readonly bp2: BandPass = new BandPass(4000, 5000); \n \n readonly env3: Envelope = new Envelope(0.001, 0.1, 0.05, 0.1);\n readonly bp3: BandPass = new BandPass(10, 100);\n\n set note(note: f32) { \n if(note > 1) { \n this.velocity = note / 16; \n this.env2.attack(); \n this.env3.attack(); \n } else {\n \n this.env2.release(); \n this.env3.release(); \n }\n }\n\n next(): void {\n let env2: f32 = this.env2.next();\n let env3: f32 = this.env3.next();\n \n let osc: f32 = this.noise.next();\n \n \n let sig2 = this.bp2.process(osc) * env2 ;\n let sig3 = this.bp3.process(osc) * env3 * 8;\n\n this.signal.left = this.velocity * (-sig2 + sig3);\n this.signal.right = this.velocity * ( + sig2 - sig3); \n } \n}\n ","instruments/drums/rimshot.class.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\n\nexport class Rimshot {\n private _note: f32;\n private velocity: f32;\n \n readonly noise: Noise = new Noise();\n readonly env1: Envelope = new Envelope(0.001, 1.0, 0.8, 0.3);\n readonly bp1: BandPass = new BandPass(200, 350);\n readonly env2: Envelope = new Envelope(0.001, 0.08, 0.06, 1);\n readonly bp2: BandPass = new BandPass(3000, 7000); \n \n readonly env3: Envelope = new Envelope(0.001, 0.05, 0.01, 0.1);\n readonly bp3: BandPass = new BandPass(10, 150); \n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.velocity = note / 16; \n this.env1.attack(); \n this.env2.attack(); \n this.env3.attack(); \n } else {\n this.env1.release();\n this.env2.release(); \n this.env3.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env1: f32 = this.env1.next();\n let env2: f32 = this.env2.next();\n let env3: f32 = this.env3.next();\n \n let osc: f32 = this.noise.next();\n \n let sig1 = this.bp1.process(osc) * env1;\n let sig2 = this.bp2.process(osc) * env2 * 2;\n let sig3 = this.bp3.process(osc) * env3 * 16;\n\n this.signal.left = this.velocity * (sig1 + sig2 * 0.8 + sig3);\n this.signal.right = this.velocity * (sig1 * 0.8 + sig2 + sig3);\n \n \n } \n}\n ","instruments/drums/snare2.class.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\n\nexport class Snare2 {\n private _note: f32;\n private velocity: f32;\n \n readonly noise: Noise = new Noise();\n readonly env1: Envelope = new Envelope(0.001, 1.0, 0.8, 0.3);\n readonly bp1: BandPass = new BandPass(200, 350);\n readonly env2: Envelope = new Envelope(0.001, 0.08, 0.06, 0.5);\n readonly bp2: BandPass = new BandPass(3000, 7000); \n \n readonly env3: Envelope = new Envelope(0.001, 0.05, 0.01, 0.1);\n readonly bp3: BandPass = new BandPass(10, 150); \n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.velocity = note / 16; \n this.env1.attack(); \n this.env2.attack(); \n this.env3.attack(); \n } else {\n this.env1.release();\n this.env2.release(); \n this.env3.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env1: f32 = this.env1.next();\n let env2: f32 = this.env2.next();\n let env3: f32 = this.env3.next();\n \n let osc: f32 = this.noise.next();\n \n let sig1 = this.bp1.process(osc) * env1 * 6;\n let sig2 = this.bp2.process(osc) * env2 * 2;\n let sig3 = this.bp3.process(osc) * env3 * 4;\n\n this.signal.left = this.velocity * (sig1 + sig2 * 0.8 + sig3);\n this.signal.right = this.velocity * (sig1 * 0.8 + sig2 + sig3);\n \n \n } \n}\n ","instruments/hihat.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { Noise } from '../synth/noise.class';\n\nexport class Hihat {\n private _note: f32;\n private velocity: f32;\n\n readonly envelope: Envelope = new Envelope(0.0, 0.08, 0, 0.1); \n readonly noise: Noise = new Noise();\n \n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.velocity = note / 32; \n this.envelope.attack(); \n } else {\n this.envelope.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next(); \n if(env === 0) {\n this.signal.clear();\n return;\n } \n let osc: f32 = this.noise.next(); \n let signal = this.velocity * 2 * env * osc;\n \n this.filter.update_coeffecients(FilterType.HighPass, SAMPLERATE, \n 10000 + 2000 * env, Q_BUTTERWORTH);\n\n signal = this.filter.process(signal);\n\n this.signal.left = signal;\n this.signal.right = signal;\n } \n}\n ","instruments/instrument.class.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nexport abstract class Instrument {\n abstract set note(note: f32);\n readonly signal: StereoSignal = new StereoSignal();\n abstract next(): void;\n}","instruments/kick.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { Noise } from '../synth/noise.class';\n\n\n\nexport class Kick {\n private _note: f32;\n private velocity: f32;\n readonly envelope: Envelope = new Envelope(0.0, 0.2, 0, 0.2);\n readonly filterenvelope: Envelope = new Envelope(0.0, 0.05, 0.05, 0.1);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly noise: Noise = new Noise();\n \n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = 150;\n this.velocity = note / 16; \n this.envelope.attack(); \n this.filterenvelope.attack(); \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n this.sawoscillator.frequency = 20.0 + (env * 150.0);\n \n this.filter.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 40 + (this.filterenvelope.next() * 2000), 0.2);\n\n let osc1: f32 = this.envelope.next() * this.velocity * this.sawoscillator.next() * 0.8 + this.noise.next();\n\n osc1 = this.filter.process(osc1);\n \n this.signal.left = env * osc1;\n this.signal.right = env * osc1;\n } \n}\n ","instruments/lead/brassy.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\n\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\n\nimport { SineOscillator } from '../../synth/sineoscillator.class';\nimport { notefreq } from '../../synth/note';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\n\nexport class BrassyLead {\n private _note: f32;\n \n readonly osc: SineOscillator = new SineOscillator();\n readonly osc2: SawOscillator = new SawOscillator();\n \n readonly env1: Envelope = new Envelope(0.01, 0.1, 0.4, 0.3);\n \n readonly filterenv: Envelope = new Envelope(0.01, 0.1, 0.1, 0.3);\n \n readonly lopass: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.osc.frequency = notefreq(note);\n this.osc2.frequency = notefreq(note);\n this._note = note;\n this.env1.attack();\n \n this.filterenv.attack(); \n } else {\n this.env1.release(); \n \n this.filterenv.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n const env1: f32 = this.env1.next();\n if(env1 === 0) {\n this.signal.clear();\n return;\n }\n \n let osc: f32 = this.osc.next() * 0.05;\n let osc2: f32 = this.osc2.next() * env1 * 0.2;\n\n const pan = this._note / 127;\n\n let sig = osc + osc2;\n\n const filterenv = this.filterenv.next();\n this.lopass.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n (14000 * filterenv) , Q_BUTTERWORTH);\n sig = this.lopass.process(sig);\n \n this.signal.left = sig;\n this.signal.right = sig;\n \n \n } \n}\n ","instruments/lead/eftang.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { notefreq } from '../../synth/note';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class Eftang {\n private _note: f32;\n \n\n readonly lfo: SineOscillator = new SineOscillator();\n readonly osc: SawOscillator = new SawOscillator();\n readonly osc2: SawOscillator = new SawOscillator();\n readonly osc3: SawOscillator = new SawOscillator();\n \n readonly noise: Noise = new Noise();\n readonly env1: Envelope = new Envelope(0.001, 1.0, 0.8, 0.3);\n readonly bp1: BandPass = new BandPass(200, 350);\n readonly env2: Envelope = new Envelope(0.1, 0.2, 0.5, 1);\n readonly bp2: BandPass = new BandPass(3000, 7000); \n \n readonly env3: Envelope = new Envelope(0.001, 0.3, 0.1, 0.1);\n readonly bp3: BandPass = new BandPass(10, 150); \n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.osc.frequency = notefreq(note);\n this.osc2.frequency = notefreq(note - 0.1);\n this.osc3.frequency = notefreq(note + 0.1);\n this.lfo.position = 0;\n this.lfo.frequency = 4;\n \n this.env1.attack(); \n this.env2.attack(); \n this.env3.attack(); \n } else {\n this.env1.release();\n this.env2.release(); \n this.env3.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n const env1: f32 = this.env1.next();\n if(env1 === 0) {\n this.signal.clear();\n return;\n }\n \n const env2: f32 = this.env2.next();\n const env3: f32 = this.env3.next();\n \n const osc: f32 = this.osc.next() + this.osc2.next() + this.osc3.next();\n \n const lfo = this.lfo.next() + 1;\n const basefreq = this.osc.frequency;\n this.bp1.update_frequencies(20, basefreq + 1);\n this.bp2.update_frequencies(basefreq * 1.5,basefreq * 1.6);\n this.bp3.update_frequencies(basefreq * 12, 8000 + (lfo * 5000));\n const noise = this.noise.next();\n\n const sig1 = this.bp1.process(osc) * env1;\n const sig2 = this.bp2.process(osc) * env2;\n const sig3 = this.bp3.process(osc + noise * 0.2) * env3;\n\n this.signal.left = (sig1 + sig3);\n this.signal.right = ( sig1 + sig2 );\n \n \n } \n}\n ","instruments/lead/sinelead.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\n\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { notefreq } from '../../synth/note';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class SineLead {\n private _note: f32;\n \n\n readonly osc: SineOscillator = new SineOscillator();\n readonly osc2: SineOscillator = new SineOscillator();\n \n readonly env1: Envelope = new Envelope(0.02, 0.15, 0.05, 0.3);\n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.osc.frequency = notefreq(note) * 2;\n this.osc2.frequency = notefreq(note);\n this._note = note;\n this.env1.attack(); \n } else {\n this.env1.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n const env1: f32 = this.env1.next();\n \n let osc: f32 = this.osc.next();\n let osc2: f32 = this.osc2.next() * 0.2 * env1;\n osc *= env1;\n\n const pan = this._note / 127;\n\n this.signal.left = osc * pan + osc2 * (1-pan);\n this.signal.right = osc * (1 - pan) + osc2 * pan;\n \n \n } \n}\n ","instruments/pad/flatpad.class.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { notefreq } from '../../synth/note';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class FlatPad {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.1, 1.0, 0.1);\n readonly filterenvelope: Envelope = new Envelope(0.001, 1.0, 1.0, 0.1);\n readonly hipassfilterenvelope: Envelope = new Envelope(0.02, 3, 0.2, 2.0);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly sawoscillator3: SawOscillator = new SawOscillator();\n readonly sawoscillator4: SawOscillator = new SawOscillator();\n readonly sawoscillator5: SawOscillator = new SawOscillator();\n readonly lfo: SineOscillator = new SineOscillator();\n \n readonly filterl: BiQuadFilter = new BiQuadFilter();\n readonly filterr: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.lfo.frequency = 1;\n this.lfo.position = 0;\n this.sawoscillator.frequency = notefreq(note);\n this.sawoscillator2.frequency = notefreq(note + 0.03);\n this.sawoscillator3.frequency = notefreq(note - 0.03);\n this.sawoscillator4.frequency = notefreq(note + 0.06);\n this.sawoscillator5.frequency = notefreq(note - 0.06);\n \n this.envelope.attack(); \n this.filterenvelope.attack(); \n this.hipassfilterenvelope.attack(); \n this._note = note; \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n this.hipassfilterenvelope.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n \n }\n\n const lfo: f32 = this.lfo.next();\n\n const note = this.note;\n if(note<2) {\n return;\n }\n this.sawoscillator2.frequency = notefreq(note + 0.05 + (0.02 * lfo));\n this.sawoscillator3.frequency = notefreq(note - 0.05 - (0.02 * lfo));\n this.sawoscillator4.frequency = notefreq(note + 0.1 + (0.03 * lfo));\n this.sawoscillator5.frequency = notefreq(note - 0.1 - (0.03 * lfo));\n \n \n let osc: f32 = this.sawoscillator.next();\n let osc2: f32 = this.sawoscillator2.next();\n let osc3: f32 = this.sawoscillator3.next();\n let osc4: f32 = this.sawoscillator4.next();\n let osc5: f32 = this.sawoscillator5.next();\n \n let left = env * (osc + osc2 + osc5);\n let right = env * (osc + osc3 + osc4 );\n\n const filterlfo: f32 = (lfo * 0.9) + 1;\n this.filterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 10000 + 20 * (127 - this.note), Q_BUTTERWORTH);\n \n this.filterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 10000 + 20 * (this.note), Q_BUTTERWORTH);\n \n this.signal.left = this.filterl.process(left );\n this.signal.right = this.filterr.process(right );\n } \n}\n ","instruments/pad/softpad.class.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { notefreq } from '../../synth/note';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class SoftPad {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.2, 0.6, 0.75, 0.5);\n readonly filterenvelope: Envelope = new Envelope(0.8, 1.0, 0.6, 0.5);\n readonly hipassfilterenvelope: Envelope = new Envelope(0.02, 3, 0.2, 2.0);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly sawoscillator3: SawOscillator = new SawOscillator();\n readonly sawoscillator4: SawOscillator = new SawOscillator();\n readonly sawoscillator5: SawOscillator = new SawOscillator();\n readonly lfo: SineOscillator = new SineOscillator();\n \n readonly filterl: BiQuadFilter = new BiQuadFilter();\n readonly filterr: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.lfo.frequency = 1;\n this.lfo.position = 0;\n this.sawoscillator.frequency = notefreq(note);\n this.sawoscillator2.frequency = notefreq(note + 0.03);\n this.sawoscillator3.frequency = notefreq(note - 0.03);\n this.sawoscillator4.frequency = notefreq(note + 0.06);\n this.sawoscillator5.frequency = notefreq(note - 0.06);\n \n this.envelope.attack(); \n this.filterenvelope.attack(); \n this.hipassfilterenvelope.attack(); \n this._note = note; \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n this.hipassfilterenvelope.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n \n }\n\n const lfo: f32 = this.lfo.next();\n\n const note = this.note;\n if(note<2) {\n return;\n }\n this.sawoscillator2.frequency = notefreq(note + 0.05 + (0.02 * lfo));\n this.sawoscillator3.frequency = notefreq(note - 0.05 - (0.02 * lfo));\n this.sawoscillator4.frequency = notefreq(note + 0.1 + (0.03 * lfo));\n this.sawoscillator5.frequency = notefreq(note - 0.1 - (0.03 * lfo));\n \n \n let osc: f32 = this.sawoscillator.next();\n let osc2: f32 = this.sawoscillator2.next();\n let osc3: f32 = this.sawoscillator3.next();\n let osc4: f32 = this.sawoscillator4.next();\n let osc5: f32 = this.sawoscillator5.next();\n \n let left = env * (osc + osc2 + osc5);\n let right = env * (osc + osc3 + osc4 );\n\n const filterlfo = lfo + 1;\n this.filterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 2000 + 20 * (127 - this.note), Q_BUTTERWORTH);\n \n this.filterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 2000 + 20 * (this.note), Q_BUTTERWORTH);\n \n this.signal.left = this.filterl.process(left );\n this.signal.right = this.filterr.process(right );\n } \n}\n ","instruments/pad.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { notefreq } from '../synth/note';\nimport { WaveShaper } from '../synth/shaper';\n\n\n\nexport class Pad {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.05, 0.6, 0.75, 0.3);\n readonly filterenvelope: Envelope = new Envelope(0.06, 0.6, 0.3, 0.3);\n readonly hipassfilterenvelope: Envelope = new Envelope(0.02, 3, 0.2, 2.0);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly sawoscillator3: SawOscillator = new SawOscillator();\n readonly sawoscillator4: SawOscillator = new SawOscillator();\n readonly sawoscillator5: SawOscillator = new SawOscillator();\n \n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly hipassfilterl: BiQuadFilter = new BiQuadFilter();\n readonly hipassfilterr: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = notefreq(note);\n this.sawoscillator2.frequency = notefreq(note + 0.05);\n this.sawoscillator3.frequency = notefreq(note - 0.05);\n this.sawoscillator4.frequency = notefreq(note + 0.1);\n this.sawoscillator5.frequency = notefreq(note - 0.1);\n \n this.envelope.attack(); \n this.filterenvelope.attack(); \n this.hipassfilterenvelope.attack(); \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n this.hipassfilterenvelope.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n \n }\n let osc: f32 = this.sawoscillator.next();\n let osc2: f32 = this.sawoscillator2.next();\n let osc3: f32 = this.sawoscillator3.next();\n let osc4: f32 = this.sawoscillator4.next();\n let osc5: f32 = this.sawoscillator5.next();\n \n let left = env * (osc + osc2 + osc5);\n let right = env * (osc + osc3 + osc4 );\n\n this.filter.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * 18000, 0.2);\n let hpfilterfreq: f32 = 0 + (1-this.hipassfilterenvelope.next()) * 500;\n this.hipassfilterl.update_coeffecients(FilterType.HighPass, SAMPLERATE, \n hpfilterfreq, 0.3);\n this.hipassfilterr.update_coeffecients(FilterType.HighPass, SAMPLERATE, \n hpfilterfreq, 0.3);\n \n this.signal.left = this.hipassfilterl.process(this.filter.process(left ));\n this.signal.right = this.hipassfilterr.process(this.filter.process(right ));\n } \n}\n ","instruments/piano/subpiano.ts":"import { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\nimport { notefreq } from '../../synth/note';\nimport { SquareOscillator } from '../../synth/squareoscillator.class';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class SubPiano {\n private _note: f32;\n private pan: f32;\n\n readonly lfo: SineOscillator = new SineOscillator();\n readonly osc: SquareOscillator = new SquareOscillator();\n readonly env1: Envelope = new Envelope(0.02, 1.5, 0.1, 0.4);\n readonly bp1: BandPass = new BandPass(200, 350);\n readonly env2: Envelope = new Envelope(0.01, 0.6, 0.02, 0.2);\n readonly bp2: BandPass = new BandPass(3000, 7000); \n \n readonly env3: Envelope = new Envelope(0.01, 0.1, 0.00, 0.1);\n readonly bp3: BandPass = new BandPass(10, 150); \n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n let freq : f32 = notefreq(note);\n this.osc.frequency = freq;\n this.lfo.frequency = 5.0;\n this.pan = note / 128.0;\n\n this.env1.attack(); \n this.env2.attack(); \n this.env3.attack(); \n } else {\n this.env1.release();\n this.env2.release(); \n this.env3.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env1: f32 = this.env1.next();\n let env2: f32 = this.env2.next();\n let env3: f32 = this.env3.next();\n \n let osc: f32 = this.osc.next();\n \n const lfo: f32 = this.lfo.next();\n const filterlfo = lfo + 1;\n const panlfo = lfo * 0.2 + 1;\n const freq: f32 = this.osc.frequency;\n this.bp1.update_frequencies(freq, freq + filterlfo * 30);\n this.bp2.update_frequencies(freq * 1.5, freq * 1.5 + filterlfo * 300);\n this.bp3.update_frequencies(freq * 2.25, freq * 2.25 + filterlfo * 800);\n \n let sig1 = this.bp1.process(osc) * env1 * 12;\n let sig2 = this.bp2.process(osc) * env2 * 6;\n let sig3 = this.bp3.process(osc) * env3 * 10;\n\n this.signal.left = this.pan * (sig1 * panlfo + sig2 * 0.8 * -panlfo + sig3 * panlfo);\n this.signal.right = 1 - this.pan * (sig1 * 0.8 * -panlfo + sig2 * panlfo + sig3 - panlfo * 0.2);\n } \n}\n ","instruments/sawbass.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { notefreq } from '../synth/note';\nimport { Instrument } from './instrument.class';\n\nexport class SawBass extends Instrument {\n readonly envelope: Envelope = new Envelope(0.01, 0.2, 0.8, 0.2);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly hpfilterl: BiQuadFilter = new BiQuadFilter();\n readonly hpfilterr: BiQuadFilter = new BiQuadFilter();\n \n constructor() {\n super();\n this.hpfilterl.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH);\n this.hpfilterr.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH);\n }\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = notefreq(note + 0.1);\n this.sawoscillator2.frequency = notefreq(note - 0.1);\n this.envelope.attack(); \n } else {\n this.envelope.release();\n }\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n // this.signal.clear();\n this.signal.left /= 1.03; // feedback\n this.signal.right /= 1.03; // feedback\n this.signal.addMonoSignal(\n this.hpfilterl.process(this.sawoscillator.next() * env), 0.3, 0.3\n );\n this.signal.addMonoSignal(\n this.hpfilterr.process(this.sawoscillator2.next() * env), 0.3, 0.7\n );\n } \n}\n ","instruments/snare.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { Noise } from '../synth/noise.class';\nimport { Instrument } from './instrument.class';\n\nexport class Snare extends Instrument {\n private velocity: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.2, 0, 0.2);\n readonly hpfilterenvelope: Envelope = new Envelope(0.01, 0.5, 0.5, 0.3);\n \n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly noise: Noise = new Noise();\n \n readonly hpfilter: BiQuadFilter = new BiQuadFilter();\n readonly lpfilter: BiQuadFilter = new BiQuadFilter();\n\n constructor() {\n super();\n this.lpfilter.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 13000 , Q_BUTTERWORTH);\n }\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = 200;\n this.velocity = note / 16; \n this.envelope.attack(); \n this.hpfilterenvelope.attack(); \n } else {\n this.envelope.release();\n this.hpfilterenvelope.release();\n }\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n this.sawoscillator.frequency = 20.0 + (env * 200.0);\n \n \n this.hpfilter.update_coeffecients(FilterType.HighPass, SAMPLERATE, \n 20000 - (19900 * this.hpfilterenvelope.next()) , Q_BUTTERWORTH);\n\n let osc1: f32 = this.sawoscillator.next() * 0.6 + this.noise.next();\n osc1= this.hpfilter.process(osc1);\n osc1 = this.lpfilter.process(osc1);\n\n this.signal.left = this.velocity * env * osc1;\n this.signal.right = this.velocity * env * osc1;\n \n \n } \n}\n ","instruments/squarelead.class.ts":"\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { WaveShaper } from '../synth/shaper';\nimport { notefreq } from '../synth/note';\nimport { SquareOscillator } from '../synth/squareoscillator.class';\nimport { BiQuadFilter, Q_BUTTERWORTH, FilterType } from '../synth/biquad';\nimport { SAMPLERATE } from '../environment';\n\n\nexport class SquareLead {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.02, 0.2, 0.2, 0.2);\n readonly filterenvelope: Envelope = new Envelope(0.02, 0.1, 0.4, 0.2);\n readonly squareoscillatorl: SquareOscillator = new SquareOscillator();\n readonly squareoscillatorr: SquareOscillator = new SquareOscillator();\n readonly lpfilterleft: BiQuadFilter = new BiQuadFilter();\n readonly lpfilterright: BiQuadFilter = new BiQuadFilter();\n readonly shaper: WaveShaper = new WaveShaper();\n readonly signal: StereoSignal = new StereoSignal();\n \n baseFrequency : f32;\n\n set note(note: f32) { \n if(note > 1) { \n this.shaper.drive = 0.5; \n this.baseFrequency = notefreq(note);\n this.envelope.attack(); \n this.filterenvelope.attack();\n } else {\n this.envelope.release();\n this.filterenvelope.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n let filterenv: f32 = this.filterenvelope.next();\n if(env===0 && filterenv===0) {\n this.signal.clear();\n return;\n }\n \n this.squareoscillatorl.frequency = this.baseFrequency + 0.3;\n this.squareoscillatorr.frequency = this.baseFrequency - 0.3;\n \n this.lpfilterleft.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n filterenv * 3000, Q_BUTTERWORTH);\n this.lpfilterright.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n filterenv * 3000, Q_BUTTERWORTH);\n \n let left = env* this.squareoscillatorl.next();\n left = this.shaper.process(left);\n left = this.lpfilterleft.process(left);\n\n let right = env* this.squareoscillatorr.next();\n right = this.shaper.process(right);\n right = this.lpfilterright.process(right);\n\n this.signal.left = left;\n this.signal.right = right; \n } \n}\n ","instruments/string1.class.ts":"\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { notefreq } from '../synth/note';\n\nexport class Test4KlangString {\n private _note: f32;\n readonly env0: Envelope = new Envelope(0.01, 0.2, 0.8, 0.2);\n readonly vco1: SineOscillator = new SineOscillator();\n readonly vco5: SawOscillator = new SawOscillator();\n readonly vco6: SawOscillator = new SawOscillator();\n\n readonly signal: StereoSignal = new StereoSignal();\n\n notefreq: f32;\n\n set note(note: f32) { \n if(note > 1) { \n this.notefreq = notefreq(note);\n this.vco1.frequency = this.notefreq / 1000;\n\n this.env0.attack(); \n } else {\n this.env0.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let f_0:f32 = this.env0.next(); // GO4K_ENV ATTAC(88),DECAY(88),SUSTAIN(88),RELEASE(88),GAIN(88)\n let f_1:f32 = this.vco1.next(); // GO4K_VCO TRANSPOSE(76),DETUNE(64),PHASE(64),GATES(85),COLOR(64),SHAPE(64),GAIN(64),FLAGS(SINE|LFO)\n this.vco5.frequency = this.notefreq + f_1; // GO4K_FST AMOUNT(70),DEST(5*MAX_UNIT_SLOTS+2+FST_SET)\n this.vco6.frequency = this.notefreq - f_1; // GO4K_FST AMOUNT(70),DEST(6*MAX_UNIT_SLOTS+5+FST_SET)\n\n f_1 = this.vco5.next(); // GO4K_VCO TRANSPOSE(64),DETUNE(65),PHASE(64),GATES(85),COLOR(52),SHAPE(64),GAIN(64),FLAGS(TRISAW)\n let f_2:f32 = this.vco6.next(); // GO4K_VCO TRANSPOSE(64),DETUNE(63),PHASE(64),GATES(85),COLOR(52),SHAPE(64),GAIN(64),FLAGS(TRISAW)\n f_1 += f_2; // GO4K_FOP OP(FOP_ADDP)\n f_0 *= f_1; // GO4K_FOP OP(FOP_MULP)\n f_1 = f_0; // GO4K_PAN PANNING(64)\n this.signal.left = f_1;\n this.signal.right = f_0; // GO4K_OUT GAIN(0), AUXSEND(128)\n } \n}\n ","instruments/testinstrument.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { DelayLine } from '../fx/delayline';\nimport { notefreq } from '../synth/note';\n\nexport class TestInstrument {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.02, 0.2, 0.2, 0.2);\n readonly sineoscillator: SineOscillator = new SineOscillator();\n readonly sineoscillator2: SineOscillator = new SineOscillator();\n readonly delayline: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\n readonly delayline2: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note!==this.note && note > 1) { \n this.envelope.attack(); \n this.sineoscillator.frequency = notefreq(note);\n this.sineoscillator2.frequency = notefreq(note + 12);\n } else if(note===0) {\n this.envelope.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear(); \n } else {\n let osc1 = env * this.sineoscillator.next();\n let osc2 = env * this.sineoscillator2.next();\n this.signal.left = osc1 * 0.8 + osc2 * 0.2;\n this.signal.right = osc1 * 0.2 + osc2 * 0.8;\n }\n } \n}\n ","math/fft.ts":"/**\n * Originally ported from http://rosettacode.org/wiki/Fast_Fourier_transform#C_sharp\n * \n * Optimized by reusing Complex objects instead of creating new, avoiding garbage collection\n * Precalculating of twiddles, making reuse of the FFT instance faster \n */ \n\n\nexport class Complex {\n re: f32 = 0;\n im: f32 = 0;\n \n public clone(b: Complex): void {\n this.re = b.re;\n this.im = b.im;\n }\n\n public add(b: Complex): void {\n this.re += b.re;\n this.im += b.im;\n }\n \n public sub(b: Complex): void {\n this.re -= b.re;\n this.im -= b.im;\n }\n \n public mult(b: Complex): void {\n const re: f32 = this.re;\n\n this.re = re * b.re - this.im * b.im;\n this.im = re * b.im + this.im * b.re;\n }\n\n public scale(n: f32): void {\n this.re *= n;\n this.im *= n;\n }\n\n public conjugate(): void {\n this.im = -this.im;\n }\n}\n\nfunction bitReverse(n: i32, bits: i32): i32 {\n let reversedN: i32 = n;\n let count: i32 = bits - 1;\n\n n >>= 1;\n while (n > 0) {\n reversedN = (reversedN << 1) | (n & 1);\n count--;\n n >>= 1;\n }\n\n return ((reversedN << count) & ((1 << bits) - 1));\n}\n \n/* Uses Cooley-Tukey iterative in-place algorithm with radix-2 DIT case\n * assumes no of points provided are a power of 2 */\nexport class FFT {\n buffer: StaticArray;\n bits: i32;\n exps: StaticArray;\n tmp: Complex = new Complex();\n\n /**\n * \n * @param buffersize_shift buffersize will be 2^buffersize_shift\n */\n constructor(buffersize_shift: i32) {\n const buffersize = 1 << buffersize_shift;\n const buffer = new StaticArray(buffersize);\n for (let n=0;n((\n buffersize as f32 *\n NativeMathf.log2(buffersize as f32)\n ) as i32);\n\n let expsIndex = 0;\n for (let N: i32 = 2; N <= buffer.length; N <<= 1) {\n for (let i: i32 = 0; i < buffer.length; i += N) {\n for (let k: i32 = 0; k < (N >> 1); k++) {\n const term: f32 = -2 * NativeMathf.PI * (k as f32) / (N as f32);\n const exp: Complex = new Complex();\n exp.re = NativeMathf.cos(term);\n exp.im = NativeMathf.sin(term);\n this.exps[expsIndex++] = exp;\n }\n }\n }\n }\n\n calculateInverse(): void {\n const N = this.buffer.length;\n const iN: f32 = 1 / (N as f32);\n\n for (let n=0;n> 1); k++) {\n const evenIndex = i + k;\n const oddIndex = i + k + (N >> 1);\n const even = buffer[evenIndex];\n const odd = buffer[oddIndex];\n const exp = this.tmp;\n exp.clone(this.exps[expsIndex++]);\n\n exp.mult(odd);\n\n odd.clone(even);\n even.add(exp);\n odd.sub(exp);\n }\n }\n }\n }\n}\n\nexport function createFFT(buffersize_shift: i32): usize {\n return changetype(new FFT(buffersize_shift));\n}\n\nexport function setComplex(instance: usize, arrayIndex: i32, re: f32, im: f32): void {\n const buffer = changetype(instance).buffer;\n buffer[arrayIndex].re = re;\n buffer[arrayIndex].im = im;\n}\n\nexport function getComplexRe(instance: usize, arrayIndex: i32): f32 {\n return changetype(instance).buffer[arrayIndex].re;\n}\n\nexport function getComplexIm(instance: usize, arrayIndex: i32): f32 {\n return changetype(instance).buffer[arrayIndex].im;\n}\n\nexport function calculateFFT(instance: usize): void {\n changetype(instance).calculate();\n}\n\nexport function calculateIFFT(instance: usize): void {\n changetype(instance).calculateInverse();\n}","math/sin.ts":"// By Max Graey ( https://github.com/petersalomonsen/javascriptmusic/issues/2#issuecomment-469419609 )\n\nexport const PI: f32 = 3.141592653589793;\nexport function sin(x: f32): f32 {\n var y: f32, z: f32;\n x *= 1 / PI;\n y = floor(x);\n z = x - y;\n z *= 1.0 - z;\n z *= 3.6 * z + 3.1;\n return select(-z, z, y & 1);\n}\n\nexport function cos(x: f32): f32 {\n return sin(x + PI * .5);\n}","midi/instruments/audioplayer.ts":"import { LoPassBiQuadFilter, MidiChannel, Q_BUTTERWORTH } from \"../../mixes/globalimports\";\nimport { Envelope } from \"../../synth/envelope.class\";\nimport { MidiVoice } from \"../midisynth\";\n\nconst CONTROL_FREQUENCY_CUTOFF = 74;\nconst MAX_CUTOFF_FREQUENCY: f32 = 20000;\nconst audioBuffers: Array> = new Array>();\n\nexport class AudioPlayerChannel extends MidiChannel {\n gain: f32 = 1.0;\n cutoff: f32 = MAX_CUTOFF_FREQUENCY;\n lopassleft: LoPassBiQuadFilter = new LoPassBiQuadFilter();\n lopassright: LoPassBiQuadFilter = new LoPassBiQuadFilter();\n\n controlchange(controller: u8, value: u8): void {\n super.controlchange(controller, value);\n switch (controller) {\n case CONTROL_FREQUENCY_CUTOFF:\n this.cutoff = value * MAX_CUTOFF_FREQUENCY / 127 as f32;\n this.lopassleft.update(this.cutoff, Q_BUTTERWORTH);\n this.lopassright.update(this.cutoff, Q_BUTTERWORTH);\n break;\n }\n }\n\n preprocess(): void {\n let left = this.signal.left;\n let right = this.signal.right;\n if (this.cutoff < MAX_CUTOFF_FREQUENCY) {\n left = this.lopassleft.process(left);\n right = this.lopassright.process(right);\n }\n left *= this.gain;\n right *= this.gain;\n\n this.signal.left = left;\n this.signal.right = right;\n }\n}\n\nexport class AudioPlayer extends MidiVoice {\n position: i32 = 0;\n velocityLevel: f32;\n\n constructor(channel: MidiChannel,\n private audioBufferPairNdx: i32,\n private startPosition: i32,\n noteNumber: u8,\n private env: Envelope = new Envelope(0.01, 0.0, 1.0, 0.01)\n ) {\n super(channel);\n this.minnote = noteNumber;\n this.maxnote = noteNumber;\n }\n\n noteon(note: u8, velocity: u8): void {\n super.noteon(note, velocity);\n this.velocityLevel = velocity as f32 / 127 as f32;\n this.position = this.startPosition;\n this.env.attack();\n }\n\n noteoff(): void {\n this.env.release();\n }\n\n isDone(): boolean {\n return audioBuffers.length == 0 || this.env.isDone();\n }\n\n nextframe(): void {\n const env = this.env.next();\n const vel = env * this.velocityLevel;\n\n let pos = this.position;\n const audioBufferNdx = this.audioBufferPairNdx << 1;\n const leftarr = audioBuffers[audioBufferNdx];\n const left = vel * leftarr[pos];\n const right = vel * audioBuffers[audioBufferNdx + 1][pos];\n pos++;\n if (pos == leftarr.length) {\n pos = 0;\n }\n this.position = pos;\n\n this.channel.signal.left += left;\n this.channel.signal.right += right;\n }\n}\n\nexport class MonoAudioPlayer {\n position: i32 = 0;\n\n constructor(private audioBufferNdx: i32) {\n\n }\n\n restart(): void {\n this.position = 0;\n }\n\n get audioBuffer(): StaticArray {\n return audioBuffers[this.audioBufferNdx];\n }\n\n nextframe(): f32 {\n return this.audioBuffer[(this.position++) % this.audioBuffer.length];\n }\n}\n\nexport function allocateAudioBuffer(frames: i32): usize {\n const buf = new StaticArray(frames);\n audioBuffers.push(buf);\n return changetype(buf);\n}","midi/instruments/defaultinstrument.ts":"import { Envelope } from \"../../synth/envelope.class\";\nimport { notefreq } from \"../../synth/note\";\nimport { SineOscillator } from \"../../synth/sineoscillator.class\";\nimport { MidiVoice } from \"../midisynth\";\n\nexport class DefaultInstrument extends MidiVoice {\n osc: SineOscillator = new SineOscillator();\n env: Envelope = new Envelope(0.01, 0.0, 1.0, 0.01);\n\n noteon(note: u8, velocity: u8): void {\n super.noteon(note, velocity);\n this.osc.frequency = notefreq(note);\n this.env.attack();\n }\n\n noteoff(): void {\n this.env.release();\n }\n\n isDone(): boolean {\n return this.env.isDone();\n }\n\n nextframe(): void {\n const signal = this.osc.next() * this.env.next() * this.velocity / 256;\n this.channel.signal.addMonoSignal(signal, 0.2, 0.5);\n }\n}","midi/midisynth.ts":"import { initializeMidiSynth, postprocess } from '../mixes/midi.mix';\nimport { StereoSignal, Freeverb } from '../mixes/globalimports';\nimport { midiLevelToGain } from '../synth/decibel';\n\nimport { Pan } from '../synth/pan.class';\nimport { DefaultInstrument } from './instruments/defaultinstrument';\n// export { allocateAudioBuffer } from './instruments/audioplayer';\n\nexport const MAX_ACTIVE_VOICES_SHIFT = 5; // up to 32 voices playing simultaneously\nexport const MAX_ACTIVE_VOICES = 1 << MAX_ACTIVE_VOICES_SHIFT;\n\nexport const midichannels = new StaticArray(16);\nexport const activeVoices = new StaticArray(MAX_ACTIVE_VOICES);\nconst activeVoicesStatusSnapshot = new StaticArray(MAX_ACTIVE_VOICES * 3);\n\nexport let numActiveVoices = 0;\nexport let voiceActivationCount = 0;\n\nexport const sampleBufferFrames = 128;\nexport const sampleBufferBytesPerChannel = sampleBufferFrames * 4;\nexport const sampleBufferChannels = 2;\nexport const samplebuffer = new StaticArray(sampleBufferFrames * sampleBufferChannels);\nconst bufferposstart = changetype(samplebuffer);\n\nconst CONTROL_SUSTAIN: u8 = 64;\nconst CONTROL_VOLUME: u8 = 7;\nconst CONTROL_PAN: u8 = 10;\nconst CONTROL_REVERB: u8 = 91;\n\nconst mainline = new StereoSignal();\nconst reverbline = new StereoSignal();\nconst freeverb = new Freeverb();\nexport const outputline = new StereoSignal();\nexport class MidiChannel {\n controllerValues: StaticArray = new StaticArray(128);\n voices: StaticArray;\n sustainedVoices: StaticArray = new StaticArray(128);\n\n signal: StereoSignal = new StereoSignal();\n volume: f32 = midiLevelToGain(100);\n reverb: f32 = midiLevelToGain(7);\n pan: Pan = new Pan();\n voiceTransitionBuffer: StaticArray = new StaticArray(sampleBufferFrames * 2);\n\n constructor(numvoices: i32, factoryFunc: (channel: MidiChannel, voiceindex: i32) => MidiVoice) {\n this.voices = new StaticArray(numvoices);\n for (let n = 0; n < numvoices; n++) {\n this.voices[n] = factoryFunc(this, n);\n }\n\n }\n\n controlchange(controller: u8, value: u8): void {\n this.controllerValues[controller] = value;\n\n switch (controller) {\n case CONTROL_SUSTAIN:\n // sustain\n if (value < 64) {\n for (let n = 0; n < 128; n++) {\n if (this.sustainedVoices[n] != null) {\n (this.sustainedVoices[n] as MidiVoice).noteoff();\n this.sustainedVoices[n] = null;\n }\n }\n }\n break;\n case CONTROL_VOLUME:\n this.volume = midiLevelToGain(value);\n break;\n case CONTROL_REVERB:\n this.reverb = midiLevelToGain(value);\n break;\n case CONTROL_PAN:\n this.pan.setPan((value as f32) / 127.0);\n break;\n }\n }\n\n noteoff(note: u8): void {\n for (let n = 0; n < this.voices.length; n++) {\n const voice = this.voices[n];\n if (voice.note === note) {\n if (this.controllerValues[CONTROL_SUSTAIN] >= 64) {\n this.sustainedVoices[note] = voice;\n } else { \n voice.noteoff();\n }\n break;\n }\n }\n }\n\n removeFromSustainedVoices(voice: MidiVoice): void {\n this.sustainedVoices[voice.note] = null;\n }\n\n activateVoice(note: u8, channelNo: u8): MidiVoice | null {\n for (let n = 0; n < this.voices.length; n++) {\n const voice = this.voices[n];\n voice.channelNo = channelNo;\n if (voice.activeVoicesIndex > -1 && voice.note === note) {\n // Found already active voice for the given note\n voice.activationCount = voiceActivationCount++;\n // must remove from sustained voices\n this.removeFromSustainedVoices(voice);\n return voice;\n }\n }\n\n if (numActiveVoices === activeVoices.length) {\n return null;\n }\n\n let activeVoiceIndex: i32 = numActiveVoices;\n\n for (let n = 0; n < this.voices.length; n++) {\n const voice = this.voices[n];\n if (voice.activeVoicesIndex === -1 &&\n note >= voice.minnote &&\n note <= voice.maxnote) {\n const availableVoice = voice as MidiVoice;\n activeVoices[activeVoiceIndex] = availableVoice;\n availableVoice.activeVoicesIndex = activeVoiceIndex;\n numActiveVoices++;\n availableVoice.activationCount = voiceActivationCount++;\n return availableVoice;\n }\n }\n\n // no available voices for the current channel, we'll pick the oldest\n let oldestVoice: MidiVoice | null = null;\n for (let n = 0; n < this.voices.length; n++) {\n const voice = this.voices[n];\n if (\n (oldestVoice === null ||\n voice.activationCount <= (oldestVoice as MidiVoice).activationCount) &&\n note >= voice.minnote &&\n note <= voice.maxnote) {\n oldestVoice = voice;\n }\n }\n if (oldestVoice !== null) {\n const voice = (oldestVoice as MidiVoice);\n for (let n = 0;n 0) {\n const activatedVoice = midichannels[channel].activateVoice(val2, channel);\n if (activatedVoice !== null) {\n const voice = activatedVoice as MidiVoice;\n voice.noteon(val2, val3);\n }\n } else if (\n (command === 0x80 ||\n (command === 0x90 && val3 === 0)) // \n ) {\n // note off\n midichannels[channel].noteoff(val2);\n } else if (command === 0xb0) {\n // control change\n midichannels[channel].controlchange(val2, val3);\n }\n}\n\nexport function getActiveVoicesStatusSnapshot(): usize {\n for (let n=0;n(activeVoicesStatusSnapshot);\n}\n\nexport function allNotesOff(): void {\n for (let n = 0; n < numActiveVoices; n++) {\n const voice = activeVoices[n] as MidiVoice;\n voice.noteoff();\n }\n}\n\nexport function cleanupInactiveVoices(): void {\n for (let n = 0; n < numActiveVoices; n++) {\n const voice = activeVoices[n] as MidiVoice;\n if (voice.isDone()) {\n voice.deactivate();\n for (let r = n + 1; r < numActiveVoices; r++) {\n const nextVoice = activeVoices[r] as MidiVoice;\n nextVoice.activeVoicesIndex--;\n activeVoices[r - 1] = nextVoice;\n activeVoices[r] = null;\n }\n numActiveVoices--;\n n--;\n }\n }\n}\n\nexport function playActiveVoices(): void {\n for (let n = 0; n < numActiveVoices; n++) {\n (activeVoices[n] as MidiVoice).nextframe();\n }\n}\n\nexport function fillSampleBuffer(): void {\n fillSampleBufferWithNumSamples(sampleBufferFrames);\n}\n\nexport function fillSampleBufferWithNumSamples(numSamples: i32): void {\n const bufferposend = changetype(samplebuffer) + 4 * numSamples;\n\n cleanupInactiveVoices();\n\n let voiceTransitionBufferNdx = 0;\n\n for (let bufferpos = bufferposstart; bufferpos < bufferposend; bufferpos += 4) {\n playActiveVoices();\n\n for (let ch = 0; ch < 16; ch++) {\n const midichannel = midichannels[ch];\n const channelsignal = midichannel.signal;\n\n channelsignal.left += midichannel.voiceTransitionBuffer[voiceTransitionBufferNdx];\n midichannel.voiceTransitionBuffer[voiceTransitionBufferNdx] = 0;\n channelsignal.right +=midichannel.voiceTransitionBuffer[voiceTransitionBufferNdx+1];\n midichannel.voiceTransitionBuffer[voiceTransitionBufferNdx+1] = 0;\n \n midichannel.preprocess(); \n \n channelsignal.left *= midichannel.pan.leftLevel * midichannel.volume;\n channelsignal.right *= midichannel.pan.rightLevel * midichannel.volume;\n\n const reverb = midichannel.reverb;\n\n mainline.add(channelsignal.left, channelsignal.right);\n reverbline.add(channelsignal.left * reverb, channelsignal.right * reverb);\n midichannel.signal.clear();\n }\n\n freeverb.tick(reverbline);\n\n outputline.add(\n mainline.left + reverbline.left,\n mainline.right + reverbline.right\n );\n\n postprocess();\n\n store(bufferpos, outputline.left);\n store(bufferpos + sampleBufferBytesPerChannel, outputline.right);\n\n mainline.clear();\n reverbline.clear();\n outputline.clear();\n voiceTransitionBufferNdx += 2;\n }\n}\n\nconst defaultMidiChannel = new MidiChannel(1, (channel: MidiChannel) => new DefaultInstrument(channel));\n\nfor (let ch = 0; ch < 16; ch++) {\n midichannels[ch] = defaultMidiChannel;\n}\n\ninitializeMidiSynth();\n\n","midi/sequencer/midiparts.ts":"import { MidiSequencerPart, MidiSequencerPartSchedule } from \"./midisequencerpart\";\n\nexport const midiparts: MidiSequencerPart[] = new Array();\nexport const midipartschedule: MidiSequencerPartSchedule[] = new Array();\n","midi/sequencer/midisequencer.ts":"import { SAMPLERATE } from \"../../environment\";\nimport { midiparts, midipartschedule } from \"./midiparts\";\nimport { fillSampleBuffer, sampleBufferFrames } from \"../midisynth\";\n\nconst PLAY_EVENT_INTERVAL = ((sampleBufferFrames * 1000) as f64 / SAMPLERATE);\n\nexport let currentTimeMillis: f64 = 0;\n\nexport function seek(time: i32): void {\n currentTimeMillis = time as f64;\n\n for (let ndx = 0;\n ndx < midipartschedule.length;\n ndx++) {\n const scheduleEntry = midipartschedule[ndx];\n const midiSequencerPart = midiparts[scheduleEntry.midipartindex];\n if (scheduleEntry.endTime >= currentTimeMillis && scheduleEntry.startTime <= currentTimeMillis) {\n midiSequencerPart.seek(Math.round(currentTimeMillis) as i32 - scheduleEntry.startTime);\n } else {\n midiSequencerPart.seek(0);\n }\n }\n}\n\nexport function playMidiPartEvents(): void {\n for (let ndx = 0;\n ndx < midipartschedule.length;\n ndx++) {\n const scheduleEntry = midipartschedule[ndx]; \n if (scheduleEntry.startTime > currentTimeMillis) {\n break;\n }\n const midiSequencerPart = midiparts[scheduleEntry.midipartindex];\n if (currentTimeMillis <= (scheduleEntry.endTime + PLAY_EVENT_INTERVAL)) {\n midiSequencerPart.playEvents(Math.round(currentTimeMillis) as i32 - scheduleEntry.startTime);\n }\n }\n}\n\nexport function playEventsAndFillSampleBuffer(): void {\n playMidiPartEvents();\n fillSampleBuffer();\n currentTimeMillis += PLAY_EVENT_INTERVAL;\n}\n\nexport function setMidiPartSchedule(ndx: i32, midipartindex: i32, startTime: i32): void {\n midipartschedule[ndx].updateEndTime(midipartindex, startTime);\n}\n","midi/sequencer/midisequencerpart.ts":"import { midiparts, midipartschedule } from \"./midiparts\";\nimport { shortmessage } from \"../midisynth\";\n\nexport class MidiSequencerPart {\n currentEventTime: i32 = 0;\n currentEventIndex: i32 = 0;\n previousTargetTime: i32 = 0;\n lastEventTime: i32 = 0;\n\n constructor(public eventlist: u8[]) {\n let lastEventTime = 0;\n for (let ndx = 0; ndx < this.eventlist.length;ndx += 3) {\n let deltaTime: i32 = 0;\n let deltaTimePart: u8;\n\n let shiftamount: u8 = 0;\n do {\n deltaTimePart = this.eventlist[ndx++];\n deltaTime += (((deltaTimePart & 0x7f) as i32) << shiftamount);\n shiftamount += 7;\n } while (deltaTimePart & 0x80);\n\n lastEventTime = lastEventTime + deltaTime;\n }\n this.lastEventTime = lastEventTime;\n }\n\n playEvents(targetTime: i32): void {\n if (targetTime < this.previousTargetTime) {\n this.currentEventTime = 0;\n this.currentEventIndex = 0;\n }\n this.previousTargetTime = targetTime;\n let ndx = this.currentEventIndex;\n\n while (ndx < this.eventlist.length) {\n let deltaTime: i32 = 0;\n let deltaTimePart: u8;\n\n let shiftamount: u8 = 0;\n do {\n deltaTimePart = this.eventlist[ndx++];\n deltaTime += (((deltaTimePart & 0x7f) as i32) << shiftamount);\n shiftamount += 7;\n } while (deltaTimePart & 0x80);\n\n const newTime = this.currentEventTime + deltaTime;\n\n if (newTime <= targetTime) {\n shortmessage(this.eventlist[ndx++], this.eventlist[ndx++], this.eventlist[ndx++]);\n\n this.currentEventTime = newTime;\n this.currentEventIndex = ndx;\n } else {\n break;\n }\n }\n }\n\n seek(targetTime: i32): void {\n this.currentEventIndex = 0;\n this.currentEventTime = 0;\n let ndx = this.currentEventIndex;\n\n while (ndx < this.eventlist.length) {\n let deltaTime: i32 = 0;\n let deltaTimePart: u8;\n\n let shiftamount: u8 = 0;\n do {\n deltaTimePart = this.eventlist[ndx++];\n deltaTime += ((deltaTimePart & 0x7f) << shiftamount);\n shiftamount += 7;\n } while (deltaTimePart & 0x80);\n\n const newTime = this.currentEventTime + deltaTime;\n\n if (newTime < targetTime) {\n ndx += 3;\n this.currentEventTime = newTime;\n this.currentEventIndex = ndx;\n } else if (newTime === targetTime) {\n this.currentEventTime = newTime;\n } else {\n break;\n }\n }\n }\n}\n\nexport class MidiSequencerPartSchedule {\n public endTime: i32\n\n constructor(\n public midipartindex: i32,\n public startTime: i32) {\n this.endTime = midiparts[midipartindex].lastEventTime + startTime;\n }\n\n updateEndTime(midipartindex: i32, startTime: i32): void {\n this.startTime = startTime;\n this.midipartindex = midipartindex;\n this.endTime = midiparts[midipartindex].lastEventTime + startTime;\n }\n}\n","mixes/empty.mix.ts":"import { Kick2, SawBass, Instrument,\n StereoSignal,\n Freeverb } from \"./globalimports\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst kick = new Kick2();\nconst sawbass = new SawBass();\n\nexport function setChannelValue(channel: usize, value: f32): void {\n ([kick, sawbass] as Instrument[])[channel].note = value;\n}\n\nconst mainline = new StereoSignal();\nconst reverbline = new StereoSignal();\nconst freeverb = new Freeverb();\n\n@inline\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear();\n reverbline.clear();\n\n kick.next();\n mainline.addStereoSignal(kick.signal, 0.5, 0.5);\n\n sawbass.next();\n mainline.addStereoSignal(sawbass.signal, 0.5, 0.5);\n reverbline.addStereoSignal(sawbass.signal, 0.1, 0.5);\n\n freeverb.tick(reverbline);\n\n store(leftSampleBufferPtr, mainline.left + reverbline.left);\n store(rightSampleBufferPtr, mainline.right + reverbline.right); \n}","mixes/globalimports.ts":"export { createInstrumentArray } from '../common/mixcommon';\nexport { AllPass } from '../fx/allpass';\nexport { AllPassFloat } from '../fx/allpass';\nexport { BandPass } from '../fx/bandpass';\nexport { Comb } from '../fx/comb';\nexport { DelayLine } from '../fx/delayline';\nexport { DelayLineFloat } from '../fx/delayline';\nexport { EQBand } from '../fx/eqband';\nexport { Freeverb } from '../fx/freeverb';\nexport { Limiter } from '../fx/limiter';\nexport { MidSideProcessor } from '../fx/midsideprocessor';\nexport { MonoCompressor } from '../fx/monocompressor';\nexport { StereoCompressor } from '../fx/monocompressor';\nexport { MultiBandEQ } from '../fx/multibandeq';\nexport { StereoCompressor } from '../fx/stereocompressor';\nexport { TriBandEQ } from '../fx/tribandeq';\nexport { TriBandStereoCompressor } from '../fx/tribandstereocompressor';\nexport { DeepBass } from '../instruments/bass/deepbass';\nexport { SawBass2 } from '../instruments/bass/sawbass2.class';\nexport { SawBass3 } from '../instruments/bass/sawbass3';\nexport { DriveLead } from '../instruments/drivelead.class';\nexport { Kick2 } from '../instruments/drums/kick2.class';\nexport { Rimshot } from '../instruments/drums/rimshot.class';\nexport { Snare2 } from '../instruments/drums/snare2.class';\nexport { Hihat } from '../instruments/hihat.class';\nexport { Instrument } from '../instruments/instrument.class';\nexport { Kick } from '../instruments/kick.class';\nexport { BrassyLead } from '../instruments/lead/brassy';\nexport { Eftang } from '../instruments/lead/eftang';\nexport { SineLead } from '../instruments/lead/sinelead';\nexport { FlatPad } from '../instruments/pad/flatpad.class';\nexport { SoftPad } from '../instruments/pad/softpad.class';\nexport { Pad } from '../instruments/pad.class';\nexport { SubPiano } from '../instruments/piano/subpiano';\nexport { SawBass } from '../instruments/sawbass.class';\nexport { Snare } from '../instruments/snare.class';\nexport { SquareLead } from '../instruments/squarelead.class';\nexport { Test4KlangString } from '../instruments/string1.class';\nexport { TestInstrument } from '../instruments/testinstrument.class';\nexport { Complex } from '../math/fft';\nexport { FFT } from '../math/fft';\nexport { createFFT } from '../math/fft';\nexport { setComplex } from '../math/fft';\nexport { getComplexRe } from '../math/fft';\nexport { getComplexIm } from '../math/fft';\nexport { calculateFFT } from '../math/fft';\nexport { calculateIFFT } from '../math/fft';\nexport { PI } from '../math/sin';\nexport { sin } from '../math/sin';\nexport { cos } from '../math/sin';\nexport { AudioPlayerChannel } from '../midi/instruments/audioplayer';\nexport { AudioPlayer } from '../midi/instruments/audioplayer';\nexport { MonoAudioPlayer } from '../midi/instruments/audioplayer';\nexport { allocateAudioBuffer } from '../midi/instruments/audioplayer';\nexport { DefaultInstrument } from '../midi/instruments/defaultinstrument';\nexport { MAX_ACTIVE_VOICES_SHIFT } from '../midi/midisynth';\nexport { MAX_ACTIVE_VOICES } from '../midi/midisynth';\nexport { midichannels } from '../midi/midisynth';\nexport { activeVoices } from '../midi/midisynth';\nexport { numActiveVoices } from '../midi/midisynth';\nexport { voiceActivationCount } from '../midi/midisynth';\nexport { sampleBufferFrames } from '../midi/midisynth';\nexport { sampleBufferBytesPerChannel } from '../midi/midisynth';\nexport { sampleBufferChannels } from '../midi/midisynth';\nexport { samplebuffer } from '../midi/midisynth';\nexport { outputline } from '../midi/midisynth';\nexport { MidiChannel } from '../midi/midisynth';\nexport { MidiVoice } from '../midi/midisynth';\nexport { shortmessage } from '../midi/midisynth';\nexport { getActiveVoicesStatusSnapshot } from '../midi/midisynth';\nexport { allNotesOff } from '../midi/midisynth';\nexport { cleanupInactiveVoices } from '../midi/midisynth';\nexport { playActiveVoices } from '../midi/midisynth';\nexport { fillSampleBuffer } from '../midi/midisynth';\nexport { fillSampleBufferWithNumSamples } from '../midi/midisynth';\nexport { Q_BUTTERWORTH } from '../synth/biquad';\nexport { FilterType } from '../synth/biquad';\nexport { Coefficients } from '../synth/biquad';\nexport { BiQuadFilter } from '../synth/biquad';\nexport { LoPassBiQuadFilter } from '../synth/biquad';\nexport { HiPassBiQuadFilter } from '../synth/biquad';\nexport { beatToFrame } from '../synth/bpm';\nexport { softclip } from '../synth/clip';\nexport { hardclip } from '../synth/clip';\nexport { decibelToGain } from '../synth/decibel';\nexport { midiLevelToDecibel } from '../synth/decibel';\nexport { midiLevelToGain } from '../synth/decibel';\nexport { EnvelopeState } from '../synth/envelope.class';\nexport { Envelope } from '../synth/envelope.class';\nexport { IFFTOscillator } from '../synth/ifftoscillator.class';\nexport { Noise } from '../synth/noise.class';\nexport { notefreq } from '../synth/note';\nexport { Pan } from '../synth/pan.class';\nexport { SawOscillator } from '../synth/sawoscillator.class';\nexport { WaveShaper } from '../synth/shaper';\nexport { SineOscillator } from '../synth/sineoscillator.class';\nexport { SquareOscillator } from '../synth/squareoscillator.class';\nexport { StereoSignal } from '../synth/stereosignal.class';\nexport { TriangleOscillator } from '../synth/triangleoscillator.class';\nexport { noise } from '../synth/waveguide';\nexport { WaveGuide } from '../synth/waveguide';\nexport { AuxExciterWaveGuide } from '../synth/waveguide';\nexport { AudioExciterWaveGuide } from '../synth/waveguide';\nexport { CustomExciterWaveGuide } from '../synth/waveguide';","mixes/goodtimes.mix.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nimport { Freeverb } from \"../fx/freeverb\";\nimport { TestInstrument } from \"../instruments/testinstrument.class\";\n\nimport { Pad } from \"../instruments/pad.class\";\nimport { Kick2 } from \"../instruments/drums/kick2.class\";\nimport { Rimshot } from \"../instruments/drums/rimshot.class\";\nimport { DriveLead } from \"../instruments/drivelead.class\";\n\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\nimport { SquareLead } from \"../instruments/squarelead.class\";\n\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\nimport { EQBand } from \"../fx/eqband\";\nimport { SawBass2 } from \"../instruments/bass/sawbass2.class\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst gain: f32 = 0.2;\nconst ENABLE_MULTIBAND_COMPRESSOR = false;\n\nlet flute = new TestInstrument();\nlet drivelead = new DriveLead();\nlet bass = new SawBass2();\nlet pad1 = new Pad();\nlet pad2 = new Pad();\nlet pad3 = new Pad();\nlet kick = new Kick2();\nlet rimshot = new Rimshot();\nlet hihat = new Hihat();\nlet squarelead = new SquareLead();\n\nlet freeverb = new Freeverb();\n\nlet delayLeft: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\nlet delayRight: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\n \nlet echoline = new StereoSignal();\nlet reverbline = new StereoSignal();\nlet mainline = new StereoSignal();\n\nlet tribandstereocompressor = new TriBandStereoCompressor(20,500,7000,19500);\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(channel) {\n case 0:\n flute.note = value;\n break;\n case 1:\n bass.note = value;\n break;\n case 2:\n pad1.note = value;\n break;\n case 3:\n pad2.note = value;\n break;\n case 4:\n pad3.note = value;\n break;\n case 5:\n kick.note = value;\n break;\n case 6:\n rimshot.note = value;\n break;\n case 7:\n drivelead.note = value;\n break;\n case 8:\n hihat.note = value;\n break;\n case 9:\n squarelead.note = value;\n break;\n }\n \n}\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear()\n reverbline.clear();\n echoline.clear();\n \n flute.next();\n pad1.next(); \n pad2.next();\n pad3.next(); \n kick.next();\n rimshot.next();\n hihat.next();\n bass.next(); \n drivelead.next();\n squarelead.next();\n\n mainline.addStereoSignal(flute.signal, 0.6, 0.0);\n echoline.addStereoSignal(flute.signal, 0.5, 1.0);\n \n mainline.addStereoSignal(pad1.signal, 0.5, 0.25);\n echoline.addStereoSignal(pad1.signal, 0.3, 0.25); \n mainline.addStereoSignal(pad2.signal, 0.5, 0.5);\n echoline.addStereoSignal(pad2.signal, 0.25, 0.5);\n mainline.addStereoSignal(pad3.signal, 0.5, 0.75);\n echoline.addStereoSignal(pad3.signal, 0.25, 0.75);\n\n mainline.addStereoSignal(kick.signal, 1.7, 0.5);\n reverbline.addStereoSignal(kick.signal, 0.08, 0.0);\n \n mainline.addStereoSignal(rimshot.signal, 0.75, 0.6);\n reverbline.addStereoSignal(rimshot.signal, 0.20, 0.4);\n \n mainline.addStereoSignal(hihat.signal, 1.0, 0.4);\n reverbline.addStereoSignal(hihat.signal, 0.2, 0.6);\n\n mainline.addStereoSignal(bass.signal, 0.6, 0.5);\n reverbline.addStereoSignal(bass.signal, 0.07, 0.0);\n\n mainline.addStereoSignal(drivelead.signal, 0.17, 0.4);\n echoline.addStereoSignal(drivelead.signal, 0.4, 0.6);\n\n mainline.addStereoSignal(squarelead.signal,0.6, 0.6);\n echoline.addStereoSignal(squarelead.signal, 0.6, 0.0);\n\n echoline.left += delayRight.read() * 0.5;\n echoline.right += delayLeft.read() * 0.5;\n \n delayLeft.write_and_advance(echoline.left);\n delayRight.write_and_advance(echoline.right);\n\n reverbline.addStereoSignal(echoline, 0.5, 0.5);\n \n freeverb.tick(reverbline);\n \n let left = gain * (mainline.left + echoline.left + reverbline.left);\n let right = gain * (mainline.right + echoline.right + reverbline.right);\n\n if (ENABLE_MULTIBAND_COMPRESSOR) {\n tribandstereocompressor.process(left,right,0.45, 1.0, 0.9 , 1.3, 1.05, 1.0);\n left = tribandstereocompressor.stereosignal.left;\n right = tribandstereocompressor.stereosignal.right;\n } else {\n left = eqbandl.process(left);\n right = eqbandr.process(right);\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/midi.mix.ts":"import { midichannels, MidiChannel, MidiVoice, SineOscillator, Envelope, notefreq } from './globalimports';\nimport { outputline } from '../midi/midisynth';\nimport { hardclip } from '../synth/clip';\n\nclass SimpleSine extends MidiVoice {\n osc: SineOscillator = new SineOscillator();\n env: Envelope = new Envelope(0.1, 0.0, 1.0, 0.1);\n\n noteon(note: u8, velocity: u8): void {\n super.noteon(note, velocity);\n this.osc.frequency = notefreq(note);\n this.env.attack();\n }\n\n noteoff(): void {\n this.env.release();\n }\n\n isDone(): boolean {\n return this.env.isDone();\n }\n\n nextframe(): void {\n const signal = this.osc.next() * this.env.next() * this.velocity / 256;\n this.channel.signal.addMonoSignal(signal, 0.2, 0.7);\n }\n}\n\nexport function initializeMidiSynth(): void {\n midichannels[0] = new MidiChannel(6, (channel: MidiChannel) => new SimpleSine(channel));\n}\n\nexport function postprocess(): void {\n outputline.left = hardclip(outputline.left);\n outputline.right = hardclip(outputline.right);\n}","mixes/newyear.mix.ts":"/**\n * Mix for \"WASM song\"\n */\nimport { EQBand } from \"../fx/eqband\";\nimport { Envelope } from '../synth/envelope.class';\nimport { Snare } from \"../instruments/snare.class\";\nimport { SawBass3 } from \"../instruments/bass/sawbass3\";\nimport { Eftang } from \"../instruments/lead/eftang\";\nimport { StereoSignal } from \"../synth/stereosignal.class\";\nimport { Kick } from \"../instruments/kick.class\";\nimport { BrassyLead } from \"../instruments/lead/brassy\";\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { WaveShaper } from '../synth/shaper';\nimport { createInstrumentArray } from '../common/mixcommon';\nimport { Freeverb } from \"../fx/freeverb\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { notefreq } from '../synth/note';\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst tribandstereocompressor = new TriBandStereoCompressor(0.05, 25,150,1500,20000);\nconst ENABLE_MULTIBAND_COMPRESSOR = true;\n\nconst gain: f32 = 0.5;\n\nconst bass = new SawBass3();\nconst lead = new Eftang();\nconst kick = new Kick();\nconst snare = new Snare();\nconst hihat = new Hihat();\n\n\nexport class FlatPad {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.1, 1.0, 0.1);\n readonly filterenvelope: Envelope = new Envelope(0.001, 1.0, 1.0, 0.1);\n readonly hipassfilterenvelope: Envelope = new Envelope(0.02, 3, 0.2, 2.0);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly sawoscillator3: SawOscillator = new SawOscillator();\n readonly sawoscillator4: SawOscillator = new SawOscillator();\n readonly sawoscillator5: SawOscillator = new SawOscillator();\n readonly lfo: SineOscillator = new SineOscillator();\n \n readonly filterl: BiQuadFilter = new BiQuadFilter();\n readonly filterr: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n \n set note(note: f32) { \n if(note > 1) { \n this.lfo.frequency = 1;\n this.lfo.position = 0;\n this.sawoscillator.frequency = notefreq(note);\n this.sawoscillator2.frequency = notefreq(note + 0.03);\n this.sawoscillator3.frequency = notefreq(note - 0.03);\n this.sawoscillator4.frequency = notefreq(note + 0.06);\n this.sawoscillator5.frequency = notefreq(note - 0.06);\n \n this.envelope.attack(); \n this.filterenvelope.attack(); \n this.hipassfilterenvelope.attack(); \n this._note = note; \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n this.hipassfilterenvelope.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n \n }\n\n const lfo: f32 = this.lfo.next();\n\n const note = this.note;\n if(note<2) {\n return;\n }\n this.sawoscillator2.frequency = notefreq(note + 0.05 + (0.02 * lfo));\n this.sawoscillator3.frequency = notefreq(note - 0.05 - (0.02 * lfo));\n this.sawoscillator4.frequency = notefreq(note + 0.1 + (0.03 * lfo));\n this.sawoscillator5.frequency = notefreq(note - 0.1 - (0.03 * lfo));\n \n \n let osc: f32 = this.sawoscillator.next();\n let osc2: f32 = this.sawoscillator2.next();\n let osc3: f32 = this.sawoscillator3.next();\n let osc4: f32 = this.sawoscillator4.next();\n let osc5: f32 = this.sawoscillator5.next();\n \n let left = env * (osc + osc2 + osc5);\n let right = env * (osc + osc3 + osc4 );\n\n const filterlfo: f32 = (lfo * 0.9) + 1;\n this.filterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 10000 + 20 * (127 - this.note), Q_BUTTERWORTH);\n \n this.filterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 10000 + 20 * (this.note), Q_BUTTERWORTH);\n \n this.signal.left = this.filterl.process(left );\n this.signal.right = this.filterr.process(right );\n } \n}\n \nconst pads: FlatPad[] = createInstrumentArray(10, () => new FlatPad());\nlet padsVolume: f32 = 1.0;\n\nclass SineLead {\n private _note: f32;\n \n readonly osc: SineOscillator = new SineOscillator();\n readonly env1: Envelope = new Envelope(0.02, 0.15, 0.5, 0.3); \n readonly signal: StereoSignal = new StereoSignal();\n\n\n set note(note: f32) { \n if(note > 1) { \n this.osc.frequency = notefreq(note);\n this._note = note;\n this.env1.attack(); \n } else {\n this.env1.release(); \n } \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n const env1: f32 = this.env1.next();\n \n let osc: f32 = this.osc.next(); \n osc *= env1;\n\n const pan = this._note / 127;\n\n this.signal.left = osc * pan;\n this.signal.right = osc * (1 - pan); \n } \n}\n\nexport class DriveLead {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.03, 1.0, 0.6, 0.2);\n readonly sawoscillatorl: SawOscillator = new SawOscillator();\n readonly sawoscillatorr: SawOscillator = new SawOscillator();\n readonly shaper: WaveShaper = new WaveShaper();\n readonly signal: StereoSignal = new StereoSignal();\n readonly lfoenvelope: Envelope = new Envelope(1.0, 0, 1.0, 0.1);\n readonly lfo: SineOscillator = new SineOscillator();\n private baseFrequency : f32;\n private pitchbend: f32 = 0;\n\n set note(note: f32) { \n if(note > 1) { \n this.shaper.drive = 0.5; \n this.baseFrequency = notefreq(note + this.pitchbend);\n this.lfo.frequency = 8;\n this.envelope.attack(); \n this.lfoenvelope.attack(); \n this._note = note;\n } else {\n this.envelope.release();\n this.lfoenvelope.release();\n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n setPitchbend(bend: f32): void {\n \tthis.pitchbend = bend;\n \tthis.baseFrequency = notefreq(this._note + bend); \t\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env===0) {\n this.signal.clear();\n return;\n } \n \n let lfo: f32 = this.lfo.next() * 3 * this.lfoenvelope.next();\n this.sawoscillatorl.frequency = this.baseFrequency + lfo + 0.5;\n this.sawoscillatorr.frequency = this.baseFrequency + lfo - 0.5;\n \n let left = env* this.sawoscillatorl.next() + this.signal.right * 0.5;\n left = this.shaper.process(left);\n \n let right = env* this.sawoscillatorr.next() + this.signal.left * 0.5;\n right = this.shaper.process(right);\n \n this.signal.left = left * 0.5 + right;\n this.signal.right = right * 0.5 + left; \n } \n}\n\nconst sinelead = new SineLead();\nconst drivelead = new DriveLead();\n\nexport function setChannelValue(channel: usize, value: f32): void {\n const setChannelValueFunctions: usize[] = [\n changetype((value:f32): void => {bass.note = value;}),\n changetype((value:f32): void => {lead.note = value;}),\n changetype((value:f32): void => {sinelead.note = value;}),\n changetype((value:f32): void => {kick.note = value;}),\n changetype((value:f32): void => {snare.note = value;}),\n changetype((value:f32): void => {hihat.note = value;}),\n changetype((value:f32): void => {pads[0].note = value;}),\n changetype((value:f32): void => {pads[1].note = value;}),\n changetype((value:f32): void => {pads[2].note = value;}),\n changetype((value:f32): void => {pads[3].note = value;}), \n changetype((value:f32): void => {pads[4].note = value;}), \n changetype((value:f32): void => {pads[5].note = value;}),\n changetype((value:f32): void => {pads[6].note = value;}),\n changetype((value:f32): void => {pads[7].note = value;}),\n changetype((value:f32): void => {pads[8].note = value;}),\n changetype((value:f32): void => {pads[9].note = value;}),\n changetype((value:f32): void => {\n if(value > 0) {\n\t padsVolume = value / 100.0;\n }\n }),\n changetype((value:f32): void => {drivelead.note = value;}),\n changetype((value:f32): void => {\n if(value > 0) {\n\t drivelead.setPitchbend((value - 64) / 32);\n }\n })\n \n ];\n\n changetype<(val: f32) => void>(setChannelValueFunctions[channel])(value);\n}\n\n\nconst mainline = new StereoSignal();\nconst reverbline = new StereoSignal();\nconst freeverb = new Freeverb();\n\nconst delayframes = (SAMPLERATE * (6/8) * 60 / 120) as usize;\nlet delayLeft: DelayLine = new DelayLine(delayframes);\nlet delayRight: DelayLine = new DelayLine(delayframes);\n \nlet echoline = new StereoSignal();\n\n\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n let left: f32 = 0;\n let right: f32 = 0;\n\n mainline.clear();\n reverbline.clear();\n echoline.clear();\n\n bass.next();\n mainline.addStereoSignal(bass.signal, 1.0, 0.5);\n reverbline.addStereoSignal(bass.signal, 0.0, 0.5);\n\n lead.next();\n mainline.addStereoSignal(lead.signal, 0.8, 0.5);\n echoline.addStereoSignal(lead.signal, 0.8, 0.5);\n\n \tdrivelead.next();\n mainline.addStereoSignal(drivelead.signal, 0.1, 0.5);\n echoline.addStereoSignal(drivelead.signal, 0.4, 0.5);\n\n \tsinelead.next();\n mainline.addStereoSignal(sinelead.signal, 1.0, 0.5);\n echoline.addStereoSignal(sinelead.signal, 1.2, 0.5);\n\n kick.next();\n mainline.addStereoSignal(kick.signal, 0.8, 0.5);\n\n snare.next();\n mainline.addStereoSignal(snare.signal, 0.8, 0.5); \n\n hihat.next();\n mainline.addStereoSignal(hihat.signal, 0.8, 0.5);\n\n pads.forEach(pad => {\n pad.next();\n mainline.addStereoSignal(pad.signal, 0.45 * padsVolume, 0.5);\n });\n \n echoline.left += delayRight.read() * 0.7;\n echoline.right += delayLeft.read() * 0.7;\n\n delayLeft.write_and_advance(echoline.left);\n delayRight.write_and_advance(echoline.right);\n\n freeverb.tick(reverbline);\n\n left = gain * (mainline.left + reverbline.left + echoline.left);\n right = gain * (mainline.right + reverbline.right + echoline.right);\n\n \tif (ENABLE_MULTIBAND_COMPRESSOR) {\n tribandstereocompressor.process(left,right,0.45, 0.6, 0.9 , 1.20, 1.05, 1.0);\n left = tribandstereocompressor.stereosignal.left;\n right = tribandstereocompressor.stereosignal.right;\n } else {\n left = eqbandl.process(left);\n right = eqbandr.process(right);\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/protracker.mix.ts":"import { EQBand } from \"../fx/eqband\";\n\nimport { Snare } from \"../instruments/snare.class\";\nimport { SawBass3 } from \"../instruments/bass/sawbass3\";\nimport { Eftang } from \"../instruments/lead/eftang\";\nimport { StereoSignal } from \"../synth/stereosignal.class\";\nimport { Kick } from \"../instruments/kick.class\";\nimport { BrassyLead } from \"../instruments/lead/brassy\";\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { FlatPad } from \"../instruments/pad/flatpad.class\";\nimport { createInstrumentArray } from '../common/mixcommon';\nimport { Freeverb } from \"../fx/freeverb\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst gain: f32 = 0.2;\n\nconst bass = new SawBass3();\nconst lead = new Eftang();\nconst kick = new Kick();\nconst snare = new Snare();\nconst hihat = new Hihat();\nconst brassylead = new BrassyLead();\nconst pads: FlatPad[] = createInstrumentArray(4, () => new FlatPad());\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(channel) {\n case 0:\n bass.note = value;\n break;\n case 1:\n lead.note = value;\n break;\n case 2:\n kick.note = value;\n break;\n case 3:\n snare.note = value;\n break;\n case 4:\n hihat.note = value;\n break;\n case 5:\n brassylead.note = value;\n break;\n case 6:\n case 7:\n case 8:\n case 9:\n pads[channel-6].note = value;\n break; \n \n }\n \n}\n\n\nconst mainline = new StereoSignal();\nconst reverbline = new StereoSignal();\nconst freeverb = new Freeverb();\n\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n let left: f32 = 0;\n let right: f32 = 0;\n\n mainline.clear();\n reverbline.clear();\n\n bass.next();\n mainline.addStereoSignal(bass.signal, 0.2, 0.5);\n reverbline.addStereoSignal(bass.signal, 0.1, 0.5);\n\n lead.next();\n mainline.addStereoSignal(lead.signal, 0.2, 0.5);\n reverbline.addStereoSignal(lead.signal, 0.02, 0.5);\n\n kick.next();\n mainline.addStereoSignal(kick.signal, 0.2, 0.5);\n\n snare.next();\n mainline.addStereoSignal(snare.signal, 0.2, 0.5); \n\n hihat.next();\n mainline.addStereoSignal(hihat.signal, 0.2, 0.5);\n\n brassylead.next();\n mainline.addStereoSignal(brassylead.signal, 0.5, 0.5);\n reverbline.addStereoSignal(brassylead.signal, 0.1, 0.5);\n\n pads.forEach(pad => {\n pad.next();\n mainline.addStereoSignal(pad.signal, 0.5, 0.5);\n \n });\n \n freeverb.tick(reverbline);\n\n left = gain * (mainline.left + reverbline.left );\n right = gain * (mainline.right + reverbline.right );\n\n left = eqbandl.process(left);\n right = eqbandr.process(right);\n \n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/shuffle.mix.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nimport { Freeverb } from \"../fx/freeverb\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\n\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\nimport { EQBand } from \"../fx/eqband\";\nimport { SubPiano } from \"../instruments/piano/subpiano\";\nimport { Kick2 } from \"../instruments/drums/kick2.class\";\nimport { Snare } from \"../instruments/snare.class\";\nimport { DeepBass } from \"../instruments/bass/deepbass\";\nimport { Eftang } from \"../instruments/lead/eftang\";\nimport { SoftPad } from \"../instruments/pad/softpad.class\";\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { SineLead } from \"../instruments/lead/sinelead\";\nimport { DriveLead } from \"../instruments/drivelead.class\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 3;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 0;\n\nconst gain: f32 = 0.13;\nconst ENABLE_MULTIBAND_COMPRESSOR = true;\n\nlet freeverb = new Freeverb();\n\nconst delayframes = (SAMPLERATE * (3/8) * 60 / 70) as usize;\nlet delayLeft: DelayLine = new DelayLine(delayframes);\nlet delayRight: DelayLine = new DelayLine(delayframes);\n \nlet echoline = new StereoSignal();\nlet reverbline = new StereoSignal();\nlet mainline = new StereoSignal();\n\nlet tribandstereocompressor = new TriBandStereoCompressor(20,500,7000,19500);\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nfunction createInstrumentArray(length: i32, factoryFunc: () => T): T[] {\n const arr = new Array(length);\n for(let n = 0; n < length;n++) {\n arr[n] = factoryFunc();\n }\n return arr;\n}\n\nconst pianos: SubPiano[] = createInstrumentArray(8, () => new SubPiano());\nconst pads: SoftPad[] = createInstrumentArray(8, () => new SoftPad());\nconst driveleads: DriveLead[] = createInstrumentArray(3, () => new DriveLead());\n\nconst kick = new Kick2();\nconst bass = new DeepBass();\nconst eftang = new Eftang();\nconst snare = new Snare();\nconst hihat = new Hihat();\nconst sinelead = new SineLead();\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(true) {\n case (channel < 8):\n pianos[channel].note = value;\n break;\n case channel === 8:\n kick.note = value;\n break;\n case channel === 9:\n snare.note = value;\n break;\n case channel === 10:\n hihat.note = value;\n break;\n case channel === 11:\n bass.note = value\n break;\n case channel === 12:\n eftang.note = value;\n break;\n case channel < 21:\n pads[channel - 13].note = value;\n break;\n case channel === 21:\n sinelead.note = value;\n break;\n case channel < 25:\n driveleads[channel - 22].note = value;\n break;\n case channel === 25:\n if(value > 1) {\n for(let n = 0; n 1.0) {\n left = 1.0;\n }\n\n if (Math.abs(right) > 1.0) {\n right = 1.0;\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/simple.mix.ts":"import { SawOscillator, Instrument, Noise, BiQuadFilter, FilterType, \n StereoSignal,\n Freeverb, SineOscillator, Envelope, notefreq } from \"./globalimports\";\n import { SAMPLERATE } from '../environment';\n \n export const PATTERN_SIZE_SHIFT: usize = 4;\n export const BEATS_PER_PATTERN_SHIFT: usize = 2;\n \n const mainline = new StereoSignal();\n const reverbline = new StereoSignal();\n const freeverb = new Freeverb();\n \n class Kick extends Instrument {\n private velocity: f32;\n envelope: Envelope = new Envelope(0.0, 0.2, 0, 0.2);\n filterenvelope: Envelope = new Envelope(0.0, 0.05, 0.05, 0.1);\n sawoscillator: SawOscillator = new SawOscillator();\n noise: Noise = new Noise();\n \n filter: BiQuadFilter = new BiQuadFilter();\n \n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = 150;\n this.velocity = note / 16; \n this.envelope.attack(); \n this.filterenvelope.attack(); \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n }\n }\n \n next(): void { \n let env: f32 = this.envelope.next();\n this.sawoscillator.frequency = 20.0 + (env * 150.0);\n \n this.filter.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 40 + (this.filterenvelope.next() * 2000), 0.2);\n \n let osc1: f32 = this.envelope.next() * this.velocity * this.sawoscillator.next() * 0.8 + this.noise.next();\n \n osc1 = this.filter.process(osc1);\n \n const val = env * osc1;\n \n mainline.left+=val;\n mainline.right+=val;\n } \n }\n \n class Lead extends Instrument {\n osc: SineOscillator = new SineOscillator();\n env: Envelope = new Envelope(0.1,0.1,1.0,0.1);\n \n set note(note: f32) {\n if(note > 1) {\n this.osc.frequency = notefreq(note);\n this.env.attack();\n } else if (note === 0) {\n this.env.release();\n }\n }\n @inline\n next(): void {\n const val = this.osc.next() * this.env.next() * 0.3;\n mainline.left += val;\n mainline.right += val;\n }\n }\n \n \n const voices: Instrument[] = [\n new Kick(),\n new Lead(),\n new Lead(),\n new Lead(),\n new Lead()\n ];\n \n export function setChannelValue(channel: usize, value: f32): void {\n voices[channel].note = value;\n }\n \n \n @inline\n export function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear();\n reverbline.clear();\n \n for(var n=0;n(leftSampleBufferPtr, mainline.left + reverbline.left);\n store(rightSampleBufferPtr, mainline.right + reverbline.right); \n }","mixes/test.mix.ts":"// This mix was used in the song \"Groove is in the code\"\n\nimport { StereoSignal } from \"../synth/stereosignal.class\";\n\nimport { Freeverb } from \"../fx/freeverb\";\nimport { TestInstrument } from \"../instruments/testinstrument.class\";\nimport { SawBass } from \"../instruments/sawbass.class\";\nimport { Pad } from \"../instruments/pad.class\";\nimport { Kick } from \"../instruments/kick.class\";\nimport { Snare } from \"../instruments/snare.class\";\nimport { DriveLead } from \"../instruments/drivelead.class\";\n\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\nimport { SquareLead } from \"../instruments/squarelead.class\";\n\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst gain: f32 = 0.15;\nconst ENABLE_MULTIBAND_COMPRESSOR = false;\n\nlet flute = new TestInstrument();\nlet drivelead = new DriveLead();\nlet bass = new SawBass();\nlet pad1 = new Pad();\nlet pad2 = new Pad();\nlet pad3 = new Pad();\nlet kick = new Kick();\nlet snare = new Snare();\nlet hihat = new Hihat();\nlet squarelead = new SquareLead();\n\nlet freeverb = new Freeverb();\n\nlet delayLeft: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\nlet delayRight: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\n \nlet echoline = new StereoSignal();\nlet reverbline = new StereoSignal();\nlet mainline = new StereoSignal();\n\nlet tribandstereocompressor = new TriBandStereoCompressor(15,500,8000,19000);\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(channel) {\n case 0:\n flute.note = value;\n break;\n case 1:\n bass.note = value;\n break;\n case 2:\n pad1.note = value;\n break;\n case 3:\n pad2.note = value;\n break;\n case 4:\n pad3.note = value;\n break;\n case 5:\n kick.note = value;\n break;\n case 6:\n snare.note = value;\n break;\n case 7:\n drivelead.note = value;\n break;\n case 8:\n hihat.note = value;\n break;\n case 9:\n squarelead.note = value;\n break;\n }\n \n}\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear()\n reverbline.clear();\n echoline.clear();\n \n flute.next();\n pad1.next(); \n pad2.next();\n pad3.next(); \n kick.next();\n snare.next();\n hihat.next();\n bass.next(); \n drivelead.next();\n squarelead.next();\n\n mainline.addStereoSignal(flute.signal, 0.7, 0.0);\n echoline.addStereoSignal(flute.signal, 0.6, 1.0);\n \n mainline.addStereoSignal(pad1.signal, 0.58, 0.25);\n echoline.addStereoSignal(pad1.signal, 0.35, 0.25); \n mainline.addStereoSignal(pad2.signal, 0.58, 0.5);\n echoline.addStereoSignal(pad2.signal, 0.30, 0.5);\n mainline.addStereoSignal(pad3.signal, 0.58, 0.75);\n echoline.addStereoSignal(pad3.signal, 0.30, 0.75);\n\n mainline.addStereoSignal(kick.signal, 1.6, 0.5);\n reverbline.addStereoSignal(kick.signal, 0.05, 0.0);\n \n mainline.addStereoSignal(snare.signal, 0.38, 0.6);\n echoline.addStereoSignal(snare.signal, 0.1, 0.4);\n \n mainline.addStereoSignal(hihat.signal, 0.7, 0.4);\n reverbline.addStereoSignal(hihat.signal, 0.05, 0.6);\n\n mainline.addStereoSignal(bass.signal, 1.2, 0.5);\n reverbline.addStereoSignal(bass.signal, 0.1, 0.0);\n\n mainline.addStereoSignal(drivelead.signal, 0.17, 0.4);\n echoline.addStereoSignal(drivelead.signal, 0.4, 0.6);\n\n mainline.addStereoSignal(squarelead.signal,0.6, 0.6);\n echoline.addStereoSignal(squarelead.signal, 0.6, 0.0);\n\n echoline.left += delayRight.read() * 0.5;\n echoline.right += delayLeft.read() * 0.5;\n \n delayLeft.write_and_advance(echoline.left);\n delayRight.write_and_advance(echoline.right);\n\n reverbline.addStereoSignal(echoline, 0.5, 0.5);\n \n freeverb.tick(reverbline);\n \n let left = gain * (mainline.left + echoline.left + reverbline.left);\n let right = gain * (mainline.right + echoline.right + reverbline.right);\n\n if (ENABLE_MULTIBAND_COMPRESSOR) {\n tribandstereocompressor.process(left,right,0.3, 0.3, 0.5 , 2.0, 0.80, 0.9);\n left = tribandstereocompressor.stereosignal.left;\n right = tribandstereocompressor.stereosignal.right;\n } else {\n left = left;\n right = right;\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/webchip.mix.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nimport { Freeverb } from \"../fx/freeverb\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\n\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\nimport { EQBand } from \"../fx/eqband\";\nimport { SubPiano } from \"../instruments/piano/subpiano\";\nimport { Kick2 } from \"../instruments/drums/kick2.class\";\nimport { Snare2 } from \"../instruments/drums/snare2.class\";\nimport { SawBass3 } from \"../instruments/bass/sawbass3\";\nimport { Eftang } from \"../instruments/lead/eftang\";\nimport { SoftPad } from \"../instruments/pad/softpad.class\";\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { SineLead } from \"../instruments/lead/sinelead\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst gain: f32 = 0.13;\nconst ENABLE_MULTIBAND_COMPRESSOR = false;\n\nlet freeverb = new Freeverb();\n\nconst delayframes = (SAMPLERATE * (2/3) * 60 / 110) as usize;\nlet delayLeft: DelayLine = new DelayLine(delayframes);\nlet delayRight: DelayLine = new DelayLine(delayframes);\n \nlet echoline = new StereoSignal();\nlet reverbline = new StereoSignal();\nlet mainline = new StereoSignal();\n\nlet tribandstereocompressor = new TriBandStereoCompressor(20,500,7000,19500);\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nfunction createInstrumentArray(length: i32, factoryFunc: () => T): T[] {\n const arr = new Array(length);\n for(let n = 0; n < length;n++) {\n arr[n] = factoryFunc();\n }\n return arr;\n}\n\nconst pianos: SubPiano[] = createInstrumentArray(8, () => new SubPiano());\nconst pads: SoftPad[] = createInstrumentArray(8, () => new SoftPad());\n\nconst kick = new Kick2();\nconst bass = new SawBass3();\nconst eftang = new Eftang();\nconst snare = new Snare2();\nconst hihat = new Hihat();\nconst sinelead = new SineLead();\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(true) {\n case (channel < 8):\n pianos[channel].note = value;\n break;\n case channel === 8:\n kick.note = value;\n break;\n case channel === 9:\n snare.note = value;\n break;\n case channel === 10:\n hihat.note = value;\n break;\n case channel === 11:\n bass.note = value\n break;\n case channel === 12:\n eftang.note = value;\n break;\n case channel < 21:\n pads[channel - 13].note = value;\n break;\n case channel === 21:\n sinelead.note = value;\n break;\n }\n}\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear()\n reverbline.clear();\n echoline.clear();\n \n for(let n = 0;n 1.0) {\n left = 1.0;\n }\n\n if (Math.abs(right) > 1.0) {\n right = 1.0;\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","synth/biquad.ts":"import { SAMPLERATE } from \"../environment\";\nimport { cos, PI, sin } from \"../math/sin\";\n\n// Taken from https://docs.rs/crate/biquad/0.2.0/source/src/\n\nexport const Q_BUTTERWORTH = 0.7071067811865475 as f32; // 1/Math.sqrt(2)\n\nexport enum FilterType {\n SinglePoleLowPass = 1 as i8,\n LowPass = 2 as i8,\n HighPass = 3 as i8,\n Notch = 4 as i8\n}\n\nexport class Coefficients {\n // Denominator coefficients\n a1: f32;\n a2: f32;\n\n // Nominator coefficients\n b0: f32;\n b1: f32;\n b2: f32;\n\n phaseSamples: f32;\n magnitude: f32;\n\n calculatePhaseAndMagnitudeForFreq(freq: f32): void {\n const w: f32 = 2 * Mathf.PI * freq / SAMPLERATE;\n \n const cos1: f32 = Mathf.cos(-1 * w);\n const cos2: f32 = Mathf.cos(-2 * w);\n \n const sin1: f32 = Mathf.sin(-1 * w);\n const sin2: f32 = Mathf.sin(-2 * w);\n \n const realZeros: f32 = this.b0 + this.b1 * cos1 + this.b2 * cos2;\n const imagZeros: f32 = this.b1 * sin1 + this.b2 * sin2;\n \n const realPoles: f32 = 1 + this.a1 * cos1 + this.a2 * cos2;\n const imagPoles: f32 = this.a1 * sin1 + this.a2 * sin2;\n \n const divider: f32 = realPoles * realPoles + imagPoles * imagPoles;\n \n const realHw: f32 = (realZeros * realPoles + imagZeros * imagPoles) / divider;\n const imagHw: f32 = (imagZeros * realPoles - realZeros * imagPoles) / divider;\n \n this.magnitude = Mathf.sqrt(realHw * realHw + imagHw * imagHw);\n\n const phase: f32 = Mathf.atan2(imagHw, realHw);\n \n this.phaseSamples = -(phase / (2*Mathf.PI)) * (SAMPLERATE / freq);\n }\n}\n\nexport class BiQuadFilter {\n y1: f32 = 0;\n y2: f32 = 0;\n x1: f32 = 0;\n x2: f32 = 0;\n s1: f32 = 0;\n s2: f32 = 0;\n readonly coeffs: Coefficients = new Coefficients();\n\n processForm2(input: f32): f32 {\n let out = this.s1 + this.coeffs.b0 * input;\n this.s1 = this.s2 + this.coeffs.b1 * input - this.coeffs.a1 * out;\n this.s2 = this.coeffs.b2 * input - this.coeffs.a2 * out;\n\n return out;\n }\n\n process(input: f32): f32 {\n let out = this.coeffs.b0 * input + this.coeffs.b1 * this.x1 + this.coeffs.b2 * this.x2\n - this.coeffs.a1 * this.y1\n - this.coeffs.a2 * this.y2;\n\n this.x2 = this.x1;\n this.x1 = input;\n this.y2 = this.y1;\n this.y1 = out;\n\n return out;\n }\n\n clearBuffers(): void {\n this.y1 = 0;\n this.y2 = 0;\n this.x1 = 0;\n this.x2 = 0;\n this.s1 = 0;\n this.s2 = 0; \n }\n\n /// Creates coefficients based on the biquad filter type, sampling and cutoff frequency, and Q\n /// value. Note that the cutoff frequency must be smaller than half the sampling frequency and\n /// that Q may not be negative, this will result in an `Err()`.\n update_coeffecients(\n filtertype: FilterType,\n fsHertz: f32,\n f0Hertz: f32,\n q_value: f32\n ): void {\n const fLimit = (fsHertz / 2.0) - 1000;\n if (f0Hertz > fLimit) {\n f0Hertz = fLimit;\n }\n\n if (q_value < 0.0) {\n q_value = 0;\n }\n\n let omega: f32 = 2.0 * PI * f0Hertz / fsHertz;\n let alpha: f32;\n let omega_s: f32;\n let omega_c: f32;\n let b0: f32;\n let b1: f32;\n let b2: f32;\n let a0: f32;\n let a1: f32;\n let a2: f32;\n\n\n switch (filtertype) {\n case FilterType.SinglePoleLowPass:\n alpha = omega / (omega + 1.0);\n\n this.coeffs.a1 = alpha - 1.0;\n this.coeffs.a2 = 0.0;\n this.coeffs.b0 = alpha;\n this.coeffs.b1 = 0.0;\n this.coeffs.b2 = 0.0;\n\n break;\n case FilterType.LowPass:\n // The code for omega_s/c and alpha is currently duplicated due to the single pole\n // low pass filter not needing it and when creating coefficients are commonly\n // assumed to be of low computational complexity.\n omega_s = sin(omega);\n omega_c = cos(omega);\n alpha = omega_s / (2.0 * q_value);\n\n b0 = (1.0 - omega_c) * 0.5;\n b1 = 1.0 - omega_c;\n b2 = (1.0 - omega_c) * 0.5;\n a0 = 1.0 + alpha;\n a1 = -2.0 * omega_c;\n a2 = 1.0 - alpha;\n\n this.coeffs.a1 = a1 / a0;\n this.coeffs.a2 = a2 / a0;\n this.coeffs.b0 = b0 / a0;\n this.coeffs.b1 = b1 / a0;\n this.coeffs.b2 = b2 / a0;\n\n break;\n case FilterType.HighPass:\n omega_s = sin(omega);\n omega_c = cos(omega);\n alpha = omega_s / (2.0 * q_value);\n\n b0 = (1.0 + omega_c) * 0.5;\n b1 = -(1.0 + omega_c);\n b2 = (1.0 + omega_c) * 0.5;\n a0 = 1.0 + alpha;\n a1 = -2.0 * omega_c;\n a2 = 1.0 - alpha;\n\n this.coeffs.a1 = a1 / a0;\n this.coeffs.a2 = a2 / a0;\n this.coeffs.b0 = b0 / a0;\n this.coeffs.b1 = b1 / a0;\n this.coeffs.b2 = b2 / a0;\n\n break;\n case FilterType.Notch:\n omega_s = sin(omega);\n omega_c = cos(omega);\n alpha = omega_s / (2.0 * q_value);\n\n b0 = 1.0;\n b1 = -2.0 * omega_c;\n b2 = 1.0;\n a0 = 1.0 + alpha;\n a1 = -2.0 * omega_c;\n a2 = 1.0 - alpha;\n\n this.coeffs.a1 = a1 / a0;\n this.coeffs.a2 = a2 / a0;\n this.coeffs.b0 = b0 / a0;\n this.coeffs.b1 = b1 / a0;\n this.coeffs.b2 = b2 / a0;\n\n break;\n }\n }\n}\n\nexport class LoPassBiQuadFilter extends BiQuadFilter {\n update(frequency: f32, Q: f32): void {\n this.update_coeffecients(FilterType.LowPass, SAMPLERATE, frequency , Q);\n }\n}\n\nexport class HiPassBiQuadFilter extends BiQuadFilter {\n update(frequency: f32, Q: f32): void {\n this.update_coeffecients(FilterType.HighPass, SAMPLERATE, frequency , Q);\n }\n}\n","synth/bpm.ts":"import { SAMPLERATE } from \"../environment\";\n\nexport function beatToFrame(beat: f64, bpm: f32): usize {\n return (SAMPLERATE * beat * 60 / bpm) as usize;\n}\n","synth/clip.ts":"// From https://ccrma.stanford.edu/~jos/pasp/Soft_Clipping.html#29695\n\n/**\n * soft clip signal with 1/3 headroom as result\n * @param signal signal to be clipped\n */\nexport function softclip(signal: f32): f32 {\n if(signal > 1.0) {\n return 2.0/3.0;\n } else if(signal < -1.0) {\n return -2.0/3.0;\n } else {\n return (signal - ((signal * signal * signal) / 3.0));\n }\n}\n\nexport function hardclip(signal: f32): f32 {\n if(signal > 1.0) {\n return 1.0;\n } else if(signal < -1.0) {\n return -1.0;\n } else {\n return signal;\n }\n}","synth/decibel.ts":"export function decibelToGain(dB: f32): f32 {\n return NativeMathf.pow(10, dB/20.0);\n}\n\nexport function midiLevelToDecibel(midiLevel: u8): f32 {\n return 40 * NativeMathf.log10(midiLevel as f32/127);\n}\n\nexport function midiLevelToGain(midiLevel: u8): f32 {\n return decibelToGain(midiLevelToDecibel(midiLevel));\n}","synth/envelope.class.ts":"import { SAMPLERATE } from \"../environment\";\n\nexport enum EnvelopeState {\n ATTACK = 0,\n DECAY = 1,\n SUSTAIN = 2,\n RELEASE = 3,\n DONE = 4\n}\n\nexport class Envelope {\n attackStep: f32;\n decayStep: f32;\n sustainLevel: f32;\n releaseStep: f32;\n \n val: f32 = 0;\n state: EnvelopeState = EnvelopeState.DONE;\n\n constructor(attackTime: f32, decayTime: f32, sustainLevel: f32, releaseTime: f32) {\n this.attackStep = 1.0 / (attackTime * SAMPLERATE);\n this.decayStep = 1.0 / (decayTime * SAMPLERATE);\n this.releaseStep = 1.0 / (releaseTime * SAMPLERATE);\n this.sustainLevel = sustainLevel;\n }\n\n next(): f32 {\n switch(this.state) {\n case EnvelopeState.ATTACK:\n this.val += this.attackStep;\n if(this.val >= 1.0) {\n this.val = 1.0;\n this.state = EnvelopeState.DECAY;\n }\n break;\n case EnvelopeState.DECAY:\n this.val -= this.decayStep;\n if(this.val <= this.sustainLevel) {\n this.val = this.sustainLevel;\n this.state = EnvelopeState.SUSTAIN;\n }\n break;\n case EnvelopeState.SUSTAIN:\n break;\n case EnvelopeState.RELEASE:\n this.val -= this.releaseStep;\n if(this.val <= 0) {\n this.val = 0;\n this.state = EnvelopeState.DONE;\n }\n break;\n case EnvelopeState.DONE:\n break;\n }\n return this.val;\n }\n\n attack(): void {\n this.state = EnvelopeState.ATTACK;\n }\n \n release(): void {\n this.state = EnvelopeState.RELEASE;\n }\n\n isDone(): boolean {\n return this.state === EnvelopeState.DONE;\n }\n}","synth/ifftoscillator.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { FFT } from '../math/fft';\n\nexport class IFFTOscillator {\n position: f32 = 0;\n positionincrement: f32 = 0;\n buffersize: f32;\n buffermask: u32;\n fft: FFT;\n scalefactor: f32;\n\n constructor(buffersize_shift: i32) {\n this.fft = new FFT(buffersize_shift);\n this.buffersize = (1 << buffersize_shift) as f32;\n this.buffermask = ~(0xffffffff << buffersize_shift);\n this.scalefactor = (this.buffersize / 2) - 1;\n }\n\n set frequency(frequency: f32) {\n this.positionincrement = (frequency * this.buffersize) / SAMPLERATE;\n }\n\n createWave(real: f32[], imaginary: f32[]): void { \n for (let n = 1; n <= real.length &&\n n <= imaginary.length &&\n n < (this.fft.buffer.length / 2) - 1; n++) {\n this.fft.buffer[n].re = -real[n - 1] * this.scalefactor;\n this.fft.buffer[this.fft.buffer.length - n].re = real[n -1] * this.scalefactor;\n\n this.fft.buffer[n].im = -imaginary[n -1] * this.scalefactor;\n this.fft.buffer[this.fft.buffer.length - n].im = imaginary[n -1] * this.scalefactor;\n }\n }\n\n next(): f32 {\n const bufferposfloor = NativeMathf.floor(this.position);\n const bufferpos = bufferposfloor as i32;\n const t = this.position - bufferposfloor;\n\n const x0 = this.fft.buffer[(bufferpos - 1) & this.buffermask].re;\n const x1 = this.fft.buffer[bufferpos].re;\n const x2 = this.fft.buffer[(bufferpos + 1) & this.buffermask].re;\n const x3 = this.fft.buffer[(bufferpos + 2) & this.buffermask].re;\n \n // cubic interpolation\n \n const a0 = x3 - x2 - x0 + x1;\n const a1 = x0 - x1 - a0;\n const a2 = x2 - x0;\n const a3 = x1;\n const ret = (a0 * (t * t * t)) + (a1 * (t * t)) + (a2 * t) + (a3);\n\n // increment position\n this.position += this.positionincrement;\n this.position %= this.buffersize;\n \n return ret; \n }\n}\n","synth/noise.class.ts":"let x: i32 = 123456789;\nlet y: i32=234567891;\nlet z: i32=345678912;\nlet w: i32=456789123;\nlet c: i32=0; \n\nexport class Noise {\n \n next(): f32 { \n y ^= (y<<5); y ^= (y>>7); y ^= (y<<22); \n\n let t = z+w+c; z = w;\n c = t < 0 ? 1 : 0;\n w = t & 2147483647; \n \n x += 1411392427; \n \n let rnd: f32 = ((x + y + w) & 0xffff) as f32;\n return ((rnd / (1 << 16 as f32))) - 0.5;\n }\n }\n ","synth/note.ts":"const pitchstep: f64 = 1.0004513695322617; // Math.pow(2, (1/128) / 12);\nconst c0: f64 = 8.175798915643707; // 440 * Math.pow(2, -69 / 12);\nlet pitchtable = __new(128 * 128 * 4, idof>());\nlet pitch: f64 = c0;\n\nfor (let n: usize = 0; n < (128 * 128); n++) {\n store(pitchtable + (n << 2), pitch as f32);\n pitch *= pitchstep;\n}\n\nexport function notefreq(note: f32): f32 {\n let pitchtableIndex: usize = (note * 128.0) as usize;\n return load(pitchtable + (pitchtableIndex << 2));\n}","synth/pan.class.ts":"import { StereoSignal } from \"./stereosignal.class\";\n\nconst HALF_OF_SQRT_2 = NativeMathf.sqrt(2) / 2;\n\nexport class Pan {\n leftLevel: f32;\n rightLevel: f32;\n \n constructor() {\n this.setPan(0.5); \n }\n\n /**\n * Don't use as part of the rendering process. Use to calculate pan levels on controller changes\n * @param pan from 0.0 (left) to 1.0 (right). 0.5 is center\n */\n setPan(pan: f32): void {\n const angle = (pan - 0.5) * NativeMathf.PI / 2;\n // left channel\n this.leftLevel = HALF_OF_SQRT_2 * (NativeMathf.cos(angle) - NativeMathf.sin(angle));\n // right channel\n this.rightLevel = HALF_OF_SQRT_2 * (NativeMathf.cos(angle) + NativeMathf.sin(angle));\n }\n}\n","synth/sawoscillator.class.ts":"\nimport { SAMPLERATE } from '../environment';\n\nexport class SawOscillator {\n position: u32 = 0;\n frequency: f32 = 0;\n\n next(): f32 {\n if(this.frequency > 0) {\n let ret = (this.position as f32 / 0x10000 as f32) - 0.5;\n this.position = (((this.position as f32) + (this.frequency/SAMPLERATE)\n * 0x10000 as f32) as u32) & 0xffff;\n \n \n return ret as f32;\n } else {\n return 0;\n }\n }\n }\n ","synth/shaper.ts":"/**\n * Taken from https://github.com/hzdgopher/64klang/blob/master/Player/Player/SynthNode.cpp#L2050\n */\n\nconst NOISEGEN_B0: f32 = 0.99765014648437500;\n\nexport class WaveShaper {\n drive: f32 = 0.5;\n \n process(input: f32): f32 { \n // clamp to -1..1 (a little less)\n let f: f32 = this.drive < NOISEGEN_B0 ? this.drive > -NOISEGEN_B0 ?\n this.drive : -NOISEGEN_B0 : \n NOISEGEN_B0;\n\n // k = 2*amount/(1-amount);\n let v = (f+f)/(1.0-f);\n\n // process f(x) = (1+k)*x/(1+k*abs(x))\n return (1.0 + v) *\n input/\n (1.0 + v * min(abs(input), 1.0)); \n }\n}","synth/sineoscillator.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { sin, PI } from '../math/sin';\n\nexport class SineOscillator {\n position: u32 = 0;\n frequency: f32 = 0;\n\n next(): f32 {\n let ret = sin(PI * 2 * (this.position as f32) / (1 << 16 as f32));\n this.position = (((this.position as f32) + (this.frequency/SAMPLERATE)\n * 0x10000 as f32) as u32) & 0xffff;\n \n return ret as f32;\n }\n }\n ","synth/squareoscillator.class.ts":"\nimport { SAMPLERATE } from '../environment';\n\nexport class SquareOscillator {\n position: u32 = 0;\n frequency: f32 = 0;\n\n next(): f32 {\n if(this.frequency > 0) {\n let ret: f32 = this.position as f32 > 0x8000 ? 0.5 : -0.5;\n this.position = (((this.position as f32) + (this.frequency/SAMPLERATE)\n * 0x10000 as f32) as u32) & 0xffff;\n \n \n return ret;\n } else {\n return 0;\n }\n }\n}\n ","synth/stereosignal.class.ts":"import { Pan } from './pan.class';\n\nexport class StereoSignal {\n left: f32 = 0;\n right: f32 = 0;\n\n clear(): void {\n this.left = 0;\n this.right = 0;\n }\n\n /**\n * Add left and right values directly to the signal\n * @param left\n * @param right \n */\n @inline\n add(left: f32, right:f32): void {\n this.left += left;\n this.right += right;\n }\n\n /**\n * Add stereo signal with simple (not proper) panning\n * @param signal \n * @param level \n * @param pan 0.0 - 1.0\n */\n addStereoSignal(signal: StereoSignal, level: f32, pan: f32): void {\n this.left += signal.left * pan * level;\n this.right += signal.right * (1 - pan) * level;\n }\n\n addMonoSignal(signal: f32, level: f32, pan: f32): void {\n this.left += signal * pan * level;\n this.right += signal * (1 - pan) * level;\n }\n}","synth/triangleoscillator.class.ts":"import { SAMPLERATE } from '../environment';\n\nexport class TriangleOscillator {\n position: i32 = 0;\n frequency: f32 = 0;\n\n next(): f32 {\n if (this.frequency > 0) {\n const pos: i32 = this.position;\n let ret: f32;\n if (pos < 0x8000) {\n ret = (pos as f32 / 0x8000 as f32);\n } else {\n ret = (- (pos - 0x8000) as f32 / 0x8000 as f32) + 1.0;\n }\n\n this.position = (((this.position as f32) + (this.frequency / SAMPLERATE)\n * 0x10000 as f32) as i32) & 0xffff;\n\n return ret * 2 - 1 as f32;\n } else {\n return 0;\n }\n }\n}\n","synth/waveguide.ts":"import { SAMPLERATE } from \"../environment\";\nimport { DelayLineFloat } from \"../fx/delayline\";\nimport { MonoAudioPlayer } from \"../midi/instruments/audioplayer\";\nimport { BiQuadFilter, FilterType, LoPassBiQuadFilter, Q_BUTTERWORTH } from \"./biquad\";\nimport { Envelope } from \"./envelope.class\";\nimport { notefreq } from \"./note\";\n\nlet seed: i32 = 1;\n\nexport function noise(): f32 {\n seed = (seed * 1103515245 + 12345) & 0x7fffffff;\n return ((seed as f32 % 1000000 / 1000000) - 0.5) as f32;\n}\n\nexport class WaveGuide {\n envExciter: Envelope;\n filterExciter: BiQuadFilter = new BiQuadFilter();\n delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);\n filterFeedback: BiQuadFilter = new BiQuadFilter();\n feedbackLevel: f32;\n feedbackFilterFreq: f32;\n freq: f32;\n exciterenvlevel: f32;\n\n constructor(exciterAttack: f32, exciterRelease: f32, exciterFilterFreq: f32, feedbackLevel: f32) {\n this.envExciter = new Envelope(exciterAttack,\n exciterRelease, 0,\n exciterRelease);\n this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n exciterFilterFreq, Q_BUTTERWORTH);\n\n this.feedbackLevel = feedbackLevel;\n }\n\n setFilterExciterFreq(freq: f32): void {\n this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n freq, Q_BUTTERWORTH);\n\n }\n\n start(freq: f32, feedbackFilterFreq: f32): void {\n if (freq != this.freq) {\n this.freq = freq;\n const maxFeedbackFilterFreq: f32 = 20000;\n if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {\n feedbackFilterFreq = maxFeedbackFilterFreq as f32;\n } else if (feedbackFilterFreq < 10) {\n feedbackFilterFreq = 10;\n }\n this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n feedbackFilterFreq, Q_BUTTERWORTH);\n\n this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);\n const filterphase = this.filterFeedback.coeffs.phaseSamples;\n\n this.filterFeedback.clearBuffers(); \n this.filterExciter.clearBuffers();\n\n this.feedbackFilterFreq = feedbackFilterFreq;\n this.delay.setNumFramesAndClear(\n (SAMPLERATE /\n (freq)\n ) - filterphase\n );\n this.envExciter.val = 0;\n\n }\n this.exciterenvlevel = 1;\n this.envExciter.attack();\n\n }\n\n process(): f32 {\n const envexciter = this.envExciter.next() * this.exciterenvlevel;\n let exciterSignal: f32 = noise() * envexciter;\n exciterSignal = this.filterExciter.process(exciterSignal);\n\n const feedback = this.delay.read();\n let signal = exciterSignal + feedback;\n\n signal = this.filterFeedback.processForm2(signal);\n this.delay.write_and_advance(\n signal * this.feedbackLevel\n );\n return signal;\n\n }\n}\n\nexport class AuxExciterWaveGuide {\n delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);\n filterFeedback: BiQuadFilter = new BiQuadFilter();\n feedbackFilterFreq: f32;\n feedbackLevel: f32;\n freq: f32;\n\n constructor(public exciter: WaveGuide) {\n\n }\n\n start(freq: f32, feedbackFilterFreq: f32): void {\n if (freq != this.freq) {\n this.freq = freq;\n const maxFeedbackFilterFreq: f32 = 20000;\n if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {\n feedbackFilterFreq = maxFeedbackFilterFreq as f32;\n } else if (feedbackFilterFreq < 10) {\n feedbackFilterFreq = 10;\n }\n this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n feedbackFilterFreq, Q_BUTTERWORTH);\n this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);\n const filterphase: f32 = this.filterFeedback.coeffs.phaseSamples;\n\n this.filterFeedback.clearBuffers();\n \n this.feedbackFilterFreq = feedbackFilterFreq;\n this.delay.setNumFramesAndClear(\n (SAMPLERATE /\n (freq)\n ) - filterphase\n );\n\n }\n }\n\n process(): f32 {\n let exciterSignal: f32 = this.exciter.process();\n\n const feedback = this.delay.read();\n let signal = exciterSignal + feedback;\n\n signal = this.filterFeedback.processForm2(signal);\n this.delay.write_and_advance(\n signal * this.feedbackLevel\n );\n return signal;\n }\n}\n\nexport class AudioExciterWaveGuide {\n delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);\n filterFeedback: BiQuadFilter = new BiQuadFilter();\n exciterFilter: LoPassBiQuadFilter = new LoPassBiQuadFilter();\n feedbackFilterFreq: f32;\n feedbackLevel: f32;\n freq: f32;\n\n constructor(public exciter: MonoAudioPlayer) {\n\n }\n\n start(freq: f32, feedbackFilterFreq: f32): void {\n this.exciter.restart();\n if (freq != this.freq) {\n this.freq = freq;\n const maxFeedbackFilterFreq: f32 = 20000;\n if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {\n feedbackFilterFreq = maxFeedbackFilterFreq as f32;\n } else if (feedbackFilterFreq < 10) {\n feedbackFilterFreq = 10;\n }\n this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n feedbackFilterFreq, Q_BUTTERWORTH);\n this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);\n const filterphase: f32 = this.filterFeedback.coeffs.phaseSamples;\n\n this.filterFeedback.clearBuffers();\n this.exciterFilter.clearBuffers();\n \n this.feedbackFilterFreq = feedbackFilterFreq;\n this.delay.setNumFramesAndClear(\n (SAMPLERATE /\n (freq)\n ) - filterphase\n );\n }\n }\n\n reset(): void {\n this.delay.reset();;\n this.filterFeedback.clearBuffers();\n this.exciterFilter.clearBuffers();\n }\n\n process(): f32 {\n let exciterSignal: f32 = this.exciter.nextframe();\n exciterSignal = this.exciterFilter.process(exciterSignal);\n\n const feedback = this.delay.read();\n let signal = exciterSignal + feedback;\n\n signal = this.filterFeedback.processForm2(signal);\n this.delay.write_and_advance(\n signal * this.feedbackLevel\n );\n return signal;\n }\n}\n\nexport class CustomExciterWaveGuide {\n delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);\n filterFeedback: BiQuadFilter = new BiQuadFilter();\n feedbackFilterFreq: f32;\n feedbackLevel: f32;\n freq: f32;\n exciterSignal: f32;\n\n start(freq: f32, feedbackFilterFreq: f32): void {\n if (freq != this.freq) {\n this.freq = freq;\n const maxFeedbackFilterFreq: f32 = 20000;\n if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {\n feedbackFilterFreq = maxFeedbackFilterFreq as f32;\n } else if (feedbackFilterFreq < 10) {\n feedbackFilterFreq = 10;\n }\n this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n feedbackFilterFreq, Q_BUTTERWORTH);\n this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);\n const filterphase: f32 = this.filterFeedback.coeffs.phaseSamples;\n\n this.filterFeedback.clearBuffers();\n \n this.feedbackFilterFreq = feedbackFilterFreq;\n this.delay.setNumFramesAndClear(\n (SAMPLERATE /\n (freq)\n ) - filterphase\n );\n }\n }\n\n process(): f32 {\n const feedback = this.delay.read();\n let signal = this.exciterSignal + feedback;\n\n signal = this.filterFeedback.processForm2(signal);\n this.delay.write_and_advance(\n signal * this.feedbackLevel\n );\n return signal;\n }\n}","wasi_main.ts":"import { fd_write, iovec} from 'bindings/wasi';\nimport { allocateSampleBuffer, getTick, setBPM, setPatternsPtr, setInstrumentPatternListPtr, fillSampleBufferInterleaved } from './index';\n\nconst patterns: i8[] = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,1,1,1,33,1,36,38,0,36,1,33,36,0,38,1,33,1,45,1,0,0,33,1,36,1,48,1,36,48,0,50,100,0,0,0,100,0,0,10,100,0,0,0,100,0,0,0,90,20,90,20,90,20,90,20,90,20,90,20,90,20,90,20,0,0,0,0,60,0,0,0,0,0,0,0,60,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,1,1,1,0,0,0,0,0,0,0,0,62,1,1,1,64,1,1,1,0,0,0,0,0,0,0,0,64,1,1,1,62,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,64,1,1,64,0,0,0,0,62,1,1,62,0,0,0,0,66,1,1,1,0,0,0,0,0,0,0,0,66,1,1,1,67,1,1,1,0,0,0,0,0,0,0,0,67,1,1,1,66,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,67,1,1,67,0,0,0,0,67,1,1,67,0,0,0,0,57,1,1,1,0,0,0,0,0,0,0,0,57,1,1,1,60,1,1,1,0,0,0,0,0,0,0,0,71,1,1,1,69,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,72,1,1,72,0,0,0,0,71,1,1,71,0,0,0,0,0,0,0,0,60,0,0,0,0,0,0,30,60,0,0,40,0,0,57,1,62,1,57,1,62,1,1,64,1,1,60,1,1,1,59,1,60,1,59,1,60,1,1,59,1,1,57,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,1,67,1,67,1,67,1,1,69,1,1,66,0,62,64,67,0,71,0,0,74,0,67,0,0,0,0,0,0,31,1,43,1,0,0,0,0,26,38,0,41,0,41,43,0,26,1,38,1,0,0,0,0,21,33,0,36,0,36,38,0,29,1,41,1,0,0,0,0,24,36,0,39,0,39,41,0,24,1,36,1,0,0,0,0,19,31,0,34,0,34,36,0,0,0,67,0,67,0,67,71,0,72,0,71,0,67,65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,0,65,62,0,65,0,67,0,69,0,0,67,0,0,64,0,62,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,65,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,67,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,69,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,71,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,72,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,62,0,65,0,67,0,69,0,0,67,0,0,0,72,0,72,71,0,72,0,74,0,71,0,0,67,0,0,0,0,62,74,0,62,74,0,62,0,69,1,1,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,0,67,0,74,72,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,71,1,1,1,67,1,1,1,0,0,0,0,1,1,1,1,71,1,1,1,67,1,1,1,69,1,1,1,72,1,1,1,1,1,1,1,1,1,1,1,71,1,69,1,67,1,1,1,1,1,1,1,1,1,1,1,1,1,64,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,16,32,48,64,0,0,0,0,0,0,0,0,0,0,0,32,40,48,64,0,0,0,0,0,0,0,0,0,0,0,0,74,1,1,1,1,1,1,1,1,1,1,1,1,1,1,77,1,1,1,1,1,1,1,1,1,1,1,1,76,1,74,1,72,1,1,1,1,1,1,1,1,1,1,1,1,1,79,1,2,16,32,48,64,0,0,0,0,0,0,0,0,80,96,32,36,40,48,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,96,112,127,0,0,0,0,0,20,0,30,60,0,0,20,0,20,0,30,60,20,60,40,81,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,64,0,48,32,16,0,0,0,0,64,0,0,0,0,0,0,57,0,57,0,62,0,62,0,69,0,69,0,72,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,78,74,69,0,0,0,0,62,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,0,0,10,0,10,0,0,60,0,0,25,0,20,0,0,60,10,0,10,0,10,35,0,60,10,0,35,0,0,69,0,69,0,74,0,74,0,81,0,81,0,83,0,83,0,81,0,81,0,74,0,76,0,74,0,74,0,0,0,0,0,62,1,1,1,69,1,71,1,1,1,69,1,1,1,64,1,1,69,1,1,62,1,1,1,1,1,1,1,0,0,64,0,0,0,0,0,0,0,2,32,64,0,0,0,0,0,64,1,1,69,1,1,62,1,1,1,64,1,66,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,67,1,1,1,66,1,1,1,64,1,62,1,1,1,59,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,32,48,64,0,0,69,0,69,0,74,86,74,0,81,0,81,0,83,91,83,0,81,0,81,0,74,86,76,0,74,86,91,90,86,81,83,0,81,0,81,0,74,0,76,0,74,0,74,0,86,0,69,1,1,1,0,0,0,0,0,0,0,0,69,1,1,1,67,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,69,1,1,69,0,0,0,0,67,1,1,67,0,0,0,0,71,1,1,1,0,0,0,0,0,0,0,0,71,1,1,1,72,1,1,1,0,0,0,0,0,0,0,0,72,1,1,1,71,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,72,1,1,67,0,0,0,0,72,1,1,67,0,0,0,0,65,1,1,1,0,0,0,0,0,0,0,0,76,1,1,1,74,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,77,1,1,72,0,0,0,0,76,1,1,71,0,0,0,0,31,1,1,1,38,1,41,43,0,41,1,38,41,0,43,1,38,1,50,1,0,0,38,1,41,1,53,1,41,53,0,55,0,0,74,0,74,0,79,0,79,0,86,0,86,0,88,0,88,0,86,0,86,0,79,0,81,0,79,0,79,0,0,0,0,0,74,0,74,0,79,91,79,0,86,0,86,0,88,96,88,0,86,0,86,0,79,91,81,0,79,91,96,95,91,86,0,0,67,1,1,1,74,1,76,1,1,1,74,1,1,1,69,1,1,74,1,1,67,1,1,1,1,1,1,1,0,0,88,0,86,0,86,0,79,0,81,0,79,0,79,0,91,0,69,1,1,74,1,1,67,1,1,1,69,1,71,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,72,1,1,1,71,1,1,1,69,1,67,1,1,1,64,1,1,1,26,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,100,0,0,0,100,0,0,30,100,0,0,0,100,0,0,0,90,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,1,1,1,0,0,0,0,0,0,0,0,60,1,1,1,57,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,66,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,69,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,69,74,81,0,74,81,86,0,0,0,0,0,0,0,0,91,90,86,81,0,0,0,0,0,0,0,0,0,0,0,0,93,86,81,78,74,69,74,78,0,0,0,0,0,74,81,74,81,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];\nconst instrumentspatternlists: i8[] = [1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,88,88,88,89,88,88,88,89,1,1,1,100,0,0,0,0,0,0,0,0,20,21,22,23,20,21,22,24,0,0,0,0,0,0,0,0,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,0,0,0,0,0,0,63,0,20,21,22,23,20,21,22,24,0,0,0,0,0,0,0,0,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,105,35,106,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,31,0,29,30,40,41,29,30,31,0,29,30,31,0,29,30,31,0,29,30,31,0,0,0,0,0,61,62,0,0,0,0,0,0,0,0,0,0,29,30,31,0,29,30,40,41,29,30,31,0,29,30,31,0,29,30,31,0,29,30,31,0,0,0,0,0,0,0,0,0,66,67,0,0,66,67,0,0,66,67,75,76,66,77,75,76,90,91,92,93,90,96,92,93,107,108,109,110,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,101,101,101,6,5,5,5,5,5,5,5,19,5,5,5,5,5,5,5,19,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,58,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,19,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,58,5,5,5,5,64,64,64,65,64,64,64,65,64,64,64,65,64,64,64,65,64,64,64,65,64,64,64,65,64,64,64,65,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,102,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,12,78,79,80,12,78,79,80,7,8,9,0,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,81,82,83,84,81,82,83,84,11,12,13,0,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,7,85,86,87,7,85,86,87,15,103,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,43,45,43,44,43,46,37,47,48,49,52,53,54,49,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,43,45,43,44,43,46,37,47,48,49,52,53,54,49,22,0,0,0,0,0,0,0,68,69,0,0,68,71,72,73,68,69,0,0,68,71,72,73,94,95,0,0,94,97,98,99,105,35,106,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,51,51,0,55,56,51,57,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,51,51,0,55,56,51,57,0,0,0,0,0,0,0,0,70,0,0,0,70,0,74,0,70,0,0,0,70,0,74,0,70,0,0,0,70,0,74,0,0,0,50,0];\n\n\n// ./node_modules/.bin/asc --runtime none assembly/wasi_main.ts --noAssert --use abort= -O3 -o build/index.wasm\n// wasmer build/index.wasm | sox -S -t raw -b 32 -e float -r 44100 -c 2 - -d\nexport function _start(): void {\n const samplebuf = allocateSampleBuffer(128);\n setPatternsPtr(load(changetype(patterns)));\n setInstrumentPatternListPtr(load(changetype(instrumentspatternlists)), 116, 19);\n setBPM(123);\n \n const iov = new iovec();\n iov.buf = samplebuf;\n iov.buf_len = 128 * 8;\n \n const written_ptr = changetype(new ArrayBuffer(sizeof()));\n \n let previousTick: f64;\n do {\n previousTick = getTick();\n fillSampleBufferInterleaved();\n fd_write(1, changetype(iov), 1, written_ptr);\n } while(previousTick < getTick())\n}"} \ No newline at end of file +{"common/mixcommon.ts":"export function createInstrumentArray(length: i32, factoryFunc: () => T): T[] {\n const arr = new Array(length);\n for(let n = 0; n < length;n++) {\n arr[n] = factoryFunc();\n }\n return arr;\n}\n","environment.ts":"// earlier this used to externally declared\nexport const SAMPLERATE: f32 = 44100;","fx/allpass.ts":"import { DelayLine } from \"./delayline\";\n\nexport class AllPass {\n readonly delay_line: DelayLine;\n\n constructor(delay_length: usize) {\n this.delay_line = new DelayLine(delay_length);\n }\n\n tick(input: f32): f32 {\n let delayed: f32 = this.delay_line.read();\n let output: f32 = -input + delayed;\n\n // in the original version of freeverb this is a member which is never modified\n const feedback: f32 = 0.5;\n\n this.delay_line\n .write_and_advance(input + delayed * feedback);\n\n return output;\n }\n}\n\nexport class AllPassFloat {\n coeff: f32;\n previousinput: f32;\n previousoutput: f32;\n\n setDelta(delta: f32): void {\n this.coeff = (1 - delta) / (1 + delta);\n }\n\n clearBuffers(): void {\n this.previousinput = 0;\n this.previousoutput = 0;\n }\n\n process(input: f32): f32 {\n const output = this.coeff * (input\n - this.previousoutput)\n + this.previousinput;\n this.previousoutput = output;\n this.previousinput = input;\n return output;\n }\n}\n","fx/bandpass.ts":"import { BiQuadFilter, FilterType, Q_BUTTERWORTH } from \"../synth/biquad\";\nimport { SAMPLERATE } from \"../environment\";\n\nexport class BandPass {\n lpfilter: BiQuadFilter = new BiQuadFilter();\n hpfilter: BiQuadFilter = new BiQuadFilter();\n \n constructor(lowfreq: f32, hifreq: f32) {\n this.update_frequencies(lowfreq, hifreq);\n }\n\n clearBuffers(): void {\n this.hpfilter.clearBuffers();\n this.lpfilter.clearBuffers();\n }\n\n update_frequencies(lowfreq: f32, hifreq: f32): void {\n this.lpfilter.update_coeffecients(FilterType.LowPass, SAMPLERATE, hifreq, Q_BUTTERWORTH);\n this.hpfilter.update_coeffecients(FilterType.HighPass, SAMPLERATE, lowfreq, Q_BUTTERWORTH);\n }\n\n process(sample: f32): f32 {\n return this.lpfilter.process(this.hpfilter.process(sample)); \n }\n}","fx/comb.ts":"import { DelayLine } from \"./delayline\";\n\nexport class Comb {\n readonly delay_line: DelayLine;\n feedback: f32;\n filter_state: f32;\n dampening: f32;\n dampening_inverse: f32;\n\n constructor(delay_length: usize) { \n this.delay_line = new DelayLine(delay_length);\n this.feedback= 0.5;\n this.filter_state = 0.0;\n this.dampening = 0.5;\n this.dampening_inverse = 0.5;\n \n }\n\n set_dampening(value: f32): void{\n this.dampening = value;\n this.dampening_inverse = 1.0 - value;\n }\n\n set_feedback(value: f32): void {\n this.feedback = value;\n }\n\n tick(input: f32): f32 {\n let output = this.delay_line.read();\n\n this.filter_state =\n output * this.dampening_inverse + this.filter_state * this.dampening;\n\n this.delay_line\n .write_and_advance(input + this.filter_state * this.feedback);\n\n return output;\n }\n}\n","fx/delayline.ts":"import { AllPassFloat } from \"./allpass\";\n\nexport class DelayLine {\n readonly bufferPointer: usize;\n index: usize = 0;\n length: usize = 0;\n currentPeak: f32 = 0;\n currentPeakSamplesToLive: usize = 0;\n\n private numsamplesf64: f64 = 0\n private meanSquared: f64 = 0;\n\n constructor(private numsamples: usize) {\n this.numsamplesf64 = numsamples as f64;\n this.length = numsamples * 4 as usize;\n this.bufferPointer = __new(this.length, 0);\n }\n\n read(): f32 {\n return load(this.bufferPointer + this.index);\n }\n\n calculateRMS(): f32 {\n let ndx = this.index;\n let bufferPointer = this.bufferPointer;\n\n let leastrecentsample: f64 = load(bufferPointer + ndx) as f64;\n if (ndx === 0) {\n ndx = this.length;\n }\n ndx -= 4;\n let mostrecentsample: f64 = load(bufferPointer + ndx) as f64;\n\n let meanSquared: f64 = this.meanSquared;\n let numSamples: f64 = this.numsamplesf64;\n meanSquared += ((mostrecentsample * mostrecentsample) / numSamples);\n meanSquared -= ((leastrecentsample * leastrecentsample) / numSamples);\n this.meanSquared = meanSquared;\n\n return Math.sqrt(meanSquared) as f32;\n }\n\n getPeakValue(): f32 {\n let ndx = this.index;\n if (ndx === 0) {\n ndx = this.length;\n }\n ndx -= 4;\n let mostrecentsample: f32 = load(this.bufferPointer + ndx) as f32;\n if (mostrecentsample < 0) {\n mostrecentsample = -mostrecentsample;\n }\n if (mostrecentsample > this.currentPeak) {\n this.currentPeak = mostrecentsample;\n this.currentPeakSamplesToLive = this.numsamples;\n } else if (this.currentPeakSamplesToLive > 0) {\n this.currentPeakSamplesToLive--;\n }\n if (this.currentPeakSamplesToLive == 0) {\n this.currentPeak = this.calculatePeakValue();\n }\n return this.currentPeak;\n }\n\n private calculatePeakValue(): f32 {\n let peak: f32 = 0.0;\n for (let i: usize = 0; i < this.length; i += 4) {\n let value = load(this.bufferPointer + i);\n if (value < 0) {\n value = -value;\n }\n if (value > peak) {\n peak = value;\n this.currentPeakSamplesToLive = ((i >= this.index) ? (i - this.index) : ((this.length) - this.index) + i) >> 2;\n }\n }\n return peak;\n }\n\n write_and_advance(value: f32): void {\n store(this.bufferPointer + this.index, value);\n\n if (this.index === this.length - 4) {\n this.index = 0;\n } else {\n this.index += 4;\n }\n }\n}\n\nexport class DelayLineFloat {\n buffer: StaticArray;\n frame: f64 = 0;\n numframes: f64 = 1;\n previous: f32;\n allpass: AllPassFloat = new AllPassFloat();\n\n constructor(private buffersizeframes: i32) {\n this.buffer = new StaticArray(buffersizeframes);\n }\n\n read(): f32 {\n const index = this.frame as i32 % this.buffer.length;\n return this.allpass.process(this.buffer[index]);\n }\n\n reset(): void {\n this.allpass.previousoutput = 0;\n this.allpass.previousinput = 0;\n for (let n = 0; n < this.numframes; n++) {\n this.buffer[n] = 0;\n }\n this.frame = 0;\n }\n\n setNumFramesAndClear(numframes: f64): void {\n this.numframes = Math.floor(numframes);\n this.allpass.setDelta((numframes - this.numframes) as f32);\n this.reset();\n }\n\n write_and_advance(value: f32): void {\n const index = ((this.frame++) + this.numframes) as i32 % this.buffer.length;\n this.buffer[index] = value;\n }\n}\n","fx/eqband.ts":"import { BiQuadFilter, FilterType, Q_BUTTERWORTH } from \"../synth/biquad\";\nimport { SAMPLERATE } from \"../environment\";\n\nexport class EQBand {\n lpfilter: BiQuadFilter = new BiQuadFilter();\n hpfilter: BiQuadFilter = new BiQuadFilter();\n lpfilter2: BiQuadFilter = new BiQuadFilter();\n hpfilter2: BiQuadFilter = new BiQuadFilter();\n \n \n constructor(lowfreq: f32, hifreq: f32) {\n this.lpfilter.update_coeffecients(FilterType.LowPass, SAMPLERATE, hifreq, Q_BUTTERWORTH);\n this.lpfilter2.update_coeffecients(FilterType.LowPass, SAMPLERATE, hifreq, Q_BUTTERWORTH);\n this.hpfilter.update_coeffecients(FilterType.HighPass, SAMPLERATE, lowfreq, Q_BUTTERWORTH);\n this.hpfilter2.update_coeffecients(FilterType.HighPass, SAMPLERATE, lowfreq, Q_BUTTERWORTH); \n }\n\n process(left: f32): f32 {\n return this.lpfilter2.process(this.lpfilter.process(this.hpfilter2.process(this.hpfilter.process(left)))); \n }\n}","fx/freeverb.ts":"\n/**\n * Freeverb implementation taken from Rust implementation here:\n * https://github.com/irh/freeverb-rs/blob/master/freeverb/src/freeverb.rs\n */\nimport { Comb } from './comb';\nimport { AllPass } from './allpass';\nimport { SAMPLERATE as SAMPLERATE_f32 } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\n\nlet SAMPLERATE = SAMPLERATE_f32 as usize;\nconst FIXED_GAIN: f32 = 0.015;\n\nconst SCALE_WET: f32 = 3.0;\nconst SCALE_DAMPENING: f32 = 0.4;\n\nconst SCALE_ROOM: f32 = 0.28;\nconst OFFSET_ROOM: f32 = 0.7;\n\nconst STEREO_SPREAD: usize = 23;\n\nconst COMB_TUNING_L1: usize = 1116;\nconst COMB_TUNING_R1: usize = 1116 + STEREO_SPREAD;\nconst COMB_TUNING_L2: usize = 1188;\nconst COMB_TUNING_R2: usize = 1188 + STEREO_SPREAD;\nconst COMB_TUNING_L3: usize = 1277;\nconst COMB_TUNING_R3: usize = 1277 + STEREO_SPREAD;\nconst COMB_TUNING_L4: usize = 1356;\nconst COMB_TUNING_R4: usize = 1356 + STEREO_SPREAD;\nconst COMB_TUNING_L5: usize = 1422;\nconst COMB_TUNING_R5: usize = 1422 + STEREO_SPREAD;\nconst COMB_TUNING_L6: usize = 1491;\nconst COMB_TUNING_R6: usize = 1491 + STEREO_SPREAD;\nconst COMB_TUNING_L7: usize = 1557;\nconst COMB_TUNING_R7: usize = 1557 + STEREO_SPREAD;\nconst COMB_TUNING_L8: usize = 1617;\nconst COMB_TUNING_R8: usize = 1617 + STEREO_SPREAD;\n\nconst ALLPASS_TUNING_L1: usize = 556;\nconst ALLPASS_TUNING_R1: usize = 556 + STEREO_SPREAD;\nconst ALLPASS_TUNING_L2: usize = 441;\nconst ALLPASS_TUNING_R2: usize = 441 + STEREO_SPREAD;\nconst ALLPASS_TUNING_L3: usize = 341;\nconst ALLPASS_TUNING_R3: usize = 341 + STEREO_SPREAD;\nconst ALLPASS_TUNING_L4: usize = 225;\nconst ALLPASS_TUNING_R4: usize = 225 + STEREO_SPREAD;\n\nfunction adjust_length(length: usize, sr: usize): usize {\n return ((length as f32) * (sr as f32) / SAMPLERATE_f32) as usize;\n}\n\nexport class Freeverb { \n readonly COMB1_L: Comb = new Comb(adjust_length(COMB_TUNING_L1, SAMPLERATE));\n readonly COMB1_R: Comb = new Comb(adjust_length(COMB_TUNING_L1, SAMPLERATE));\n readonly COMB2_L: Comb = new Comb(adjust_length(COMB_TUNING_R2, SAMPLERATE));\n readonly COMB2_R: Comb = new Comb(adjust_length(COMB_TUNING_L2, SAMPLERATE));\n readonly COMB3_L: Comb = new Comb(adjust_length(COMB_TUNING_R3, SAMPLERATE));\n readonly COMB3_R: Comb = new Comb(adjust_length(COMB_TUNING_L3, SAMPLERATE));\n readonly COMB4_L: Comb = new Comb(adjust_length(COMB_TUNING_R4, SAMPLERATE));\n readonly COMB4_R: Comb = new Comb(adjust_length(COMB_TUNING_L4, SAMPLERATE));\n readonly COMB5_L: Comb = new Comb(adjust_length(COMB_TUNING_R5, SAMPLERATE));\n readonly COMB5_R: Comb = new Comb(adjust_length(COMB_TUNING_L5, SAMPLERATE));\n readonly COMB6_L: Comb = new Comb(adjust_length(COMB_TUNING_R6, SAMPLERATE));\n readonly COMB6_R: Comb = new Comb(adjust_length(COMB_TUNING_L6, SAMPLERATE));\n readonly COMB7_L: Comb = new Comb(adjust_length(COMB_TUNING_R7, SAMPLERATE));\n readonly COMB7_R: Comb = new Comb(adjust_length(COMB_TUNING_L7, SAMPLERATE));\n readonly COMB8_L: Comb = new Comb(adjust_length(COMB_TUNING_R8, SAMPLERATE));\n readonly COMB8_R: Comb = new Comb(adjust_length(COMB_TUNING_L8, SAMPLERATE));\n\n readonly ALL1_L: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_L1, SAMPLERATE));\n readonly ALL1_R: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_R1, SAMPLERATE));\n readonly ALL2_L: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_L2, SAMPLERATE));\n readonly ALL2_R: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_R2, SAMPLERATE));\n readonly ALL3_L: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_L3, SAMPLERATE));\n readonly ALL3_R: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_R3, SAMPLERATE));\n readonly ALL4_L: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_L4, SAMPLERATE));\n readonly ALL4_R: AllPass = new AllPass(adjust_length(ALLPASS_TUNING_R4, SAMPLERATE));\n\n wet_gain_left: f32 = 0;\n wet_gain_right: f32 = 0;\n \n wet: f32 = 0;\n width: f32 = 0;\n dry: f32 = 0;\n input_gain: f32 = 0;\n dampening: f32 = 0;\n room_size: f32 = 0;\n frozen: bool = 0;\n\n constructor() {\n this.set_wet(1.0);\n this.set_width(0.5);\n this.set_dampening(0.5);\n this.set_room_size(0.7);\n this.set_frozen(false); \n }\n\n tick(signal: StereoSignal): void {\n let input_mixed = (signal.left + signal.right) * FIXED_GAIN * this.input_gain;\n\n let leftoutput:f32 = 0;\n let rightoutput:f32 = 0;\n\n leftoutput += this.COMB1_L.tick(input_mixed);\n rightoutput+= this.COMB1_R.tick(input_mixed);\n leftoutput += this.COMB2_L.tick(input_mixed);\n rightoutput+= this.COMB2_R.tick(input_mixed);\n leftoutput += this.COMB3_L.tick(input_mixed);\n rightoutput+= this.COMB3_R.tick(input_mixed);\n leftoutput += this.COMB4_L.tick(input_mixed);\n rightoutput+= this.COMB4_R.tick(input_mixed);\n leftoutput += this.COMB5_L.tick(input_mixed);\n rightoutput+= this.COMB5_R.tick(input_mixed);\n leftoutput += this.COMB6_L.tick(input_mixed);\n rightoutput+= this.COMB6_R.tick(input_mixed);\n leftoutput += this.COMB7_L.tick(input_mixed);\n rightoutput+= this.COMB7_R.tick(input_mixed);\n leftoutput += this.COMB8_L.tick(input_mixed);\n rightoutput+= this.COMB8_R.tick(input_mixed);\n \n leftoutput= this.ALL1_L.tick(leftoutput);\n rightoutput = this.ALL1_R.tick(rightoutput);\n leftoutput= this.ALL2_L.tick(leftoutput);\n rightoutput = this.ALL2_R.tick(rightoutput);\n leftoutput= this.ALL3_L.tick(leftoutput);\n rightoutput = this.ALL3_R.tick(rightoutput);\n leftoutput= this.ALL4_L.tick(leftoutput);\n rightoutput = this.ALL4_R.tick(rightoutput);\n\n signal.left = leftoutput * this.wet_gain_left +\n rightoutput * this.wet_gain_right +\n signal.left * this.dry;\n signal.right = rightoutput * this.wet_gain_left +\n leftoutput * this.wet_gain_right +\n signal.right * this.dry; \n }\n\n update_combs(): void {\n let feedback: f32;\n let dampening: f32;\n\n if(this.frozen) {\n feedback =1.0;\n dampening = 0.0;\n } else {\n feedback = this.room_size;\n dampening = this.dampening;\n }\n \n this.COMB1_L.set_feedback(feedback);\n this.COMB1_R.set_feedback(feedback);\n this.COMB1_L.set_dampening(dampening);\n this.COMB1_R.set_dampening(dampening);\n this.COMB2_L.set_feedback(feedback);\n this.COMB2_R.set_feedback(feedback);\n this.COMB2_L.set_dampening(dampening);\n this.COMB2_R.set_dampening(dampening);\n this.COMB3_L.set_feedback(feedback);\n this.COMB3_R.set_feedback(feedback);\n this.COMB3_L.set_dampening(dampening);\n this.COMB3_R.set_dampening(dampening);\n this.COMB4_L.set_feedback(feedback);\n this.COMB4_R.set_feedback(feedback);\n this.COMB4_L.set_dampening(dampening);\n this.COMB4_R.set_dampening(dampening);\n this.COMB5_L.set_feedback(feedback);\n this.COMB5_R.set_feedback(feedback);\n this.COMB5_L.set_dampening(dampening);\n this.COMB5_R.set_dampening(dampening);\n this.COMB6_L.set_feedback(feedback);\n this.COMB6_R.set_feedback(feedback);\n this.COMB6_L.set_dampening(dampening);\n this.COMB6_R.set_dampening(dampening);\n this.COMB7_L.set_feedback(feedback);\n this.COMB7_R.set_feedback(feedback);\n this.COMB7_L.set_dampening(dampening);\n this.COMB7_R.set_dampening(dampening);\n this.COMB8_L.set_feedback(feedback);\n this.COMB8_R.set_feedback(feedback);\n this.COMB8_L.set_dampening(dampening);\n this.COMB8_R.set_dampening(dampening);\n }\n\n set_dampening(value: f32): void {\n this.dampening = value * SCALE_DAMPENING;\n this.update_combs();\n }\n\n set_freeze(frozen: bool): void {\n this.frozen = frozen;\n this.update_combs();\n }\n\n set_wet(value: f32): void {\n this.wet = value * SCALE_WET;\n this.update_wet_gains();\n }\n\n set_width(value: f32): void {\n this.width = value;\n this.update_wet_gains();\n }\n\n update_wet_gains(): void {\n this.wet_gain_left = this.wet * (this.width / 2.0 + 0.5);\n this.wet_gain_right = this.wet * ((1.0 - this.width) / 2.0); \n }\n\n set_frozen(frozen: bool): void {\n this.frozen = frozen;\n this.input_gain = frozen ? 0.0 : 1.0;\n this.update_combs();\n }\n\n set_room_size(value: f32): void {\n this.room_size = value * SCALE_ROOM + OFFSET_ROOM;\n this.update_combs();\n }\n\n set_dry(value: f32): void {\n this.dry = value;\n }\n}\n","fx/limiter.ts":"import { SAMPLERATE } from '../environment';\n\nexport class Limiter {\n attack: f32 = 0;\n release: f32 = 0;\n envelope: f32 = 0;\n\n constructor(attackMs: f32, releaseMs: f32) {\n this.attack = Mathf.pow(0.01, 1.0 / (attackMs * SAMPLERATE * 0.001));\n this.release = Mathf.pow(0.01, 1.0 / (releaseMs * SAMPLERATE * 0.001));\n }\n\n process(signal: f32): f32 {\n const v = Mathf.abs(signal);\n if (v > this.envelope) {\n this.envelope = this.attack * (this.envelope - v) + v;\n } else {\n this.envelope = this.release * (this.envelope - v) + v;\n }\n\n if (this.envelope > 1) {\n signal /= this.envelope;\n }\n return signal;\n }\n}\n","fx/midsideprocessor.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nexport class MidSideProcessor {\n signal: StereoSignal = new StereoSignal();\n\n constructor(private side_level: f32) {\n\n }\n\n process(left: f32, right: f32): void {\n // Mid-side processing\n let mid: f32 = (left + right) / 2.0;\n let side: f32 = (left - right) / 2.0;\n\n side *= this.side_level;\n this.signal.left = mid + side;\n this.signal.right = mid - side;\n }\n}","fx/monocompressor.ts":"import { DelayLine } from \"./delayline\";\nexport class MonoCompressor {\n delay: DelayLine;\n\n gain: f64 = 1.0;\n targetgain: f64 = 1.0;\n gainChangePerSample: f64 = 0;\n delaybuffersamplecount: f64;\n releasesamplecount: f64;\n\n constructor(numsamples: usize) {\n this.delay = new DelayLine(numsamples);\n this.delaybuffersamplecount = numsamples as f64;\n this.releasesamplecount = this.delaybuffersamplecount;\n }\n\n setRelaseSampleCount(releasesamplecount: f64): void {\n this.releasesamplecount = releasesamplecount;\n }\n\n process(signal: f32, threshold: f32, makeupgain: f32): f32 {\n this.delay.write_and_advance(signal);\n\n let currentTargetGain: f64 = this.targetgain;\n let currentGain: f64 = this.gain;\n\n let peak: f64 = this.delay.getPeakValue();\n\n if(peak > threshold) {\n let targetGain = threshold / peak;\n\n if(targetGain < currentTargetGain) {\n currentTargetGain = targetGain;\n this.targetgain = targetGain;\n\n let newGainChangePerSample = (currentTargetGain - currentGain) / this.delaybuffersamplecount;\n \n if(newGainChangePerSample < this.gainChangePerSample) {\n this.gainChangePerSample = newGainChangePerSample;\n }\n } \n } else if(currentTargetGain < 1.0) {\n currentTargetGain = 1.0;\n this.targetgain = currentTargetGain; \n this.gainChangePerSample = (currentTargetGain - currentGain) / this.releasesamplecount;\n }\n\n let gainChangePerSample: f64 = this.gainChangePerSample;\n if((gainChangePerSample < 0 && currentTargetGain < currentGain) ||\n (gainChangePerSample > 0 && currentTargetGain > currentGain)) {\n currentGain += gainChangePerSample;\n this.gain = currentGain;\n }\n\n return this.delay.read() * currentGain as f32 * makeupgain;\n }\n}\n\nexport class StereoCompressor {\n leftCompressor: MonoCompressor;\n rightCompressor: MonoCompressor;\n\n resultSignal: StereoSignal = new StereoSignal();\n \n constructor(numsamples: usize) {\n this.leftCompressor = new MonoCompressor(numsamples);\n this.rightCompressor = new MonoCompressor(numsamples);\n }\n\n process(left: f32, right: f32, threshold: f32, makeupgain: f32): void {\n this.resultSignal.left = this.leftCompressor.process(left, threshold, makeupgain);\n \tthis.resultSignal.right = this.rightCompressor.process(right, threshold, makeupgain); \n }\n}\n","fx/multibandeq.ts":"import { EQBand } from './eqband';\nexport class MultiBandEQ {\n bands: StaticArray;\n\n constructor(freqs: f32[]) {\n this.bands = new StaticArray(freqs.length - 1);\n for (let n = 1; n < freqs.length; n++) {\n this.bands[n - 1] = new EQBand(freqs[n - 1], freqs[n]);\n }\n }\n\n\n process(signal: f32, levels: f32[]): f32 {\n let ret: f32 = 0;\n const numbands = this.bands.length;\n for (let n = 0; n < numbands; n++) {\n ret += this.bands[n].process(signal) * levels[n];\n }\n return ret;\n }\n}\n","fx/stereocompressor.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\nimport { MonoCompressor } from \"./monocompressor\";\n\nexport class StereoCompressor {\n leftCompressor: MonoCompressor;\n rightCompressor: MonoCompressor;\n\n resultSignal: StereoSignal = new StereoSignal();\n \n constructor(numsamples: usize) {\n this.leftCompressor = new MonoCompressor(numsamples);\n this.rightCompressor = new MonoCompressor(numsamples);\n }\n\n process(left: f32, right: f32, threshold: f32, makeupgain: f32): void {\n this.resultSignal.left = this.leftCompressor.process(left, threshold, makeupgain);\n \tthis.resultSignal.right = this.rightCompressor.process(right, threshold, makeupgain); \n }\n}\n","fx/tribandeq.ts":"import { EQBand } from \"./eqband\";\n\nexport class TriBandEQ {\n \n lowerband: EQBand;\n midband: EQBand;\n hiband: EQBand;\n\n constructor(low: f32, midlo: f32, midhi: f32, high: f32) {\n this.lowerband = new EQBand(low, midlo);\n this.midband = new EQBand(midlo, midhi);\n this.hiband = new EQBand(midhi, high);\n }\n\n process(signal: f32, lolevel: f32, midlevel: f32, hilevel: f32): f32 {\n return this.lowerband.process(signal) * lolevel +\n this.midband.process(signal) * midlevel +\n this.hiband.process(signal) * hilevel;\n }\n}","fx/tribandstereocompressor.ts":"import { EQBand } from \"./eqband\";\nimport { StereoSignal } from \"../synth/stereosignal.class\";\nimport { StereoCompressor } from \"./stereocompressor\";\nimport { SAMPLERATE } from \"../environment\";\n\nexport class TriBandStereoCompressor {\n lowerbandl: EQBand; \n midbandl: EQBand; \n hibandl: EQBand;\n \n lowerbandr: EQBand; \n midbandr: EQBand; \n hibandr: EQBand;\n \n compressorLow: StereoCompressor;\n compressorMid: StereoCompressor;\n compressorHigh: StereoCompressor;\n\n stereosignal: StereoSignal = new StereoSignal();\n\n constructor(low: f32, midlo: f32, midhi: f32, high: f32, compressor_delay: f32 = 0.2) {\n this.compressorLow = new StereoCompressor((SAMPLERATE * compressor_delay) as usize);\n this.compressorMid = new StereoCompressor((SAMPLERATE * compressor_delay) as usize);\n this.compressorHigh = new StereoCompressor((SAMPLERATE * compressor_delay) as usize);\n\n this.lowerbandl = new EQBand(low, midlo);\n this.lowerbandr = new EQBand(low, midlo);\n \n this.midbandl = new EQBand(midlo, midhi);\n this.midbandr = new EQBand(midlo, midhi);\n \n this.hibandl = new EQBand(midhi, high);\n this.hibandr = new EQBand(midhi, high);\n }\n\n process(left: f32, right: f32, \n lolevel: f32, \n midlevel: f32, \n hilevel: f32,\n lomakeupgain: f32,\n midmakeupgain: f32,\n himakeupgain: f32): void {\n let lowleft = this.lowerbandl.process(left);\n let midleft = this.midbandl.process(left);\n let hileft = this.hibandl.process(left);\n\n let lowright = this.lowerbandr.process(right);\n let midright = this.midbandr.process(right);\n let hiright = this.hibandr.process(right);\n\n this.compressorLow.process(lowleft,lowright,lolevel,lomakeupgain);\n this.compressorMid.process(midleft,midright,midlevel,midmakeupgain);\n this.compressorHigh.process(hileft,hiright,hilevel,himakeupgain);\n \n this.stereosignal.left = this.compressorLow.resultSignal.left + this.compressorMid.resultSignal.left + this.compressorHigh.resultSignal.left;\n this.stereosignal.right = this.compressorLow.resultSignal.right + this.compressorMid.resultSignal.right + this.compressorHigh.resultSignal.right;\n }\n}","index.ts":"// The entry file of the synth WebAssembly module.\n\n// --- Replace with your own mix implementation here\nimport { mixernext, setChannelValue, PATTERN_SIZE_SHIFT, BEATS_PER_PATTERN_SHIFT } from './mixes/newyear.mix';\nexport { setChannelValue } from './mixes/newyear.mix';\n// -------------------------------------------------\n\nimport { SAMPLERATE } from './environment';\n\nconst PATTERN_LENGTH: f32 = (1 << PATTERN_SIZE_SHIFT) as f32;\n\nlet NUM_INSTRUMENTS: i32;\n\nlet holdChannelValuesBufferPtr: usize;\nlet currentChannelValuesBufferPtr: usize;\nlet patternsPtr: usize;\nlet instrumentPatternListsPtr: usize;\nlet sampleBufferPtr: usize;\nlet sampleBufferFrames: usize;\nlet songlength: usize = 0;\n\nlet patternIndexf64: f64 = 0;\nlet patternIndex: usize = 0; \nlet patternNoteIndex: usize = -1;\n\nlet tick: f64 = 0;\nlet ticksPerBeat: f32 = (1 << PATTERN_SIZE_SHIFT >> BEATS_PER_PATTERN_SHIFT) as f32;\nlet bpm: f32 = 120;\n\nlet ticksPerSec = ticksPerBeat * bpm / 60;\nlet ticksPerSample = ticksPerSec / SAMPLERATE;\n\nlet playOrPause: boolean = true;\n\nexport function setBPM(BPM: f32): void {\n bpm = BPM;\n ticksPerSec = ticksPerBeat * BPM / 60;\n ticksPerSample = ticksPerSec / SAMPLERATE;\n}\n\nexport function setTick(newtick: f64): void {\n tick = newtick;\n}\n\nexport function getTick(): f64 {\n return tick;\n}\n\nexport function setMilliSecondPosition(millis: f64): void {\n let newtick: f64 = millis * ticksPerSec / 1000;\n let ticklength = songlength as f64 * PATTERN_LENGTH;\n\n newtick -= (floor(newtick / ticklength) * ticklength);\n if(abs(newtick - tick) > 1) {\n tick = newtick;\n }\n}\n\nexport function getPatternIndex(): usize {\n return patternIndex;\n}\n\nexport function getPatternNoteIndex(): usize {\n return patternNoteIndex;\n}\n\nexport function toggleSongPlay(status: boolean): void {\n if(!status && playOrPause) {\n for(let n=0;n songlengthf64) {\n tick -= (songlengthf64 * PATTERN_LENGTH); \n }\n\n patternIndexf64 = (tick / PATTERN_LENGTH) as f64;\n patternIndex = patternIndexf64 as usize; \n let newPatternNoteIndex: usize = ((patternIndexf64 - (patternIndex as f64)) * PATTERN_LENGTH) as usize;\n\n if(newPatternNoteIndex===patternNoteIndex) {\n return;\n }\n\n patternNoteIndex = newPatternNoteIndex;\n \n for(let n=0;n(instrumentPatternListsPtr +\n n * songlength +\n patternIndex) as usize;\n \n let channelValue: f32 = load(patternsPtr + (instrumentPatternIndex << PATTERN_SIZE_SHIFT)\n + patternNoteIndex) as f32;\n \n let holdChannelValue: f32 = load(holdChannelValuesBufferPtr + n * 4);\n if(holdChannelValue > 0 && channelValue !== 1 && channelValue !== holdChannelValue) {\n // Hold value\n channelValue = 1;\n store(patternsPtr + (instrumentPatternIndex << PATTERN_SIZE_SHIFT)\n + patternNoteIndex, 1 as u8);\n }\n\n // 1 means HOLD value - no change to the visualizer \n if(channelValue !== 1) { \n // For external visualizer to monitor channel values currently been played by the sequencer \n store(currentChannelValuesBufferPtr + n*4, channelValue);\n setChannelValue(n, channelValue);\n } \n }\n}\n\nexport function getHoldChannelValuesBufferPtr(): usize {\n return holdChannelValuesBufferPtr;\n}\n\nexport function recordChannelValue(channel: usize, value: f32): void {\n store(holdChannelValuesBufferPtr + channel * 4, value);\n setChannelValue(channel, value);\n}\n\nexport function setPatternsPtr(ptr: usize): void {\n patternsPtr = ptr;\n}\n\nexport function allocatePatterns(numpatterns: i32): usize {\n patternsPtr = __new(numpatterns << PATTERN_SIZE_SHIFT, idof>());\n return patternsPtr;\n}\n\nexport function setInstrumentPatternListPtr(ptr: usize, songpatternslength: i32, numinstruments: i32): void {\n instrumentPatternListsPtr = ptr;\n NUM_INSTRUMENTS = numinstruments;\n songlength = songpatternslength;\n \n currentChannelValuesBufferPtr = __new(NUM_INSTRUMENTS * 4, idof>());\n holdChannelValuesBufferPtr = __new(NUM_INSTRUMENTS * 4, idof>());\n}\n\nexport function allocateInstrumentPatternList(songpatternslength: i32, numinstruments: i32): usize {\n NUM_INSTRUMENTS = numinstruments;\n songlength = songpatternslength;\n \n currentChannelValuesBufferPtr = __new(NUM_INSTRUMENTS * 4, idof>());\n holdChannelValuesBufferPtr = __new(NUM_INSTRUMENTS * 4, idof>());\n instrumentPatternListsPtr = __new(songpatternslength * NUM_INSTRUMENTS, idof>());\n\n return instrumentPatternListsPtr;\n}\n\nexport function allocateSampleBuffer(frames: usize): usize {\n sampleBufferFrames = frames;\n sampleBufferPtr = __new(frames * 2 * 4, idof>());\n return sampleBufferPtr;\n}\n\nexport function getCurrentChannelValuesBufferPtr(): usize {\n return currentChannelValuesBufferPtr;\n}\n\nexport function fillSampleBuffer(): void { \n updateInstrumentNotes();\n for(let n: usize = 0;n 1) { \n this.sawoscillator.frequency = notefreq(note + 0.1) / 2;\n this.sawoscillator2.frequency = notefreq(note - 0.1) / 2;\n this.envelope.attack(); \n this.filterenv.attack(); \n } else {\n this.envelope.release();\n this.filterenv.release();\n }\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n // this.signal.clear();\n let filterenv = this.filterenv.next();\n this.signal.left *= 0.9 * env; // feedback\n this.signal.right *= 0.9 * env; // feedback\n this.lpfilterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (100 * filterenv), Q_BUTTERWORTH);\n this.lpfilterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (100 * filterenv), Q_BUTTERWORTH);\n \n this.signal.addMonoSignal(\n this.lpfilterl.process(this.hpfilterl.process(this.sawoscillator.next() * env)), 0.3, 0.3\n );\n this.signal.addMonoSignal(\n this.lpfilterr.process(this.hpfilterr.process(this.sawoscillator2.next() * env)), 0.3, 0.7\n );\n } \n}\n ","instruments/bass/sawbass2.class.ts":"\nimport { SAMPLERATE } from '../../environment';\n\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\n\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { notefreq } from '../../synth/note';\n\n\nexport class SawBass2 {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.2, 0.8, 0.2);\n readonly filterenv: Envelope = new Envelope(0.01, 0.4, 0.0, 0.2);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly hpfilterl: BiQuadFilter = new BiQuadFilter();\n readonly hpfilterr: BiQuadFilter = new BiQuadFilter();\n \n readonly lpfilterl: BiQuadFilter = new BiQuadFilter();\n readonly lpfilterr: BiQuadFilter = new BiQuadFilter();\n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n this.hpfilterl.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH);\n this.hpfilterr.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH);\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = notefreq(note + 0.1);\n this.sawoscillator2.frequency = notefreq(note - 0.1);\n this.envelope.attack(); \n this.filterenv.attack(); \n } else {\n this.envelope.release();\n this.filterenv.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n // this.signal.clear();\n let filterenv = this.filterenv.next();\n this.signal.left /= 1.03; // feedback\n this.signal.right /= 1.03; // feedback\n this.lpfilterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (8000 * filterenv), Q_BUTTERWORTH);\n this.lpfilterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, 300 + (8000 * filterenv), Q_BUTTERWORTH);\n \n this.signal.addMonoSignal(\n this.lpfilterl.process(this.hpfilterl.process(this.sawoscillator.next() * env)), 0.3, 0.3\n );\n this.signal.addMonoSignal(\n this.lpfilterr.process(this.hpfilterr.process(this.sawoscillator2.next() * env)), 0.3, 0.7\n );\n } \n}\n ","instruments/bass/sawbass3.ts":"\nimport { SAMPLERATE } from '../../environment';\n\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\n\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { notefreq } from '../../synth/note';\nimport { BandPass } from '../../fx/bandpass';\n\n\nexport class SawBass3 {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.3, 0.8, 0.2);\n readonly filterenv: Envelope = new Envelope(0.01, 0.2, 0.1, 0.2);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n \n readonly filter: BiQuadFilter = new BiQuadFilter();\n \n readonly lpfilter: BiQuadFilter = new BiQuadFilter();\n readonly band1: BandPass = new BandPass(1000, 2000);\n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = notefreq(note);\n \n this.envelope.attack(); \n this.filterenv.attack(); \n } else {\n this.envelope.release();\n this.filterenv.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n \n let filterenv = this.filterenv.next();\n \n let signal = this.sawoscillator.next();\n signal *= env;\n \n this.lpfilter.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n this.sawoscillator.frequency + (16 * this.sawoscillator.frequency * filterenv), Q_BUTTERWORTH);\n \n const band1freq = this.sawoscillator.frequency * 4;\n this.band1.update_frequencies(band1freq, band1freq + env * this.sawoscillator.frequency);\n\n let band1 = this.band1.process(signal);\n signal = this.lpfilter.process(signal);\n \n this.signal.left = signal * 2 + band1; \n this.signal.right = signal * 2 - band1;\n \n } \n}\n ","instruments/drivelead.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { Noise } from '../synth/noise.class';\nimport { WaveShaper } from '../synth/shaper';\nimport { notefreq } from '../synth/note';\n\n\nexport class DriveLead {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.1, 1.0, 0.6, 0.2);\n readonly sawoscillatorl: SawOscillator = new SawOscillator();\n readonly sawoscillatorr: SawOscillator = new SawOscillator();\n readonly shaper: WaveShaper = new WaveShaper();\n readonly signal: StereoSignal = new StereoSignal();\n readonly lfoenvelope: Envelope = new Envelope(1.0, 0, 1.0, 0.1);\n readonly lfo: SineOscillator = new SineOscillator();\n baseFrequency : f32;\n pitchbend: f32 = 0;\n\n set note(note: f32) { \n if(note > 1) { \n this.shaper.drive = 0.5; \n this.baseFrequency = notefreq(note);\n this.lfo.frequency = 8;\n this.envelope.attack(); \n this.lfoenvelope.attack(); \n this._note = note;\n } else {\n this.envelope.release();\n this.lfoenvelope.release();\n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n setPitchbend(bend: f32): void {\n this.pitchbend = bend; \n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env===0) {\n this.signal.clear();\n return;\n }\n \n const pitchbend: f32 = this.pitchbend;\n if (Math.abs(pitchbend) > 0.01) {\n // Simple pitchbend that always will return to base note\n this.baseFrequency = notefreq(this._note + pitchbend);\n this.pitchbend = pitchbend * 0.9999;\n } else if(pitchbend !==0 ) {\n this.pitchbend = 0;\n this.baseFrequency = notefreq(this._note);\n }\n \n let lfo: f32 = this.lfo.next() * 3 * this.lfoenvelope.next();\n this.sawoscillatorl.frequency = this.baseFrequency + lfo + 0.5;\n this.sawoscillatorr.frequency = this.baseFrequency + lfo - 0.5;\n \n let left = env* this.sawoscillatorl.next() + this.signal.right * 0.5;\n left = this.shaper.process(left);\n \n let right = env* this.sawoscillatorr.next() + this.signal.left * 0.5;\n right = this.shaper.process(right);\n \n this.signal.left = left * 0.5 + right;\n this.signal.right = right * 0.5 + left; \n } \n}\n ","instruments/drums/kick2.class.ts":"\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\nimport { Instrument } from '../instrument.class';\n\nexport class Kick2 extends Instrument {\n private velocity: f32;\n \n readonly noise: Noise = new Noise();\n \n readonly env2: Envelope = new Envelope(0.001, 0.01, 0.0, 1);\n readonly bp2: BandPass = new BandPass(4000, 5000); \n \n readonly env3: Envelope = new Envelope(0.001, 0.1, 0.05, 0.1);\n readonly bp3: BandPass = new BandPass(10, 100);\n\n set note(note: f32) { \n if(note > 1) { \n this.velocity = note / 16; \n this.env2.attack(); \n this.env3.attack(); \n } else {\n \n this.env2.release(); \n this.env3.release(); \n }\n }\n\n next(): void {\n let env2: f32 = this.env2.next();\n let env3: f32 = this.env3.next();\n \n let osc: f32 = this.noise.next();\n \n \n let sig2 = this.bp2.process(osc) * env2 ;\n let sig3 = this.bp3.process(osc) * env3 * 8;\n\n this.signal.left = this.velocity * (-sig2 + sig3);\n this.signal.right = this.velocity * ( + sig2 - sig3); \n } \n}\n ","instruments/drums/rimshot.class.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\n\nexport class Rimshot {\n private _note: f32;\n private velocity: f32;\n \n readonly noise: Noise = new Noise();\n readonly env1: Envelope = new Envelope(0.001, 1.0, 0.8, 0.3);\n readonly bp1: BandPass = new BandPass(200, 350);\n readonly env2: Envelope = new Envelope(0.001, 0.08, 0.06, 1);\n readonly bp2: BandPass = new BandPass(3000, 7000); \n \n readonly env3: Envelope = new Envelope(0.001, 0.05, 0.01, 0.1);\n readonly bp3: BandPass = new BandPass(10, 150); \n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.velocity = note / 16; \n this.env1.attack(); \n this.env2.attack(); \n this.env3.attack(); \n } else {\n this.env1.release();\n this.env2.release(); \n this.env3.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env1: f32 = this.env1.next();\n let env2: f32 = this.env2.next();\n let env3: f32 = this.env3.next();\n \n let osc: f32 = this.noise.next();\n \n let sig1 = this.bp1.process(osc) * env1;\n let sig2 = this.bp2.process(osc) * env2 * 2;\n let sig3 = this.bp3.process(osc) * env3 * 16;\n\n this.signal.left = this.velocity * (sig1 + sig2 * 0.8 + sig3);\n this.signal.right = this.velocity * (sig1 * 0.8 + sig2 + sig3);\n \n \n } \n}\n ","instruments/drums/snare2.class.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\n\nexport class Snare2 {\n private _note: f32;\n private velocity: f32;\n \n readonly noise: Noise = new Noise();\n readonly env1: Envelope = new Envelope(0.001, 1.0, 0.8, 0.3);\n readonly bp1: BandPass = new BandPass(200, 350);\n readonly env2: Envelope = new Envelope(0.001, 0.08, 0.06, 0.5);\n readonly bp2: BandPass = new BandPass(3000, 7000); \n \n readonly env3: Envelope = new Envelope(0.001, 0.05, 0.01, 0.1);\n readonly bp3: BandPass = new BandPass(10, 150); \n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.velocity = note / 16; \n this.env1.attack(); \n this.env2.attack(); \n this.env3.attack(); \n } else {\n this.env1.release();\n this.env2.release(); \n this.env3.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env1: f32 = this.env1.next();\n let env2: f32 = this.env2.next();\n let env3: f32 = this.env3.next();\n \n let osc: f32 = this.noise.next();\n \n let sig1 = this.bp1.process(osc) * env1 * 6;\n let sig2 = this.bp2.process(osc) * env2 * 2;\n let sig3 = this.bp3.process(osc) * env3 * 4;\n\n this.signal.left = this.velocity * (sig1 + sig2 * 0.8 + sig3);\n this.signal.right = this.velocity * (sig1 * 0.8 + sig2 + sig3);\n \n \n } \n}\n ","instruments/hihat.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { Noise } from '../synth/noise.class';\n\nexport class Hihat {\n private _note: f32;\n private velocity: f32;\n\n readonly envelope: Envelope = new Envelope(0.0, 0.08, 0, 0.1); \n readonly noise: Noise = new Noise();\n \n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.velocity = note / 32; \n this.envelope.attack(); \n } else {\n this.envelope.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next(); \n if(env === 0) {\n this.signal.clear();\n return;\n } \n let osc: f32 = this.noise.next(); \n let signal = this.velocity * 2 * env * osc;\n \n this.filter.update_coeffecients(FilterType.HighPass, SAMPLERATE, \n 10000 + 2000 * env, Q_BUTTERWORTH);\n\n signal = this.filter.process(signal);\n\n this.signal.left = signal;\n this.signal.right = signal;\n } \n}\n ","instruments/instrument.class.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nexport abstract class Instrument {\n abstract set note(note: f32);\n readonly signal: StereoSignal = new StereoSignal();\n abstract next(): void;\n}","instruments/kick.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { Noise } from '../synth/noise.class';\n\n\n\nexport class Kick {\n private _note: f32;\n private velocity: f32;\n readonly envelope: Envelope = new Envelope(0.0, 0.2, 0, 0.2);\n readonly filterenvelope: Envelope = new Envelope(0.0, 0.05, 0.05, 0.1);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly noise: Noise = new Noise();\n \n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = 150;\n this.velocity = note / 16; \n this.envelope.attack(); \n this.filterenvelope.attack(); \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n this.sawoscillator.frequency = 20.0 + (env * 150.0);\n \n this.filter.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 40 + (this.filterenvelope.next() * 2000), 0.2);\n\n let osc1: f32 = this.envelope.next() * this.velocity * this.sawoscillator.next() * 0.8 + this.noise.next();\n\n osc1 = this.filter.process(osc1);\n \n this.signal.left = env * osc1;\n this.signal.right = env * osc1;\n } \n}\n ","instruments/lead/brassy.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\n\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\n\nimport { SineOscillator } from '../../synth/sineoscillator.class';\nimport { notefreq } from '../../synth/note';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\n\nexport class BrassyLead {\n private _note: f32;\n \n readonly osc: SineOscillator = new SineOscillator();\n readonly osc2: SawOscillator = new SawOscillator();\n \n readonly env1: Envelope = new Envelope(0.01, 0.1, 0.4, 0.3);\n \n readonly filterenv: Envelope = new Envelope(0.01, 0.1, 0.1, 0.3);\n \n readonly lopass: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.osc.frequency = notefreq(note);\n this.osc2.frequency = notefreq(note);\n this._note = note;\n this.env1.attack();\n \n this.filterenv.attack(); \n } else {\n this.env1.release(); \n \n this.filterenv.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n const env1: f32 = this.env1.next();\n if(env1 === 0) {\n this.signal.clear();\n return;\n }\n \n let osc: f32 = this.osc.next() * 0.05;\n let osc2: f32 = this.osc2.next() * env1 * 0.2;\n\n const pan = this._note / 127;\n\n let sig = osc + osc2;\n\n const filterenv = this.filterenv.next();\n this.lopass.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n (14000 * filterenv) , Q_BUTTERWORTH);\n sig = this.lopass.process(sig);\n \n this.signal.left = sig;\n this.signal.right = sig;\n \n \n } \n}\n ","instruments/lead/eftang.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { notefreq } from '../../synth/note';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class Eftang {\n private _note: f32;\n \n\n readonly lfo: SineOscillator = new SineOscillator();\n readonly osc: SawOscillator = new SawOscillator();\n readonly osc2: SawOscillator = new SawOscillator();\n readonly osc3: SawOscillator = new SawOscillator();\n \n readonly noise: Noise = new Noise();\n readonly env1: Envelope = new Envelope(0.001, 1.0, 0.8, 0.3);\n readonly bp1: BandPass = new BandPass(200, 350);\n readonly env2: Envelope = new Envelope(0.1, 0.2, 0.5, 1);\n readonly bp2: BandPass = new BandPass(3000, 7000); \n \n readonly env3: Envelope = new Envelope(0.001, 0.3, 0.1, 0.1);\n readonly bp3: BandPass = new BandPass(10, 150); \n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.osc.frequency = notefreq(note);\n this.osc2.frequency = notefreq(note - 0.1);\n this.osc3.frequency = notefreq(note + 0.1);\n this.lfo.position = 0;\n this.lfo.frequency = 4;\n \n this.env1.attack(); \n this.env2.attack(); \n this.env3.attack(); \n } else {\n this.env1.release();\n this.env2.release(); \n this.env3.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n const env1: f32 = this.env1.next();\n if(env1 === 0) {\n this.signal.clear();\n return;\n }\n \n const env2: f32 = this.env2.next();\n const env3: f32 = this.env3.next();\n \n const osc: f32 = this.osc.next() + this.osc2.next() + this.osc3.next();\n \n const lfo = this.lfo.next() + 1;\n const basefreq = this.osc.frequency;\n this.bp1.update_frequencies(20, basefreq + 1);\n this.bp2.update_frequencies(basefreq * 1.5,basefreq * 1.6);\n this.bp3.update_frequencies(basefreq * 12, 8000 + (lfo * 5000));\n const noise = this.noise.next();\n\n const sig1 = this.bp1.process(osc) * env1;\n const sig2 = this.bp2.process(osc) * env2;\n const sig3 = this.bp3.process(osc + noise * 0.2) * env3;\n\n this.signal.left = (sig1 + sig3);\n this.signal.right = ( sig1 + sig2 );\n \n \n } \n}\n ","instruments/lead/sinelead.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\n\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { notefreq } from '../../synth/note';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class SineLead {\n private _note: f32;\n \n\n readonly osc: SineOscillator = new SineOscillator();\n readonly osc2: SineOscillator = new SineOscillator();\n \n readonly env1: Envelope = new Envelope(0.02, 0.15, 0.05, 0.3);\n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n this.osc.frequency = notefreq(note) * 2;\n this.osc2.frequency = notefreq(note);\n this._note = note;\n this.env1.attack(); \n } else {\n this.env1.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n const env1: f32 = this.env1.next();\n \n let osc: f32 = this.osc.next();\n let osc2: f32 = this.osc2.next() * 0.2 * env1;\n osc *= env1;\n\n const pan = this._note / 127;\n\n this.signal.left = osc * pan + osc2 * (1-pan);\n this.signal.right = osc * (1 - pan) + osc2 * pan;\n \n \n } \n}\n ","instruments/pad/flatpad.class.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { notefreq } from '../../synth/note';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class FlatPad {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.1, 1.0, 0.1);\n readonly filterenvelope: Envelope = new Envelope(0.001, 1.0, 1.0, 0.1);\n readonly hipassfilterenvelope: Envelope = new Envelope(0.02, 3, 0.2, 2.0);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly sawoscillator3: SawOscillator = new SawOscillator();\n readonly sawoscillator4: SawOscillator = new SawOscillator();\n readonly sawoscillator5: SawOscillator = new SawOscillator();\n readonly lfo: SineOscillator = new SineOscillator();\n \n readonly filterl: BiQuadFilter = new BiQuadFilter();\n readonly filterr: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.lfo.frequency = 1;\n this.lfo.position = 0;\n this.sawoscillator.frequency = notefreq(note);\n this.sawoscillator2.frequency = notefreq(note + 0.03);\n this.sawoscillator3.frequency = notefreq(note - 0.03);\n this.sawoscillator4.frequency = notefreq(note + 0.06);\n this.sawoscillator5.frequency = notefreq(note - 0.06);\n \n this.envelope.attack(); \n this.filterenvelope.attack(); \n this.hipassfilterenvelope.attack(); \n this._note = note; \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n this.hipassfilterenvelope.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n \n }\n\n const lfo: f32 = this.lfo.next();\n\n const note = this.note;\n if(note<2) {\n return;\n }\n this.sawoscillator2.frequency = notefreq(note + 0.05 + (0.02 * lfo));\n this.sawoscillator3.frequency = notefreq(note - 0.05 - (0.02 * lfo));\n this.sawoscillator4.frequency = notefreq(note + 0.1 + (0.03 * lfo));\n this.sawoscillator5.frequency = notefreq(note - 0.1 - (0.03 * lfo));\n \n \n let osc: f32 = this.sawoscillator.next();\n let osc2: f32 = this.sawoscillator2.next();\n let osc3: f32 = this.sawoscillator3.next();\n let osc4: f32 = this.sawoscillator4.next();\n let osc5: f32 = this.sawoscillator5.next();\n \n let left = env * (osc + osc2 + osc5);\n let right = env * (osc + osc3 + osc4 );\n\n const filterlfo: f32 = (lfo * 0.9) + 1;\n this.filterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 10000 + 20 * (127 - this.note), Q_BUTTERWORTH);\n \n this.filterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 10000 + 20 * (this.note), Q_BUTTERWORTH);\n \n this.signal.left = this.filterl.process(left );\n this.signal.right = this.filterr.process(right );\n } \n}\n ","instruments/pad/softpad.class.ts":"\nimport { SAMPLERATE } from '../../environment';\nimport { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { SawOscillator } from '../../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../../synth/biquad';\nimport { notefreq } from '../../synth/note';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class SoftPad {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.2, 0.6, 0.75, 0.5);\n readonly filterenvelope: Envelope = new Envelope(0.8, 1.0, 0.6, 0.5);\n readonly hipassfilterenvelope: Envelope = new Envelope(0.02, 3, 0.2, 2.0);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly sawoscillator3: SawOscillator = new SawOscillator();\n readonly sawoscillator4: SawOscillator = new SawOscillator();\n readonly sawoscillator5: SawOscillator = new SawOscillator();\n readonly lfo: SineOscillator = new SineOscillator();\n \n readonly filterl: BiQuadFilter = new BiQuadFilter();\n readonly filterr: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.lfo.frequency = 1;\n this.lfo.position = 0;\n this.sawoscillator.frequency = notefreq(note);\n this.sawoscillator2.frequency = notefreq(note + 0.03);\n this.sawoscillator3.frequency = notefreq(note - 0.03);\n this.sawoscillator4.frequency = notefreq(note + 0.06);\n this.sawoscillator5.frequency = notefreq(note - 0.06);\n \n this.envelope.attack(); \n this.filterenvelope.attack(); \n this.hipassfilterenvelope.attack(); \n this._note = note; \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n this.hipassfilterenvelope.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n \n }\n\n const lfo: f32 = this.lfo.next();\n\n const note = this.note;\n if(note<2) {\n return;\n }\n this.sawoscillator2.frequency = notefreq(note + 0.05 + (0.02 * lfo));\n this.sawoscillator3.frequency = notefreq(note - 0.05 - (0.02 * lfo));\n this.sawoscillator4.frequency = notefreq(note + 0.1 + (0.03 * lfo));\n this.sawoscillator5.frequency = notefreq(note - 0.1 - (0.03 * lfo));\n \n \n let osc: f32 = this.sawoscillator.next();\n let osc2: f32 = this.sawoscillator2.next();\n let osc3: f32 = this.sawoscillator3.next();\n let osc4: f32 = this.sawoscillator4.next();\n let osc5: f32 = this.sawoscillator5.next();\n \n let left = env * (osc + osc2 + osc5);\n let right = env * (osc + osc3 + osc4 );\n\n const filterlfo = lfo + 1;\n this.filterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 2000 + 20 * (127 - this.note), Q_BUTTERWORTH);\n \n this.filterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 2000 + 20 * (this.note), Q_BUTTERWORTH);\n \n this.signal.left = this.filterl.process(left );\n this.signal.right = this.filterr.process(right );\n } \n}\n ","instruments/pad.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { notefreq } from '../synth/note';\nimport { WaveShaper } from '../synth/shaper';\n\n\n\nexport class Pad {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.05, 0.6, 0.75, 0.3);\n readonly filterenvelope: Envelope = new Envelope(0.06, 0.6, 0.3, 0.3);\n readonly hipassfilterenvelope: Envelope = new Envelope(0.02, 3, 0.2, 2.0);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly sawoscillator3: SawOscillator = new SawOscillator();\n readonly sawoscillator4: SawOscillator = new SawOscillator();\n readonly sawoscillator5: SawOscillator = new SawOscillator();\n \n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly hipassfilterl: BiQuadFilter = new BiQuadFilter();\n readonly hipassfilterr: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = notefreq(note);\n this.sawoscillator2.frequency = notefreq(note + 0.05);\n this.sawoscillator3.frequency = notefreq(note - 0.05);\n this.sawoscillator4.frequency = notefreq(note + 0.1);\n this.sawoscillator5.frequency = notefreq(note - 0.1);\n \n this.envelope.attack(); \n this.filterenvelope.attack(); \n this.hipassfilterenvelope.attack(); \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n this.hipassfilterenvelope.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n \n }\n let osc: f32 = this.sawoscillator.next();\n let osc2: f32 = this.sawoscillator2.next();\n let osc3: f32 = this.sawoscillator3.next();\n let osc4: f32 = this.sawoscillator4.next();\n let osc5: f32 = this.sawoscillator5.next();\n \n let left = env * (osc + osc2 + osc5);\n let right = env * (osc + osc3 + osc4 );\n\n this.filter.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * 18000, 0.2);\n let hpfilterfreq: f32 = 0 + (1-this.hipassfilterenvelope.next()) * 500;\n this.hipassfilterl.update_coeffecients(FilterType.HighPass, SAMPLERATE, \n hpfilterfreq, 0.3);\n this.hipassfilterr.update_coeffecients(FilterType.HighPass, SAMPLERATE, \n hpfilterfreq, 0.3);\n \n this.signal.left = this.hipassfilterl.process(this.filter.process(left ));\n this.signal.right = this.hipassfilterr.process(this.filter.process(right ));\n } \n}\n ","instruments/piano/subpiano.ts":"import { StereoSignal } from '../../synth/stereosignal.class';\nimport { Envelope } from '../../synth/envelope.class';\nimport { Noise } from '../../synth/noise.class';\nimport { BandPass } from '../../fx/bandpass';\nimport { notefreq } from '../../synth/note';\nimport { SquareOscillator } from '../../synth/squareoscillator.class';\nimport { SineOscillator } from '../../synth/sineoscillator.class';\n\nexport class SubPiano {\n private _note: f32;\n private pan: f32;\n\n readonly lfo: SineOscillator = new SineOscillator();\n readonly osc: SquareOscillator = new SquareOscillator();\n readonly env1: Envelope = new Envelope(0.02, 1.5, 0.1, 0.4);\n readonly bp1: BandPass = new BandPass(200, 350);\n readonly env2: Envelope = new Envelope(0.01, 0.6, 0.02, 0.2);\n readonly bp2: BandPass = new BandPass(3000, 7000); \n \n readonly env3: Envelope = new Envelope(0.01, 0.1, 0.00, 0.1);\n readonly bp3: BandPass = new BandPass(10, 150); \n \n readonly signal: StereoSignal = new StereoSignal();\n\n constructor() {\n \n }\n\n set note(note: f32) { \n if(note > 1) { \n let freq : f32 = notefreq(note);\n this.osc.frequency = freq;\n this.lfo.frequency = 5.0;\n this.pan = note / 128.0;\n\n this.env1.attack(); \n this.env2.attack(); \n this.env3.attack(); \n } else {\n this.env1.release();\n this.env2.release(); \n this.env3.release(); \n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env1: f32 = this.env1.next();\n let env2: f32 = this.env2.next();\n let env3: f32 = this.env3.next();\n \n let osc: f32 = this.osc.next();\n \n const lfo: f32 = this.lfo.next();\n const filterlfo = lfo + 1;\n const panlfo = lfo * 0.2 + 1;\n const freq: f32 = this.osc.frequency;\n this.bp1.update_frequencies(freq, freq + filterlfo * 30);\n this.bp2.update_frequencies(freq * 1.5, freq * 1.5 + filterlfo * 300);\n this.bp3.update_frequencies(freq * 2.25, freq * 2.25 + filterlfo * 800);\n \n let sig1 = this.bp1.process(osc) * env1 * 12;\n let sig2 = this.bp2.process(osc) * env2 * 6;\n let sig3 = this.bp3.process(osc) * env3 * 10;\n\n this.signal.left = this.pan * (sig1 * panlfo + sig2 * 0.8 * -panlfo + sig3 * panlfo);\n this.signal.right = 1 - this.pan * (sig1 * 0.8 * -panlfo + sig2 * panlfo + sig3 - panlfo * 0.2);\n } \n}\n ","instruments/sawbass.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { notefreq } from '../synth/note';\nimport { Instrument } from './instrument.class';\n\nexport class SawBass extends Instrument {\n readonly envelope: Envelope = new Envelope(0.01, 0.2, 0.8, 0.2);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly filter: BiQuadFilter = new BiQuadFilter();\n readonly hpfilterl: BiQuadFilter = new BiQuadFilter();\n readonly hpfilterr: BiQuadFilter = new BiQuadFilter();\n \n constructor() {\n super();\n this.hpfilterl.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH);\n this.hpfilterr.update_coeffecients(FilterType.HighPass, SAMPLERATE, 35, Q_BUTTERWORTH);\n }\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = notefreq(note + 0.1);\n this.sawoscillator2.frequency = notefreq(note - 0.1);\n this.envelope.attack(); \n } else {\n this.envelope.release();\n }\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n // this.signal.clear();\n this.signal.left /= 1.03; // feedback\n this.signal.right /= 1.03; // feedback\n this.signal.addMonoSignal(\n this.hpfilterl.process(this.sawoscillator.next() * env), 0.3, 0.3\n );\n this.signal.addMonoSignal(\n this.hpfilterr.process(this.sawoscillator2.next() * env), 0.3, 0.7\n );\n } \n}\n ","instruments/snare.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { Noise } from '../synth/noise.class';\nimport { Instrument } from './instrument.class';\n\nexport class Snare extends Instrument {\n private velocity: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.2, 0, 0.2);\n readonly hpfilterenvelope: Envelope = new Envelope(0.01, 0.5, 0.5, 0.3);\n \n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly noise: Noise = new Noise();\n \n readonly hpfilter: BiQuadFilter = new BiQuadFilter();\n readonly lpfilter: BiQuadFilter = new BiQuadFilter();\n\n constructor() {\n super();\n this.lpfilter.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 13000 , Q_BUTTERWORTH);\n }\n\n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = 200;\n this.velocity = note / 16; \n this.envelope.attack(); \n this.hpfilterenvelope.attack(); \n } else {\n this.envelope.release();\n this.hpfilterenvelope.release();\n }\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n }\n this.sawoscillator.frequency = 20.0 + (env * 200.0);\n \n \n this.hpfilter.update_coeffecients(FilterType.HighPass, SAMPLERATE, \n 20000 - (19900 * this.hpfilterenvelope.next()) , Q_BUTTERWORTH);\n\n let osc1: f32 = this.sawoscillator.next() * 0.6 + this.noise.next();\n osc1= this.hpfilter.process(osc1);\n osc1 = this.lpfilter.process(osc1);\n\n this.signal.left = this.velocity * env * osc1;\n this.signal.right = this.velocity * env * osc1;\n \n \n } \n}\n ","instruments/squarelead.class.ts":"\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { WaveShaper } from '../synth/shaper';\nimport { notefreq } from '../synth/note';\nimport { SquareOscillator } from '../synth/squareoscillator.class';\nimport { BiQuadFilter, Q_BUTTERWORTH, FilterType } from '../synth/biquad';\nimport { SAMPLERATE } from '../environment';\n\n\nexport class SquareLead {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.02, 0.2, 0.2, 0.2);\n readonly filterenvelope: Envelope = new Envelope(0.02, 0.1, 0.4, 0.2);\n readonly squareoscillatorl: SquareOscillator = new SquareOscillator();\n readonly squareoscillatorr: SquareOscillator = new SquareOscillator();\n readonly lpfilterleft: BiQuadFilter = new BiQuadFilter();\n readonly lpfilterright: BiQuadFilter = new BiQuadFilter();\n readonly shaper: WaveShaper = new WaveShaper();\n readonly signal: StereoSignal = new StereoSignal();\n \n baseFrequency : f32;\n\n set note(note: f32) { \n if(note > 1) { \n this.shaper.drive = 0.5; \n this.baseFrequency = notefreq(note);\n this.envelope.attack(); \n this.filterenvelope.attack();\n } else {\n this.envelope.release();\n this.filterenvelope.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n let filterenv: f32 = this.filterenvelope.next();\n if(env===0 && filterenv===0) {\n this.signal.clear();\n return;\n }\n \n this.squareoscillatorl.frequency = this.baseFrequency + 0.3;\n this.squareoscillatorr.frequency = this.baseFrequency - 0.3;\n \n this.lpfilterleft.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n filterenv * 3000, Q_BUTTERWORTH);\n this.lpfilterright.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n filterenv * 3000, Q_BUTTERWORTH);\n \n let left = env* this.squareoscillatorl.next();\n left = this.shaper.process(left);\n left = this.lpfilterleft.process(left);\n\n let right = env* this.squareoscillatorr.next();\n right = this.shaper.process(right);\n right = this.lpfilterright.process(right);\n\n this.signal.left = left;\n this.signal.right = right; \n } \n}\n ","instruments/string1.class.ts":"\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { notefreq } from '../synth/note';\n\nexport class Test4KlangString {\n private _note: f32;\n readonly env0: Envelope = new Envelope(0.01, 0.2, 0.8, 0.2);\n readonly vco1: SineOscillator = new SineOscillator();\n readonly vco5: SawOscillator = new SawOscillator();\n readonly vco6: SawOscillator = new SawOscillator();\n\n readonly signal: StereoSignal = new StereoSignal();\n\n notefreq: f32;\n\n set note(note: f32) { \n if(note > 1) { \n this.notefreq = notefreq(note);\n this.vco1.frequency = this.notefreq / 1000;\n\n this.env0.attack(); \n } else {\n this.env0.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let f_0:f32 = this.env0.next(); // GO4K_ENV ATTAC(88),DECAY(88),SUSTAIN(88),RELEASE(88),GAIN(88)\n let f_1:f32 = this.vco1.next(); // GO4K_VCO TRANSPOSE(76),DETUNE(64),PHASE(64),GATES(85),COLOR(64),SHAPE(64),GAIN(64),FLAGS(SINE|LFO)\n this.vco5.frequency = this.notefreq + f_1; // GO4K_FST AMOUNT(70),DEST(5*MAX_UNIT_SLOTS+2+FST_SET)\n this.vco6.frequency = this.notefreq - f_1; // GO4K_FST AMOUNT(70),DEST(6*MAX_UNIT_SLOTS+5+FST_SET)\n\n f_1 = this.vco5.next(); // GO4K_VCO TRANSPOSE(64),DETUNE(65),PHASE(64),GATES(85),COLOR(52),SHAPE(64),GAIN(64),FLAGS(TRISAW)\n let f_2:f32 = this.vco6.next(); // GO4K_VCO TRANSPOSE(64),DETUNE(63),PHASE(64),GATES(85),COLOR(52),SHAPE(64),GAIN(64),FLAGS(TRISAW)\n f_1 += f_2; // GO4K_FOP OP(FOP_ADDP)\n f_0 *= f_1; // GO4K_FOP OP(FOP_MULP)\n f_1 = f_0; // GO4K_PAN PANNING(64)\n this.signal.left = f_1;\n this.signal.right = f_0; // GO4K_OUT GAIN(0), AUXSEND(128)\n } \n}\n ","instruments/testinstrument.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { StereoSignal } from '../synth/stereosignal.class';\nimport { Envelope } from '../synth/envelope.class';\nimport { DelayLine } from '../fx/delayline';\nimport { notefreq } from '../synth/note';\n\nexport class TestInstrument {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.02, 0.2, 0.2, 0.2);\n readonly sineoscillator: SineOscillator = new SineOscillator();\n readonly sineoscillator2: SineOscillator = new SineOscillator();\n readonly delayline: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\n readonly delayline2: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\n readonly signal: StereoSignal = new StereoSignal();\n\n set note(note: f32) { \n if(note!==this.note && note > 1) { \n this.envelope.attack(); \n this.sineoscillator.frequency = notefreq(note);\n this.sineoscillator2.frequency = notefreq(note + 12);\n } else if(note===0) {\n this.envelope.release();\n }\n this._note = note;\n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear(); \n } else {\n let osc1 = env * this.sineoscillator.next();\n let osc2 = env * this.sineoscillator2.next();\n this.signal.left = osc1 * 0.8 + osc2 * 0.2;\n this.signal.right = osc1 * 0.2 + osc2 * 0.8;\n }\n } \n}\n ","math/fft.ts":"/**\n * Originally ported from http://rosettacode.org/wiki/Fast_Fourier_transform#C_sharp\n * \n * Optimized by reusing Complex objects instead of creating new, avoiding garbage collection\n * Precalculating of twiddles, making reuse of the FFT instance faster \n */ \n\n\nexport class Complex {\n re: f32 = 0;\n im: f32 = 0;\n \n public clone(b: Complex): void {\n this.re = b.re;\n this.im = b.im;\n }\n\n public add(b: Complex): void {\n this.re += b.re;\n this.im += b.im;\n }\n \n public sub(b: Complex): void {\n this.re -= b.re;\n this.im -= b.im;\n }\n \n public mult(b: Complex): void {\n const re: f32 = this.re;\n\n this.re = re * b.re - this.im * b.im;\n this.im = re * b.im + this.im * b.re;\n }\n\n public scale(n: f32): void {\n this.re *= n;\n this.im *= n;\n }\n\n public conjugate(): void {\n this.im = -this.im;\n }\n}\n\nfunction bitReverse(n: i32, bits: i32): i32 {\n let reversedN: i32 = n;\n let count: i32 = bits - 1;\n\n n >>= 1;\n while (n > 0) {\n reversedN = (reversedN << 1) | (n & 1);\n count--;\n n >>= 1;\n }\n\n return ((reversedN << count) & ((1 << bits) - 1));\n}\n \n/* Uses Cooley-Tukey iterative in-place algorithm with radix-2 DIT case\n * assumes no of points provided are a power of 2 */\nexport class FFT {\n buffer: StaticArray;\n bits: i32;\n exps: StaticArray;\n tmp: Complex = new Complex();\n\n /**\n * \n * @param buffersize_shift buffersize will be 2^buffersize_shift\n */\n constructor(buffersize_shift: i32) {\n const buffersize = 1 << buffersize_shift;\n const buffer = new StaticArray(buffersize);\n for (let n=0;n((\n buffersize as f32 *\n NativeMathf.log2(buffersize as f32)\n ) as i32);\n\n let expsIndex = 0;\n for (let N: i32 = 2; N <= buffer.length; N <<= 1) {\n for (let i: i32 = 0; i < buffer.length; i += N) {\n for (let k: i32 = 0; k < (N >> 1); k++) {\n const term: f32 = -2 * NativeMathf.PI * (k as f32) / (N as f32);\n const exp: Complex = new Complex();\n exp.re = NativeMathf.cos(term);\n exp.im = NativeMathf.sin(term);\n this.exps[expsIndex++] = exp;\n }\n }\n }\n }\n\n calculateInverse(): void {\n const N = this.buffer.length;\n const iN: f32 = 1 / (N as f32);\n\n for (let n=0;n> 1); k++) {\n const evenIndex = i + k;\n const oddIndex = i + k + (N >> 1);\n const even = buffer[evenIndex];\n const odd = buffer[oddIndex];\n const exp = this.tmp;\n exp.clone(this.exps[expsIndex++]);\n\n exp.mult(odd);\n\n odd.clone(even);\n even.add(exp);\n odd.sub(exp);\n }\n }\n }\n }\n}\n\nexport function createFFT(buffersize_shift: i32): usize {\n return changetype(new FFT(buffersize_shift));\n}\n\nexport function setComplex(instance: usize, arrayIndex: i32, re: f32, im: f32): void {\n const buffer = changetype(instance).buffer;\n buffer[arrayIndex].re = re;\n buffer[arrayIndex].im = im;\n}\n\nexport function getComplexRe(instance: usize, arrayIndex: i32): f32 {\n return changetype(instance).buffer[arrayIndex].re;\n}\n\nexport function getComplexIm(instance: usize, arrayIndex: i32): f32 {\n return changetype(instance).buffer[arrayIndex].im;\n}\n\nexport function calculateFFT(instance: usize): void {\n changetype(instance).calculate();\n}\n\nexport function calculateIFFT(instance: usize): void {\n changetype(instance).calculateInverse();\n}","math/sin.ts":"// By Max Graey ( https://github.com/petersalomonsen/javascriptmusic/issues/2#issuecomment-469419609 )\n\nexport const PI: f32 = 3.141592653589793;\nexport function sin(x: f32): f32 {\n var y: f32, z: f32;\n x *= 1 / PI;\n y = floor(x);\n z = x - y;\n z *= 1.0 - z;\n z *= 3.6 * z + 3.1;\n return select(-z, z, y & 1);\n}\n\nexport function cos(x: f32): f32 {\n return sin(x + PI * .5);\n}","midi/instruments/audioplayer.ts":"import { LoPassBiQuadFilter, MidiChannel, Q_BUTTERWORTH } from \"../../mixes/globalimports\";\nimport { Envelope } from \"../../synth/envelope.class\";\nimport { MidiVoice } from \"../midisynth\";\n\nconst CONTROL_FREQUENCY_CUTOFF = 74;\nconst MAX_CUTOFF_FREQUENCY: f32 = 20000;\nconst audioBuffers: Array> = new Array>();\n\nexport class AudioPlayerChannel extends MidiChannel {\n gain: f32 = 1.0;\n cutoff: f32 = MAX_CUTOFF_FREQUENCY;\n lopassleft: LoPassBiQuadFilter = new LoPassBiQuadFilter();\n lopassright: LoPassBiQuadFilter = new LoPassBiQuadFilter();\n\n controlchange(controller: u8, value: u8): void {\n super.controlchange(controller, value);\n switch (controller) {\n case CONTROL_FREQUENCY_CUTOFF:\n this.cutoff = value * MAX_CUTOFF_FREQUENCY / 127 as f32;\n this.lopassleft.update(this.cutoff, Q_BUTTERWORTH);\n this.lopassright.update(this.cutoff, Q_BUTTERWORTH);\n break;\n }\n }\n\n preprocess(): void {\n let left = this.signal.left;\n let right = this.signal.right;\n if (this.cutoff < MAX_CUTOFF_FREQUENCY) {\n left = this.lopassleft.process(left);\n right = this.lopassright.process(right);\n }\n left *= this.gain;\n right *= this.gain;\n\n this.signal.left = left;\n this.signal.right = right;\n }\n}\n\nexport class AudioPlayer extends MidiVoice {\n position: i32 = 0;\n velocityLevel: f32;\n\n constructor(channel: MidiChannel,\n private audioBufferPairNdx: i32,\n private startPosition: i32,\n noteNumber: u8,\n private env: Envelope = new Envelope(0.01, 0.0, 1.0, 0.01)\n ) {\n super(channel);\n this.minnote = noteNumber;\n this.maxnote = noteNumber;\n }\n\n noteon(note: u8, velocity: u8): void {\n super.noteon(note, velocity);\n this.velocityLevel = velocity as f32 / 127 as f32;\n this.position = this.startPosition;\n this.env.attack();\n }\n\n noteoff(): void {\n this.env.release();\n }\n\n isDone(): boolean {\n return audioBuffers.length == 0 || this.env.isDone();\n }\n\n nextframe(): void {\n const env = this.env.next();\n const vel = env * this.velocityLevel;\n\n let pos = this.position;\n const audioBufferNdx = this.audioBufferPairNdx << 1;\n const leftarr = audioBuffers[audioBufferNdx];\n const left = vel * leftarr[pos];\n const right = vel * audioBuffers[audioBufferNdx + 1][pos];\n pos++;\n if (pos == leftarr.length) {\n pos = 0;\n }\n this.position = pos;\n\n this.channel.signal.left += left;\n this.channel.signal.right += right;\n }\n}\n\nexport class MonoAudioPlayer {\n position: i32 = 0;\n\n constructor(private audioBufferNdx: i32) {\n\n }\n\n restart(): void {\n this.position = 0;\n }\n\n get audioBuffer(): StaticArray {\n return audioBuffers[this.audioBufferNdx];\n }\n\n nextframe(): f32 {\n return this.audioBuffer[(this.position++) % this.audioBuffer.length];\n }\n}\n\nexport function allocateAudioBuffer(frames: i32): usize {\n const buf = new StaticArray(frames);\n audioBuffers.push(buf);\n return changetype(buf);\n}","midi/instruments/defaultinstrument.ts":"import { Envelope } from \"../../synth/envelope.class\";\nimport { notefreq } from \"../../synth/note\";\nimport { SineOscillator } from \"../../synth/sineoscillator.class\";\nimport { MidiVoice } from \"../midisynth\";\n\nexport class DefaultInstrument extends MidiVoice {\n osc: SineOscillator = new SineOscillator();\n env: Envelope = new Envelope(0.01, 0.0, 1.0, 0.01);\n\n noteon(note: u8, velocity: u8): void {\n super.noteon(note, velocity);\n this.osc.frequency = notefreq(note);\n this.env.attack();\n }\n\n noteoff(): void {\n this.env.release();\n }\n\n isDone(): boolean {\n return this.env.isDone();\n }\n\n nextframe(): void {\n const signal = this.osc.next() * this.env.next() * this.velocity / 256;\n this.channel.signal.addMonoSignal(signal, 0.2, 0.5);\n }\n}","midi/midisynth.ts":"import { initializeMidiSynth, postprocess } from '../mixes/midi.mix';\nimport { StereoSignal, Freeverb } from '../mixes/globalimports';\nimport { midiLevelToGain } from '../synth/decibel';\n\nimport { Pan } from '../synth/pan.class';\nimport { DefaultInstrument } from './instruments/defaultinstrument';\n// export { allocateAudioBuffer } from './instruments/audioplayer';\n\nexport const MAX_ACTIVE_VOICES_SHIFT = 5; // up to 32 voices playing simultaneously\nexport const MAX_ACTIVE_VOICES = 1 << MAX_ACTIVE_VOICES_SHIFT;\n\nexport const midichannels = new StaticArray(16);\nexport const activeVoices = new StaticArray(MAX_ACTIVE_VOICES);\nconst activeVoicesStatusSnapshot = new StaticArray(MAX_ACTIVE_VOICES * 3);\n\nexport let numActiveVoices = 0;\nexport let voiceActivationCount = 0;\n\nexport const sampleBufferFrames = 128;\nexport const sampleBufferBytesPerChannel = sampleBufferFrames * 4;\nexport const sampleBufferChannels = 2;\nexport const samplebuffer = new StaticArray(sampleBufferFrames * sampleBufferChannels);\nconst bufferposstart = changetype(samplebuffer);\n\nconst CONTROL_SUSTAIN: u8 = 64;\nconst CONTROL_VOLUME: u8 = 7;\nconst CONTROL_PAN: u8 = 10;\nconst CONTROL_REVERB: u8 = 91;\n\nconst mainline = new StereoSignal();\nconst reverbline = new StereoSignal();\nexport const freeverb = new Freeverb();\nexport const outputline = new StereoSignal();\nexport class MidiChannel {\n controllerValues: StaticArray = new StaticArray(128);\n voices: StaticArray;\n sustainedVoices: StaticArray = new StaticArray(128);\n\n signal: StereoSignal = new StereoSignal();\n volume: f32 = midiLevelToGain(100);\n reverb: f32 = midiLevelToGain(7);\n pan: Pan = new Pan();\n voiceTransitionBuffer: StaticArray = new StaticArray(sampleBufferFrames * 2);\n\n constructor(numvoices: i32, factoryFunc: (channel: MidiChannel, voiceindex: i32) => MidiVoice) {\n this.voices = new StaticArray(numvoices);\n for (let n = 0; n < numvoices; n++) {\n this.voices[n] = factoryFunc(this, n);\n }\n\n }\n\n controlchange(controller: u8, value: u8): void {\n this.controllerValues[controller] = value;\n\n switch (controller) {\n case CONTROL_SUSTAIN:\n // sustain\n if (value < 64) {\n for (let n = 0; n < 128; n++) {\n if (this.sustainedVoices[n] != null) {\n (this.sustainedVoices[n] as MidiVoice).noteoff();\n this.sustainedVoices[n] = null;\n }\n }\n }\n break;\n case CONTROL_VOLUME:\n this.volume = midiLevelToGain(value);\n break;\n case CONTROL_REVERB:\n this.reverb = midiLevelToGain(value);\n break;\n case CONTROL_PAN:\n this.pan.setPan((value as f32) / 127.0);\n break;\n }\n }\n\n noteoff(note: u8): void {\n for (let n = 0; n < this.voices.length; n++) {\n const voice = this.voices[n];\n if (voice.note === note) {\n if (this.controllerValues[CONTROL_SUSTAIN] >= 64) {\n this.sustainedVoices[note] = voice;\n } else {\n voice.noteoff();\n }\n break;\n }\n }\n }\n\n removeFromSustainedVoices(voice: MidiVoice): void {\n this.sustainedVoices[voice.note] = null;\n }\n\n activateVoice(note: u8, channelNo: u8): MidiVoice | null {\n for (let n = 0; n < this.voices.length; n++) {\n const voice = this.voices[n];\n voice.channelNo = channelNo;\n if (voice.activeVoicesIndex > -1 && voice.note === note) {\n // Found already active voice for the given note\n voice.activationCount = voiceActivationCount++;\n // must remove from sustained voices\n this.removeFromSustainedVoices(voice);\n return voice;\n }\n }\n\n if (numActiveVoices === activeVoices.length) {\n return null;\n }\n\n let activeVoiceIndex: i32 = numActiveVoices;\n\n for (let n = 0; n < this.voices.length; n++) {\n const voice = this.voices[n];\n if (voice.activeVoicesIndex === -1 &&\n note >= voice.minnote &&\n note <= voice.maxnote) {\n const availableVoice = voice as MidiVoice;\n activeVoices[activeVoiceIndex] = availableVoice;\n availableVoice.activeVoicesIndex = activeVoiceIndex;\n numActiveVoices++;\n availableVoice.activationCount = voiceActivationCount++;\n return availableVoice;\n }\n }\n\n // no available voices for the current channel, we'll pick the oldest\n let oldestVoice: MidiVoice | null = null;\n for (let n = 0; n < this.voices.length; n++) {\n const voice = this.voices[n];\n if (\n (oldestVoice === null ||\n voice.activationCount <= (oldestVoice as MidiVoice).activationCount) &&\n note >= voice.minnote &&\n note <= voice.maxnote) {\n oldestVoice = voice;\n }\n }\n if (oldestVoice !== null) {\n const voice = (oldestVoice as MidiVoice);\n for (let n = 0; n < sampleBufferFrames; n++) {\n voice.nextframe();\n const fact: f32 = ((sampleBufferFrames as f32) - (n as f32)) / (sampleBufferFrames as f32);\n this.voiceTransitionBuffer[n << 1] += this.signal.left * fact;\n this.voiceTransitionBuffer[(n << 1) + 1] += this.signal.right * fact;\n this.signal.clear();\n }\n voice.activationCount = voiceActivationCount++;\n this.removeFromSustainedVoices(voice);\n }\n return oldestVoice;\n }\n\n /**\n * Process channel signal before sending to outputs\n */\n preprocess(): void {\n\n }\n}\n\nexport abstract class MidiVoice {\n channel: MidiChannel;\n channelNo: u8;\n note: u8;\n velocity: u8;\n activeVoicesIndex: i32 = -1;\n activationCount: i32;\n minnote: u8 = 0;\n maxnote: u8 = 127;\n\n constructor(channel: MidiChannel) {\n this.channel = channel;\n }\n\n /**\n * If you override this (e.g. to trigger attacks on envelopes), make sure you call super.noteon\n * @param note \n * @param velocity \n */\n noteon(note: u8, velocity: u8): void {\n this.note = note;\n this.velocity = velocity;\n }\n\n /**\n * Override this to e.g. trigger releases on envelopes\n */\n noteoff(): void {\n this.velocity = 0;\n }\n\n /**\n * This will be called repeatedly as long as the voice is active\n * \n * Override it to add checks for e.g. envelope to be fully released\n */\n isDone(): boolean {\n return this.velocity === 0;\n }\n\n deactivate(): void {\n activeVoices[this.activeVoicesIndex] = null;\n this.activeVoicesIndex = -1;\n }\n\n /**\n * Will be called for rendering an audio frame\n */\n abstract nextframe(): void;\n}\n\nexport function shortmessage(val1: u8, val2: u8, val3: u8): void {\n const channel = val1 & 0xf;\n const command = val1 & 0xf0;\n\n if (command === 0x90 && val3 > 0) {\n const activatedVoice = midichannels[channel].activateVoice(val2, channel);\n if (activatedVoice !== null) {\n const voice = activatedVoice as MidiVoice;\n voice.noteon(val2, val3);\n }\n } else if (\n (command === 0x80 ||\n (command === 0x90 && val3 === 0)) // \n ) {\n // note off\n midichannels[channel].noteoff(val2);\n } else if (command === 0xb0) {\n // control change\n midichannels[channel].controlchange(val2, val3);\n }\n}\n\nexport function getActiveVoicesStatusSnapshot(): usize {\n for (let n = 0; n < activeVoices.length; n++) {\n const activeVoicesStatusSnapshotIndex = n * 3;\n if (activeVoices[n] != null) {\n const voice = (activeVoices[n] as MidiVoice);\n activeVoicesStatusSnapshot[activeVoicesStatusSnapshotIndex] = voice.channelNo;\n activeVoicesStatusSnapshot[activeVoicesStatusSnapshotIndex + 1] = voice.note;\n activeVoicesStatusSnapshot[activeVoicesStatusSnapshotIndex + 2] = voice.velocity;\n } else {\n activeVoicesStatusSnapshot[activeVoicesStatusSnapshotIndex] = 0;\n activeVoicesStatusSnapshot[activeVoicesStatusSnapshotIndex + 1] = 0;\n activeVoicesStatusSnapshot[activeVoicesStatusSnapshotIndex + 2] = 0;\n }\n }\n return changetype(activeVoicesStatusSnapshot);\n}\n\nexport function allNotesOff(): void {\n for (let n = 0; n < numActiveVoices; n++) {\n const voice = activeVoices[n] as MidiVoice;\n voice.noteoff();\n }\n}\n\nexport function cleanupInactiveVoices(): void {\n for (let n = 0; n < numActiveVoices; n++) {\n const voice = activeVoices[n] as MidiVoice;\n if (voice.isDone()) {\n voice.deactivate();\n for (let r = n + 1; r < numActiveVoices; r++) {\n const nextVoice = activeVoices[r] as MidiVoice;\n nextVoice.activeVoicesIndex--;\n activeVoices[r - 1] = nextVoice;\n activeVoices[r] = null;\n }\n numActiveVoices--;\n n--;\n }\n }\n}\n\nexport function playActiveVoices(): void {\n for (let n = 0; n < numActiveVoices; n++) {\n (activeVoices[n] as MidiVoice).nextframe();\n }\n}\n\nexport function fillSampleBuffer(): void {\n fillSampleBufferWithNumSamples(sampleBufferFrames);\n}\n\nexport function fillSampleBufferWithNumSamples(numSamples: i32): void {\n const bufferposend = changetype(samplebuffer) + 4 * numSamples;\n\n cleanupInactiveVoices();\n\n let voiceTransitionBufferNdx = 0;\n\n for (let bufferpos = bufferposstart; bufferpos < bufferposend; bufferpos += 4) {\n playActiveVoices();\n\n for (let ch = 0; ch < 16; ch++) {\n const midichannel = midichannels[ch];\n const channelsignal = midichannel.signal;\n\n channelsignal.left += midichannel.voiceTransitionBuffer[voiceTransitionBufferNdx];\n midichannel.voiceTransitionBuffer[voiceTransitionBufferNdx] = 0;\n channelsignal.right += midichannel.voiceTransitionBuffer[voiceTransitionBufferNdx + 1];\n midichannel.voiceTransitionBuffer[voiceTransitionBufferNdx + 1] = 0;\n\n midichannel.preprocess();\n\n channelsignal.left *= midichannel.pan.leftLevel * midichannel.volume;\n channelsignal.right *= midichannel.pan.rightLevel * midichannel.volume;\n\n const reverb = midichannel.reverb;\n\n mainline.add(channelsignal.left, channelsignal.right);\n reverbline.add(channelsignal.left * reverb, channelsignal.right * reverb);\n midichannel.signal.clear();\n }\n\n freeverb.tick(reverbline);\n\n outputline.add(\n mainline.left + reverbline.left,\n mainline.right + reverbline.right\n );\n\n postprocess();\n\n store(bufferpos, outputline.left);\n store(bufferpos + sampleBufferBytesPerChannel, outputline.right);\n\n mainline.clear();\n reverbline.clear();\n outputline.clear();\n voiceTransitionBufferNdx += 2;\n }\n}\n\nconst defaultMidiChannel = new MidiChannel(1, (channel: MidiChannel) => new DefaultInstrument(channel));\n\nfor (let ch = 0; ch < 16; ch++) {\n midichannels[ch] = defaultMidiChannel;\n}\n\ninitializeMidiSynth();\n\n","midi/sequencer/midiparts.ts":"import { MidiSequencerPart, MidiSequencerPartSchedule } from \"./midisequencerpart\";\n\nexport const midiparts: MidiSequencerPart[] = new Array();\nexport const midipartschedule: MidiSequencerPartSchedule[] = new Array();\n","midi/sequencer/midisequencer.ts":"import { SAMPLERATE } from \"../../environment\";\nimport { midiparts, midipartschedule } from \"./midiparts\";\nimport { fillSampleBuffer, sampleBufferFrames } from \"../midisynth\";\n\nconst PLAY_EVENT_INTERVAL = ((sampleBufferFrames * 1000) as f64 / SAMPLERATE);\n\nexport let currentTimeMillis: f64 = 0;\n\nexport function seek(time: i32): void {\n currentTimeMillis = time as f64;\n\n for (let ndx = 0;\n ndx < midipartschedule.length;\n ndx++) {\n const scheduleEntry = midipartschedule[ndx];\n const midiSequencerPart = midiparts[scheduleEntry.midipartindex];\n if (scheduleEntry.endTime >= currentTimeMillis && scheduleEntry.startTime <= currentTimeMillis) {\n midiSequencerPart.seek(Math.round(currentTimeMillis) as i32 - scheduleEntry.startTime);\n } else {\n midiSequencerPart.seek(0);\n }\n }\n}\n\nexport function playMidiPartEvents(): void {\n for (let ndx = 0;\n ndx < midipartschedule.length;\n ndx++) {\n const scheduleEntry = midipartschedule[ndx]; \n if (scheduleEntry.startTime > currentTimeMillis) {\n break;\n }\n const midiSequencerPart = midiparts[scheduleEntry.midipartindex];\n if (currentTimeMillis <= (scheduleEntry.endTime + PLAY_EVENT_INTERVAL)) {\n midiSequencerPart.playEvents(Math.round(currentTimeMillis) as i32 - scheduleEntry.startTime);\n }\n }\n}\n\nexport function playEventsAndFillSampleBuffer(): void {\n playMidiPartEvents();\n fillSampleBuffer();\n currentTimeMillis += PLAY_EVENT_INTERVAL;\n}\n\nexport function setMidiPartSchedule(ndx: i32, midipartindex: i32, startTime: i32): void {\n midipartschedule[ndx].updateEndTime(midipartindex, startTime);\n}\n","midi/sequencer/midisequencerpart.ts":"import { midiparts, midipartschedule } from \"./midiparts\";\nimport { shortmessage } from \"../midisynth\";\n\nexport class MidiSequencerPart {\n currentEventTime: i32 = 0;\n currentEventIndex: i32 = 0;\n previousTargetTime: i32 = 0;\n lastEventTime: i32 = 0;\n\n constructor(public eventlist: u8[]) {\n let lastEventTime = 0;\n for (let ndx = 0; ndx < this.eventlist.length;ndx += 3) {\n let deltaTime: i32 = 0;\n let deltaTimePart: u8;\n\n let shiftamount: u8 = 0;\n do {\n deltaTimePart = this.eventlist[ndx++];\n deltaTime += (((deltaTimePart & 0x7f) as i32) << shiftamount);\n shiftamount += 7;\n } while (deltaTimePart & 0x80);\n\n lastEventTime = lastEventTime + deltaTime;\n }\n this.lastEventTime = lastEventTime;\n }\n\n playEvents(targetTime: i32): void {\n if (targetTime < this.previousTargetTime) {\n this.currentEventTime = 0;\n this.currentEventIndex = 0;\n }\n this.previousTargetTime = targetTime;\n let ndx = this.currentEventIndex;\n\n while (ndx < this.eventlist.length) {\n let deltaTime: i32 = 0;\n let deltaTimePart: u8;\n\n let shiftamount: u8 = 0;\n do {\n deltaTimePart = this.eventlist[ndx++];\n deltaTime += (((deltaTimePart & 0x7f) as i32) << shiftamount);\n shiftamount += 7;\n } while (deltaTimePart & 0x80);\n\n const newTime = this.currentEventTime + deltaTime;\n\n if (newTime <= targetTime) {\n shortmessage(this.eventlist[ndx++], this.eventlist[ndx++], this.eventlist[ndx++]);\n\n this.currentEventTime = newTime;\n this.currentEventIndex = ndx;\n } else {\n break;\n }\n }\n }\n\n seek(targetTime: i32): void {\n this.currentEventIndex = 0;\n this.currentEventTime = 0;\n let ndx = this.currentEventIndex;\n\n while (ndx < this.eventlist.length) {\n let deltaTime: i32 = 0;\n let deltaTimePart: u8;\n\n let shiftamount: u8 = 0;\n do {\n deltaTimePart = this.eventlist[ndx++];\n deltaTime += ((deltaTimePart & 0x7f) << shiftamount);\n shiftamount += 7;\n } while (deltaTimePart & 0x80);\n\n const newTime = this.currentEventTime + deltaTime;\n\n if (newTime < targetTime) {\n ndx += 3;\n this.currentEventTime = newTime;\n this.currentEventIndex = ndx;\n } else if (newTime === targetTime) {\n this.currentEventTime = newTime;\n } else {\n break;\n }\n }\n }\n}\n\nexport class MidiSequencerPartSchedule {\n public endTime: i32\n\n constructor(\n public midipartindex: i32,\n public startTime: i32) {\n this.endTime = midiparts[midipartindex].lastEventTime + startTime;\n }\n\n updateEndTime(midipartindex: i32, startTime: i32): void {\n this.startTime = startTime;\n this.midipartindex = midipartindex;\n this.endTime = midiparts[midipartindex].lastEventTime + startTime;\n }\n}\n","mixes/empty.mix.ts":"import { Kick2, SawBass, Instrument,\n StereoSignal,\n Freeverb } from \"./globalimports\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst kick = new Kick2();\nconst sawbass = new SawBass();\n\nexport function setChannelValue(channel: usize, value: f32): void {\n ([kick, sawbass] as Instrument[])[channel].note = value;\n}\n\nconst mainline = new StereoSignal();\nconst reverbline = new StereoSignal();\nconst freeverb = new Freeverb();\n\n@inline\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear();\n reverbline.clear();\n\n kick.next();\n mainline.addStereoSignal(kick.signal, 0.5, 0.5);\n\n sawbass.next();\n mainline.addStereoSignal(sawbass.signal, 0.5, 0.5);\n reverbline.addStereoSignal(sawbass.signal, 0.1, 0.5);\n\n freeverb.tick(reverbline);\n\n store(leftSampleBufferPtr, mainline.left + reverbline.left);\n store(rightSampleBufferPtr, mainline.right + reverbline.right); \n}","mixes/globalimports.ts":"export { createInstrumentArray } from '../common/mixcommon';\nexport { AllPass } from '../fx/allpass';\nexport { AllPassFloat } from '../fx/allpass';\nexport { BandPass } from '../fx/bandpass';\nexport { Comb } from '../fx/comb';\nexport { DelayLine } from '../fx/delayline';\nexport { DelayLineFloat } from '../fx/delayline';\nexport { EQBand } from '../fx/eqband';\nexport { Freeverb } from '../fx/freeverb';\nexport { Limiter } from '../fx/limiter';\nexport { MidSideProcessor } from '../fx/midsideprocessor';\nexport { MonoCompressor } from '../fx/monocompressor';\nexport { StereoCompressor } from '../fx/monocompressor';\nexport { MultiBandEQ } from '../fx/multibandeq';\nexport { StereoCompressor } from '../fx/stereocompressor';\nexport { TriBandEQ } from '../fx/tribandeq';\nexport { TriBandStereoCompressor } from '../fx/tribandstereocompressor';\nexport { DeepBass } from '../instruments/bass/deepbass';\nexport { SawBass2 } from '../instruments/bass/sawbass2.class';\nexport { SawBass3 } from '../instruments/bass/sawbass3';\nexport { DriveLead } from '../instruments/drivelead.class';\nexport { Kick2 } from '../instruments/drums/kick2.class';\nexport { Rimshot } from '../instruments/drums/rimshot.class';\nexport { Snare2 } from '../instruments/drums/snare2.class';\nexport { Hihat } from '../instruments/hihat.class';\nexport { Instrument } from '../instruments/instrument.class';\nexport { Kick } from '../instruments/kick.class';\nexport { BrassyLead } from '../instruments/lead/brassy';\nexport { Eftang } from '../instruments/lead/eftang';\nexport { SineLead } from '../instruments/lead/sinelead';\nexport { FlatPad } from '../instruments/pad/flatpad.class';\nexport { SoftPad } from '../instruments/pad/softpad.class';\nexport { Pad } from '../instruments/pad.class';\nexport { SubPiano } from '../instruments/piano/subpiano';\nexport { SawBass } from '../instruments/sawbass.class';\nexport { Snare } from '../instruments/snare.class';\nexport { SquareLead } from '../instruments/squarelead.class';\nexport { Test4KlangString } from '../instruments/string1.class';\nexport { TestInstrument } from '../instruments/testinstrument.class';\nexport { Complex } from '../math/fft';\nexport { FFT } from '../math/fft';\nexport { createFFT } from '../math/fft';\nexport { setComplex } from '../math/fft';\nexport { getComplexRe } from '../math/fft';\nexport { getComplexIm } from '../math/fft';\nexport { calculateFFT } from '../math/fft';\nexport { calculateIFFT } from '../math/fft';\nexport { PI } from '../math/sin';\nexport { sin } from '../math/sin';\nexport { cos } from '../math/sin';\nexport { AudioPlayerChannel } from '../midi/instruments/audioplayer';\nexport { AudioPlayer } from '../midi/instruments/audioplayer';\nexport { MonoAudioPlayer } from '../midi/instruments/audioplayer';\nexport { allocateAudioBuffer } from '../midi/instruments/audioplayer';\nexport { DefaultInstrument } from '../midi/instruments/defaultinstrument';\nexport { MAX_ACTIVE_VOICES_SHIFT } from '../midi/midisynth';\nexport { MAX_ACTIVE_VOICES } from '../midi/midisynth';\nexport { midichannels } from '../midi/midisynth';\nexport { activeVoices } from '../midi/midisynth';\nexport { numActiveVoices } from '../midi/midisynth';\nexport { voiceActivationCount } from '../midi/midisynth';\nexport { sampleBufferFrames } from '../midi/midisynth';\nexport { sampleBufferBytesPerChannel } from '../midi/midisynth';\nexport { sampleBufferChannels } from '../midi/midisynth';\nexport { samplebuffer } from '../midi/midisynth';\nexport { freeverb } from '../midi/midisynth';\nexport { outputline } from '../midi/midisynth';\nexport { MidiChannel } from '../midi/midisynth';\nexport { MidiVoice } from '../midi/midisynth';\nexport { shortmessage } from '../midi/midisynth';\nexport { getActiveVoicesStatusSnapshot } from '../midi/midisynth';\nexport { allNotesOff } from '../midi/midisynth';\nexport { cleanupInactiveVoices } from '../midi/midisynth';\nexport { playActiveVoices } from '../midi/midisynth';\nexport { fillSampleBuffer } from '../midi/midisynth';\nexport { fillSampleBufferWithNumSamples } from '../midi/midisynth';\nexport { Q_BUTTERWORTH } from '../synth/biquad';\nexport { FilterType } from '../synth/biquad';\nexport { Coefficients } from '../synth/biquad';\nexport { BiQuadFilter } from '../synth/biquad';\nexport { LoPassBiQuadFilter } from '../synth/biquad';\nexport { HiPassBiQuadFilter } from '../synth/biquad';\nexport { beatToFrame } from '../synth/bpm';\nexport { softclip } from '../synth/clip';\nexport { hardclip } from '../synth/clip';\nexport { decibelToGain } from '../synth/decibel';\nexport { midiLevelToDecibel } from '../synth/decibel';\nexport { midiLevelToGain } from '../synth/decibel';\nexport { EnvelopeState } from '../synth/envelope.class';\nexport { Envelope } from '../synth/envelope.class';\nexport { IFFTOscillator } from '../synth/ifftoscillator.class';\nexport { Noise } from '../synth/noise.class';\nexport { notefreq } from '../synth/note';\nexport { Pan } from '../synth/pan.class';\nexport { SawOscillator } from '../synth/sawoscillator.class';\nexport { WaveShaper } from '../synth/shaper';\nexport { SineOscillator } from '../synth/sineoscillator.class';\nexport { SquareOscillator } from '../synth/squareoscillator.class';\nexport { StereoSignal } from '../synth/stereosignal.class';\nexport { TriangleOscillator } from '../synth/triangleoscillator.class';\nexport { noise } from '../synth/waveguide';\nexport { WaveGuide } from '../synth/waveguide';\nexport { AuxExciterWaveGuide } from '../synth/waveguide';\nexport { AudioExciterWaveGuide } from '../synth/waveguide';\nexport { CustomExciterWaveGuide } from '../synth/waveguide';","mixes/goodtimes.mix.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nimport { Freeverb } from \"../fx/freeverb\";\nimport { TestInstrument } from \"../instruments/testinstrument.class\";\n\nimport { Pad } from \"../instruments/pad.class\";\nimport { Kick2 } from \"../instruments/drums/kick2.class\";\nimport { Rimshot } from \"../instruments/drums/rimshot.class\";\nimport { DriveLead } from \"../instruments/drivelead.class\";\n\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\nimport { SquareLead } from \"../instruments/squarelead.class\";\n\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\nimport { EQBand } from \"../fx/eqband\";\nimport { SawBass2 } from \"../instruments/bass/sawbass2.class\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst gain: f32 = 0.2;\nconst ENABLE_MULTIBAND_COMPRESSOR = false;\n\nlet flute = new TestInstrument();\nlet drivelead = new DriveLead();\nlet bass = new SawBass2();\nlet pad1 = new Pad();\nlet pad2 = new Pad();\nlet pad3 = new Pad();\nlet kick = new Kick2();\nlet rimshot = new Rimshot();\nlet hihat = new Hihat();\nlet squarelead = new SquareLead();\n\nlet freeverb = new Freeverb();\n\nlet delayLeft: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\nlet delayRight: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\n \nlet echoline = new StereoSignal();\nlet reverbline = new StereoSignal();\nlet mainline = new StereoSignal();\n\nlet tribandstereocompressor = new TriBandStereoCompressor(20,500,7000,19500);\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(channel) {\n case 0:\n flute.note = value;\n break;\n case 1:\n bass.note = value;\n break;\n case 2:\n pad1.note = value;\n break;\n case 3:\n pad2.note = value;\n break;\n case 4:\n pad3.note = value;\n break;\n case 5:\n kick.note = value;\n break;\n case 6:\n rimshot.note = value;\n break;\n case 7:\n drivelead.note = value;\n break;\n case 8:\n hihat.note = value;\n break;\n case 9:\n squarelead.note = value;\n break;\n }\n \n}\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear()\n reverbline.clear();\n echoline.clear();\n \n flute.next();\n pad1.next(); \n pad2.next();\n pad3.next(); \n kick.next();\n rimshot.next();\n hihat.next();\n bass.next(); \n drivelead.next();\n squarelead.next();\n\n mainline.addStereoSignal(flute.signal, 0.6, 0.0);\n echoline.addStereoSignal(flute.signal, 0.5, 1.0);\n \n mainline.addStereoSignal(pad1.signal, 0.5, 0.25);\n echoline.addStereoSignal(pad1.signal, 0.3, 0.25); \n mainline.addStereoSignal(pad2.signal, 0.5, 0.5);\n echoline.addStereoSignal(pad2.signal, 0.25, 0.5);\n mainline.addStereoSignal(pad3.signal, 0.5, 0.75);\n echoline.addStereoSignal(pad3.signal, 0.25, 0.75);\n\n mainline.addStereoSignal(kick.signal, 1.7, 0.5);\n reverbline.addStereoSignal(kick.signal, 0.08, 0.0);\n \n mainline.addStereoSignal(rimshot.signal, 0.75, 0.6);\n reverbline.addStereoSignal(rimshot.signal, 0.20, 0.4);\n \n mainline.addStereoSignal(hihat.signal, 1.0, 0.4);\n reverbline.addStereoSignal(hihat.signal, 0.2, 0.6);\n\n mainline.addStereoSignal(bass.signal, 0.6, 0.5);\n reverbline.addStereoSignal(bass.signal, 0.07, 0.0);\n\n mainline.addStereoSignal(drivelead.signal, 0.17, 0.4);\n echoline.addStereoSignal(drivelead.signal, 0.4, 0.6);\n\n mainline.addStereoSignal(squarelead.signal,0.6, 0.6);\n echoline.addStereoSignal(squarelead.signal, 0.6, 0.0);\n\n echoline.left += delayRight.read() * 0.5;\n echoline.right += delayLeft.read() * 0.5;\n \n delayLeft.write_and_advance(echoline.left);\n delayRight.write_and_advance(echoline.right);\n\n reverbline.addStereoSignal(echoline, 0.5, 0.5);\n \n freeverb.tick(reverbline);\n \n let left = gain * (mainline.left + echoline.left + reverbline.left);\n let right = gain * (mainline.right + echoline.right + reverbline.right);\n\n if (ENABLE_MULTIBAND_COMPRESSOR) {\n tribandstereocompressor.process(left,right,0.45, 1.0, 0.9 , 1.3, 1.05, 1.0);\n left = tribandstereocompressor.stereosignal.left;\n right = tribandstereocompressor.stereosignal.right;\n } else {\n left = eqbandl.process(left);\n right = eqbandr.process(right);\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/midi.mix.ts":"import { midichannels, MidiChannel, MidiVoice, SineOscillator, Envelope, notefreq } from './globalimports';\nimport { outputline } from '../midi/midisynth';\nimport { hardclip } from '../synth/clip';\n\nclass SimpleSine extends MidiVoice {\n osc: SineOscillator = new SineOscillator();\n env: Envelope = new Envelope(0.1, 0.0, 1.0, 0.1);\n\n noteon(note: u8, velocity: u8): void {\n super.noteon(note, velocity);\n this.osc.frequency = notefreq(note);\n this.env.attack();\n }\n\n noteoff(): void {\n this.env.release();\n }\n\n isDone(): boolean {\n return this.env.isDone();\n }\n\n nextframe(): void {\n const signal = this.osc.next() * this.env.next() * this.velocity / 256;\n this.channel.signal.addMonoSignal(signal, 0.2, 0.7);\n }\n}\n\nexport function initializeMidiSynth(): void {\n midichannels[0] = new MidiChannel(6, (channel: MidiChannel) => new SimpleSine(channel));\n}\n\nexport function postprocess(): void {\n outputline.left = hardclip(outputline.left);\n outputline.right = hardclip(outputline.right);\n}","mixes/newyear.mix.ts":"/**\n * Mix for \"WASM song\"\n */\nimport { EQBand } from \"../fx/eqband\";\nimport { Envelope } from '../synth/envelope.class';\nimport { Snare } from \"../instruments/snare.class\";\nimport { SawBass3 } from \"../instruments/bass/sawbass3\";\nimport { Eftang } from \"../instruments/lead/eftang\";\nimport { StereoSignal } from \"../synth/stereosignal.class\";\nimport { Kick } from \"../instruments/kick.class\";\nimport { BrassyLead } from \"../instruments/lead/brassy\";\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { WaveShaper } from '../synth/shaper';\nimport { createInstrumentArray } from '../common/mixcommon';\nimport { Freeverb } from \"../fx/freeverb\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\nimport { BiQuadFilter, FilterType, Q_BUTTERWORTH } from '../synth/biquad';\nimport { notefreq } from '../synth/note';\nimport { SineOscillator } from '../synth/sineoscillator.class';\nimport { SawOscillator } from '../synth/sawoscillator.class';\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst tribandstereocompressor = new TriBandStereoCompressor(0.05, 25,150,1500,20000);\nconst ENABLE_MULTIBAND_COMPRESSOR = true;\n\nconst gain: f32 = 0.5;\n\nconst bass = new SawBass3();\nconst lead = new Eftang();\nconst kick = new Kick();\nconst snare = new Snare();\nconst hihat = new Hihat();\n\n\nexport class FlatPad {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.01, 0.1, 1.0, 0.1);\n readonly filterenvelope: Envelope = new Envelope(0.001, 1.0, 1.0, 0.1);\n readonly hipassfilterenvelope: Envelope = new Envelope(0.02, 3, 0.2, 2.0);\n readonly sawoscillator: SawOscillator = new SawOscillator();\n readonly sawoscillator2: SawOscillator = new SawOscillator();\n readonly sawoscillator3: SawOscillator = new SawOscillator();\n readonly sawoscillator4: SawOscillator = new SawOscillator();\n readonly sawoscillator5: SawOscillator = new SawOscillator();\n readonly lfo: SineOscillator = new SineOscillator();\n \n readonly filterl: BiQuadFilter = new BiQuadFilter();\n readonly filterr: BiQuadFilter = new BiQuadFilter();\n readonly signal: StereoSignal = new StereoSignal();\n \n set note(note: f32) { \n if(note > 1) { \n this.lfo.frequency = 1;\n this.lfo.position = 0;\n this.sawoscillator.frequency = notefreq(note);\n this.sawoscillator2.frequency = notefreq(note + 0.03);\n this.sawoscillator3.frequency = notefreq(note - 0.03);\n this.sawoscillator4.frequency = notefreq(note + 0.06);\n this.sawoscillator5.frequency = notefreq(note - 0.06);\n \n this.envelope.attack(); \n this.filterenvelope.attack(); \n this.hipassfilterenvelope.attack(); \n this._note = note; \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n this.hipassfilterenvelope.release(); \n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env === 0) {\n this.signal.clear();\n return;\n \n }\n\n const lfo: f32 = this.lfo.next();\n\n const note = this.note;\n if(note<2) {\n return;\n }\n this.sawoscillator2.frequency = notefreq(note + 0.05 + (0.02 * lfo));\n this.sawoscillator3.frequency = notefreq(note - 0.05 - (0.02 * lfo));\n this.sawoscillator4.frequency = notefreq(note + 0.1 + (0.03 * lfo));\n this.sawoscillator5.frequency = notefreq(note - 0.1 - (0.03 * lfo));\n \n \n let osc: f32 = this.sawoscillator.next();\n let osc2: f32 = this.sawoscillator2.next();\n let osc3: f32 = this.sawoscillator3.next();\n let osc4: f32 = this.sawoscillator4.next();\n let osc5: f32 = this.sawoscillator5.next();\n \n let left = env * (osc + osc2 + osc5);\n let right = env * (osc + osc3 + osc4 );\n\n const filterlfo: f32 = (lfo * 0.9) + 1;\n this.filterl.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 10000 + 20 * (127 - this.note), Q_BUTTERWORTH);\n \n this.filterr.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 200 + this.filterenvelope.next() * filterlfo * 10000 + 20 * (this.note), Q_BUTTERWORTH);\n \n this.signal.left = this.filterl.process(left );\n this.signal.right = this.filterr.process(right );\n } \n}\n \nconst pads: FlatPad[] = createInstrumentArray(10, () => new FlatPad());\nlet padsVolume: f32 = 1.0;\n\nclass SineLead {\n private _note: f32;\n \n readonly osc: SineOscillator = new SineOscillator();\n readonly env1: Envelope = new Envelope(0.02, 0.15, 0.5, 0.3); \n readonly signal: StereoSignal = new StereoSignal();\n\n\n set note(note: f32) { \n if(note > 1) { \n this.osc.frequency = notefreq(note);\n this._note = note;\n this.env1.attack(); \n } else {\n this.env1.release(); \n } \n }\n\n get note(): f32 {\n return this._note;\n }\n\n next(): void { \n const env1: f32 = this.env1.next();\n \n let osc: f32 = this.osc.next(); \n osc *= env1;\n\n const pan = this._note / 127;\n\n this.signal.left = osc * pan;\n this.signal.right = osc * (1 - pan); \n } \n}\n\nexport class DriveLead {\n private _note: f32;\n readonly envelope: Envelope = new Envelope(0.03, 1.0, 0.6, 0.2);\n readonly sawoscillatorl: SawOscillator = new SawOscillator();\n readonly sawoscillatorr: SawOscillator = new SawOscillator();\n readonly shaper: WaveShaper = new WaveShaper();\n readonly signal: StereoSignal = new StereoSignal();\n readonly lfoenvelope: Envelope = new Envelope(1.0, 0, 1.0, 0.1);\n readonly lfo: SineOscillator = new SineOscillator();\n private baseFrequency : f32;\n private pitchbend: f32 = 0;\n\n set note(note: f32) { \n if(note > 1) { \n this.shaper.drive = 0.5; \n this.baseFrequency = notefreq(note + this.pitchbend);\n this.lfo.frequency = 8;\n this.envelope.attack(); \n this.lfoenvelope.attack(); \n this._note = note;\n } else {\n this.envelope.release();\n this.lfoenvelope.release();\n }\n \n }\n\n get note(): f32 {\n return this._note;\n }\n\n setPitchbend(bend: f32): void {\n \tthis.pitchbend = bend;\n \tthis.baseFrequency = notefreq(this._note + bend); \t\n }\n\n next(): void { \n let env: f32 = this.envelope.next();\n if(env===0) {\n this.signal.clear();\n return;\n } \n \n let lfo: f32 = this.lfo.next() * 3 * this.lfoenvelope.next();\n this.sawoscillatorl.frequency = this.baseFrequency + lfo + 0.5;\n this.sawoscillatorr.frequency = this.baseFrequency + lfo - 0.5;\n \n let left = env* this.sawoscillatorl.next() + this.signal.right * 0.5;\n left = this.shaper.process(left);\n \n let right = env* this.sawoscillatorr.next() + this.signal.left * 0.5;\n right = this.shaper.process(right);\n \n this.signal.left = left * 0.5 + right;\n this.signal.right = right * 0.5 + left; \n } \n}\n\nconst sinelead = new SineLead();\nconst drivelead = new DriveLead();\n\nexport function setChannelValue(channel: usize, value: f32): void {\n const setChannelValueFunctions: usize[] = [\n changetype((value:f32): void => {bass.note = value;}),\n changetype((value:f32): void => {lead.note = value;}),\n changetype((value:f32): void => {sinelead.note = value;}),\n changetype((value:f32): void => {kick.note = value;}),\n changetype((value:f32): void => {snare.note = value;}),\n changetype((value:f32): void => {hihat.note = value;}),\n changetype((value:f32): void => {pads[0].note = value;}),\n changetype((value:f32): void => {pads[1].note = value;}),\n changetype((value:f32): void => {pads[2].note = value;}),\n changetype((value:f32): void => {pads[3].note = value;}), \n changetype((value:f32): void => {pads[4].note = value;}), \n changetype((value:f32): void => {pads[5].note = value;}),\n changetype((value:f32): void => {pads[6].note = value;}),\n changetype((value:f32): void => {pads[7].note = value;}),\n changetype((value:f32): void => {pads[8].note = value;}),\n changetype((value:f32): void => {pads[9].note = value;}),\n changetype((value:f32): void => {\n if(value > 0) {\n\t padsVolume = value / 100.0;\n }\n }),\n changetype((value:f32): void => {drivelead.note = value;}),\n changetype((value:f32): void => {\n if(value > 0) {\n\t drivelead.setPitchbend((value - 64) / 32);\n }\n })\n \n ];\n\n changetype<(val: f32) => void>(setChannelValueFunctions[channel])(value);\n}\n\n\nconst mainline = new StereoSignal();\nconst reverbline = new StereoSignal();\nconst freeverb = new Freeverb();\n\nconst delayframes = (SAMPLERATE * (6/8) * 60 / 120) as usize;\nlet delayLeft: DelayLine = new DelayLine(delayframes);\nlet delayRight: DelayLine = new DelayLine(delayframes);\n \nlet echoline = new StereoSignal();\n\n\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n let left: f32 = 0;\n let right: f32 = 0;\n\n mainline.clear();\n reverbline.clear();\n echoline.clear();\n\n bass.next();\n mainline.addStereoSignal(bass.signal, 1.0, 0.5);\n reverbline.addStereoSignal(bass.signal, 0.0, 0.5);\n\n lead.next();\n mainline.addStereoSignal(lead.signal, 0.8, 0.5);\n echoline.addStereoSignal(lead.signal, 0.8, 0.5);\n\n \tdrivelead.next();\n mainline.addStereoSignal(drivelead.signal, 0.1, 0.5);\n echoline.addStereoSignal(drivelead.signal, 0.4, 0.5);\n\n \tsinelead.next();\n mainline.addStereoSignal(sinelead.signal, 1.0, 0.5);\n echoline.addStereoSignal(sinelead.signal, 1.2, 0.5);\n\n kick.next();\n mainline.addStereoSignal(kick.signal, 0.8, 0.5);\n\n snare.next();\n mainline.addStereoSignal(snare.signal, 0.8, 0.5); \n\n hihat.next();\n mainline.addStereoSignal(hihat.signal, 0.8, 0.5);\n\n pads.forEach(pad => {\n pad.next();\n mainline.addStereoSignal(pad.signal, 0.45 * padsVolume, 0.5);\n });\n \n echoline.left += delayRight.read() * 0.7;\n echoline.right += delayLeft.read() * 0.7;\n\n delayLeft.write_and_advance(echoline.left);\n delayRight.write_and_advance(echoline.right);\n\n freeverb.tick(reverbline);\n\n left = gain * (mainline.left + reverbline.left + echoline.left);\n right = gain * (mainline.right + reverbline.right + echoline.right);\n\n \tif (ENABLE_MULTIBAND_COMPRESSOR) {\n tribandstereocompressor.process(left,right,0.45, 0.6, 0.9 , 1.20, 1.05, 1.0);\n left = tribandstereocompressor.stereosignal.left;\n right = tribandstereocompressor.stereosignal.right;\n } else {\n left = eqbandl.process(left);\n right = eqbandr.process(right);\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/protracker.mix.ts":"import { EQBand } from \"../fx/eqband\";\n\nimport { Snare } from \"../instruments/snare.class\";\nimport { SawBass3 } from \"../instruments/bass/sawbass3\";\nimport { Eftang } from \"../instruments/lead/eftang\";\nimport { StereoSignal } from \"../synth/stereosignal.class\";\nimport { Kick } from \"../instruments/kick.class\";\nimport { BrassyLead } from \"../instruments/lead/brassy\";\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { FlatPad } from \"../instruments/pad/flatpad.class\";\nimport { createInstrumentArray } from '../common/mixcommon';\nimport { Freeverb } from \"../fx/freeverb\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst gain: f32 = 0.2;\n\nconst bass = new SawBass3();\nconst lead = new Eftang();\nconst kick = new Kick();\nconst snare = new Snare();\nconst hihat = new Hihat();\nconst brassylead = new BrassyLead();\nconst pads: FlatPad[] = createInstrumentArray(4, () => new FlatPad());\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(channel) {\n case 0:\n bass.note = value;\n break;\n case 1:\n lead.note = value;\n break;\n case 2:\n kick.note = value;\n break;\n case 3:\n snare.note = value;\n break;\n case 4:\n hihat.note = value;\n break;\n case 5:\n brassylead.note = value;\n break;\n case 6:\n case 7:\n case 8:\n case 9:\n pads[channel-6].note = value;\n break; \n \n }\n \n}\n\n\nconst mainline = new StereoSignal();\nconst reverbline = new StereoSignal();\nconst freeverb = new Freeverb();\n\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n let left: f32 = 0;\n let right: f32 = 0;\n\n mainline.clear();\n reverbline.clear();\n\n bass.next();\n mainline.addStereoSignal(bass.signal, 0.2, 0.5);\n reverbline.addStereoSignal(bass.signal, 0.1, 0.5);\n\n lead.next();\n mainline.addStereoSignal(lead.signal, 0.2, 0.5);\n reverbline.addStereoSignal(lead.signal, 0.02, 0.5);\n\n kick.next();\n mainline.addStereoSignal(kick.signal, 0.2, 0.5);\n\n snare.next();\n mainline.addStereoSignal(snare.signal, 0.2, 0.5); \n\n hihat.next();\n mainline.addStereoSignal(hihat.signal, 0.2, 0.5);\n\n brassylead.next();\n mainline.addStereoSignal(brassylead.signal, 0.5, 0.5);\n reverbline.addStereoSignal(brassylead.signal, 0.1, 0.5);\n\n pads.forEach(pad => {\n pad.next();\n mainline.addStereoSignal(pad.signal, 0.5, 0.5);\n \n });\n \n freeverb.tick(reverbline);\n\n left = gain * (mainline.left + reverbline.left );\n right = gain * (mainline.right + reverbline.right );\n\n left = eqbandl.process(left);\n right = eqbandr.process(right);\n \n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/shuffle.mix.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nimport { Freeverb } from \"../fx/freeverb\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\n\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\nimport { EQBand } from \"../fx/eqband\";\nimport { SubPiano } from \"../instruments/piano/subpiano\";\nimport { Kick2 } from \"../instruments/drums/kick2.class\";\nimport { Snare } from \"../instruments/snare.class\";\nimport { DeepBass } from \"../instruments/bass/deepbass\";\nimport { Eftang } from \"../instruments/lead/eftang\";\nimport { SoftPad } from \"../instruments/pad/softpad.class\";\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { SineLead } from \"../instruments/lead/sinelead\";\nimport { DriveLead } from \"../instruments/drivelead.class\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 3;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 0;\n\nconst gain: f32 = 0.13;\nconst ENABLE_MULTIBAND_COMPRESSOR = true;\n\nlet freeverb = new Freeverb();\n\nconst delayframes = (SAMPLERATE * (3/8) * 60 / 70) as usize;\nlet delayLeft: DelayLine = new DelayLine(delayframes);\nlet delayRight: DelayLine = new DelayLine(delayframes);\n \nlet echoline = new StereoSignal();\nlet reverbline = new StereoSignal();\nlet mainline = new StereoSignal();\n\nlet tribandstereocompressor = new TriBandStereoCompressor(20,500,7000,19500);\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nfunction createInstrumentArray(length: i32, factoryFunc: () => T): T[] {\n const arr = new Array(length);\n for(let n = 0; n < length;n++) {\n arr[n] = factoryFunc();\n }\n return arr;\n}\n\nconst pianos: SubPiano[] = createInstrumentArray(8, () => new SubPiano());\nconst pads: SoftPad[] = createInstrumentArray(8, () => new SoftPad());\nconst driveleads: DriveLead[] = createInstrumentArray(3, () => new DriveLead());\n\nconst kick = new Kick2();\nconst bass = new DeepBass();\nconst eftang = new Eftang();\nconst snare = new Snare();\nconst hihat = new Hihat();\nconst sinelead = new SineLead();\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(true) {\n case (channel < 8):\n pianos[channel].note = value;\n break;\n case channel === 8:\n kick.note = value;\n break;\n case channel === 9:\n snare.note = value;\n break;\n case channel === 10:\n hihat.note = value;\n break;\n case channel === 11:\n bass.note = value\n break;\n case channel === 12:\n eftang.note = value;\n break;\n case channel < 21:\n pads[channel - 13].note = value;\n break;\n case channel === 21:\n sinelead.note = value;\n break;\n case channel < 25:\n driveleads[channel - 22].note = value;\n break;\n case channel === 25:\n if(value > 1) {\n for(let n = 0; n 1.0) {\n left = 1.0;\n }\n\n if (Math.abs(right) > 1.0) {\n right = 1.0;\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/simple.mix.ts":"import { SawOscillator, Instrument, Noise, BiQuadFilter, FilterType, \n StereoSignal,\n Freeverb, SineOscillator, Envelope, notefreq } from \"./globalimports\";\n import { SAMPLERATE } from '../environment';\n \n export const PATTERN_SIZE_SHIFT: usize = 4;\n export const BEATS_PER_PATTERN_SHIFT: usize = 2;\n \n const mainline = new StereoSignal();\n const reverbline = new StereoSignal();\n const freeverb = new Freeverb();\n \n class Kick extends Instrument {\n private velocity: f32;\n envelope: Envelope = new Envelope(0.0, 0.2, 0, 0.2);\n filterenvelope: Envelope = new Envelope(0.0, 0.05, 0.05, 0.1);\n sawoscillator: SawOscillator = new SawOscillator();\n noise: Noise = new Noise();\n \n filter: BiQuadFilter = new BiQuadFilter();\n \n set note(note: f32) { \n if(note > 1) { \n this.sawoscillator.frequency = 150;\n this.velocity = note / 16; \n this.envelope.attack(); \n this.filterenvelope.attack(); \n } else {\n this.envelope.release();\n this.filterenvelope.release();\n }\n }\n \n next(): void { \n let env: f32 = this.envelope.next();\n this.sawoscillator.frequency = 20.0 + (env * 150.0);\n \n this.filter.update_coeffecients(FilterType.LowPass, SAMPLERATE, \n 40 + (this.filterenvelope.next() * 2000), 0.2);\n \n let osc1: f32 = this.envelope.next() * this.velocity * this.sawoscillator.next() * 0.8 + this.noise.next();\n \n osc1 = this.filter.process(osc1);\n \n const val = env * osc1;\n \n mainline.left+=val;\n mainline.right+=val;\n } \n }\n \n class Lead extends Instrument {\n osc: SineOscillator = new SineOscillator();\n env: Envelope = new Envelope(0.1,0.1,1.0,0.1);\n \n set note(note: f32) {\n if(note > 1) {\n this.osc.frequency = notefreq(note);\n this.env.attack();\n } else if (note === 0) {\n this.env.release();\n }\n }\n @inline\n next(): void {\n const val = this.osc.next() * this.env.next() * 0.3;\n mainline.left += val;\n mainline.right += val;\n }\n }\n \n \n const voices: Instrument[] = [\n new Kick(),\n new Lead(),\n new Lead(),\n new Lead(),\n new Lead()\n ];\n \n export function setChannelValue(channel: usize, value: f32): void {\n voices[channel].note = value;\n }\n \n \n @inline\n export function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear();\n reverbline.clear();\n \n for(var n=0;n(leftSampleBufferPtr, mainline.left + reverbline.left);\n store(rightSampleBufferPtr, mainline.right + reverbline.right); \n }","mixes/test.mix.ts":"// This mix was used in the song \"Groove is in the code\"\n\nimport { StereoSignal } from \"../synth/stereosignal.class\";\n\nimport { Freeverb } from \"../fx/freeverb\";\nimport { TestInstrument } from \"../instruments/testinstrument.class\";\nimport { SawBass } from \"../instruments/sawbass.class\";\nimport { Pad } from \"../instruments/pad.class\";\nimport { Kick } from \"../instruments/kick.class\";\nimport { Snare } from \"../instruments/snare.class\";\nimport { DriveLead } from \"../instruments/drivelead.class\";\n\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\nimport { SquareLead } from \"../instruments/squarelead.class\";\n\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst gain: f32 = 0.15;\nconst ENABLE_MULTIBAND_COMPRESSOR = false;\n\nlet flute = new TestInstrument();\nlet drivelead = new DriveLead();\nlet bass = new SawBass();\nlet pad1 = new Pad();\nlet pad2 = new Pad();\nlet pad3 = new Pad();\nlet kick = new Kick();\nlet snare = new Snare();\nlet hihat = new Hihat();\nlet squarelead = new SquareLead();\n\nlet freeverb = new Freeverb();\n\nlet delayLeft: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\nlet delayRight: DelayLine = new DelayLine(SAMPLERATE * 0.5 as usize);\n \nlet echoline = new StereoSignal();\nlet reverbline = new StereoSignal();\nlet mainline = new StereoSignal();\n\nlet tribandstereocompressor = new TriBandStereoCompressor(15,500,8000,19000);\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(channel) {\n case 0:\n flute.note = value;\n break;\n case 1:\n bass.note = value;\n break;\n case 2:\n pad1.note = value;\n break;\n case 3:\n pad2.note = value;\n break;\n case 4:\n pad3.note = value;\n break;\n case 5:\n kick.note = value;\n break;\n case 6:\n snare.note = value;\n break;\n case 7:\n drivelead.note = value;\n break;\n case 8:\n hihat.note = value;\n break;\n case 9:\n squarelead.note = value;\n break;\n }\n \n}\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear()\n reverbline.clear();\n echoline.clear();\n \n flute.next();\n pad1.next(); \n pad2.next();\n pad3.next(); \n kick.next();\n snare.next();\n hihat.next();\n bass.next(); \n drivelead.next();\n squarelead.next();\n\n mainline.addStereoSignal(flute.signal, 0.7, 0.0);\n echoline.addStereoSignal(flute.signal, 0.6, 1.0);\n \n mainline.addStereoSignal(pad1.signal, 0.58, 0.25);\n echoline.addStereoSignal(pad1.signal, 0.35, 0.25); \n mainline.addStereoSignal(pad2.signal, 0.58, 0.5);\n echoline.addStereoSignal(pad2.signal, 0.30, 0.5);\n mainline.addStereoSignal(pad3.signal, 0.58, 0.75);\n echoline.addStereoSignal(pad3.signal, 0.30, 0.75);\n\n mainline.addStereoSignal(kick.signal, 1.6, 0.5);\n reverbline.addStereoSignal(kick.signal, 0.05, 0.0);\n \n mainline.addStereoSignal(snare.signal, 0.38, 0.6);\n echoline.addStereoSignal(snare.signal, 0.1, 0.4);\n \n mainline.addStereoSignal(hihat.signal, 0.7, 0.4);\n reverbline.addStereoSignal(hihat.signal, 0.05, 0.6);\n\n mainline.addStereoSignal(bass.signal, 1.2, 0.5);\n reverbline.addStereoSignal(bass.signal, 0.1, 0.0);\n\n mainline.addStereoSignal(drivelead.signal, 0.17, 0.4);\n echoline.addStereoSignal(drivelead.signal, 0.4, 0.6);\n\n mainline.addStereoSignal(squarelead.signal,0.6, 0.6);\n echoline.addStereoSignal(squarelead.signal, 0.6, 0.0);\n\n echoline.left += delayRight.read() * 0.5;\n echoline.right += delayLeft.read() * 0.5;\n \n delayLeft.write_and_advance(echoline.left);\n delayRight.write_and_advance(echoline.right);\n\n reverbline.addStereoSignal(echoline, 0.5, 0.5);\n \n freeverb.tick(reverbline);\n \n let left = gain * (mainline.left + echoline.left + reverbline.left);\n let right = gain * (mainline.right + echoline.right + reverbline.right);\n\n if (ENABLE_MULTIBAND_COMPRESSOR) {\n tribandstereocompressor.process(left,right,0.3, 0.3, 0.5 , 2.0, 0.80, 0.9);\n left = tribandstereocompressor.stereosignal.left;\n right = tribandstereocompressor.stereosignal.right;\n } else {\n left = left;\n right = right;\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","mixes/webchip.mix.ts":"import { StereoSignal } from \"../synth/stereosignal.class\";\n\nimport { Freeverb } from \"../fx/freeverb\";\nimport { DelayLine } from \"../fx/delayline\";\nimport { SAMPLERATE } from \"../environment\";\n\nimport { TriBandStereoCompressor } from \"../fx/tribandstereocompressor\";\nimport { EQBand } from \"../fx/eqband\";\nimport { SubPiano } from \"../instruments/piano/subpiano\";\nimport { Kick2 } from \"../instruments/drums/kick2.class\";\nimport { Snare2 } from \"../instruments/drums/snare2.class\";\nimport { SawBass3 } from \"../instruments/bass/sawbass3\";\nimport { Eftang } from \"../instruments/lead/eftang\";\nimport { SoftPad } from \"../instruments/pad/softpad.class\";\nimport { Hihat } from \"../instruments/hihat.class\";\nimport { SineLead } from \"../instruments/lead/sinelead\";\n\nexport const PATTERN_SIZE_SHIFT: usize = 4;\nexport const BEATS_PER_PATTERN_SHIFT: usize = 2;\n\nconst gain: f32 = 0.13;\nconst ENABLE_MULTIBAND_COMPRESSOR = false;\n\nlet freeverb = new Freeverb();\n\nconst delayframes = (SAMPLERATE * (2/3) * 60 / 110) as usize;\nlet delayLeft: DelayLine = new DelayLine(delayframes);\nlet delayRight: DelayLine = new DelayLine(delayframes);\n \nlet echoline = new StereoSignal();\nlet reverbline = new StereoSignal();\nlet mainline = new StereoSignal();\n\nlet tribandstereocompressor = new TriBandStereoCompressor(20,500,7000,19500);\nlet eqbandl = new EQBand(20, 19500);\nlet eqbandr = new EQBand(20, 19500);\n\nfunction createInstrumentArray(length: i32, factoryFunc: () => T): T[] {\n const arr = new Array(length);\n for(let n = 0; n < length;n++) {\n arr[n] = factoryFunc();\n }\n return arr;\n}\n\nconst pianos: SubPiano[] = createInstrumentArray(8, () => new SubPiano());\nconst pads: SoftPad[] = createInstrumentArray(8, () => new SoftPad());\n\nconst kick = new Kick2();\nconst bass = new SawBass3();\nconst eftang = new Eftang();\nconst snare = new Snare2();\nconst hihat = new Hihat();\nconst sinelead = new SineLead();\n\nexport function setChannelValue(channel: usize, value: f32): void {\n switch(true) {\n case (channel < 8):\n pianos[channel].note = value;\n break;\n case channel === 8:\n kick.note = value;\n break;\n case channel === 9:\n snare.note = value;\n break;\n case channel === 10:\n hihat.note = value;\n break;\n case channel === 11:\n bass.note = value\n break;\n case channel === 12:\n eftang.note = value;\n break;\n case channel < 21:\n pads[channel - 13].note = value;\n break;\n case channel === 21:\n sinelead.note = value;\n break;\n }\n}\n\nexport function mixernext(leftSampleBufferPtr: usize, rightSampleBufferPtr: usize): void { \n mainline.clear()\n reverbline.clear();\n echoline.clear();\n \n for(let n = 0;n 1.0) {\n left = 1.0;\n }\n\n if (Math.abs(right) > 1.0) {\n right = 1.0;\n }\n\n store(leftSampleBufferPtr, left);\n store(rightSampleBufferPtr, right); \n}","synth/biquad.ts":"import { SAMPLERATE } from \"../environment\";\nimport { cos, PI, sin } from \"../math/sin\";\n\n// Taken from https://docs.rs/crate/biquad/0.2.0/source/src/\n\nexport const Q_BUTTERWORTH = 0.7071067811865475 as f32; // 1/Math.sqrt(2)\n\nexport enum FilterType {\n SinglePoleLowPass = 1 as i8,\n LowPass = 2 as i8,\n HighPass = 3 as i8,\n Notch = 4 as i8\n}\n\nexport class Coefficients {\n // Denominator coefficients\n a1: f32;\n a2: f32;\n\n // Nominator coefficients\n b0: f32;\n b1: f32;\n b2: f32;\n\n phaseSamples: f32;\n magnitude: f32;\n\n calculatePhaseAndMagnitudeForFreq(freq: f32): void {\n const w: f32 = 2 * Mathf.PI * freq / SAMPLERATE;\n \n const cos1: f32 = Mathf.cos(-1 * w);\n const cos2: f32 = Mathf.cos(-2 * w);\n \n const sin1: f32 = Mathf.sin(-1 * w);\n const sin2: f32 = Mathf.sin(-2 * w);\n \n const realZeros: f32 = this.b0 + this.b1 * cos1 + this.b2 * cos2;\n const imagZeros: f32 = this.b1 * sin1 + this.b2 * sin2;\n \n const realPoles: f32 = 1 + this.a1 * cos1 + this.a2 * cos2;\n const imagPoles: f32 = this.a1 * sin1 + this.a2 * sin2;\n \n const divider: f32 = realPoles * realPoles + imagPoles * imagPoles;\n \n const realHw: f32 = (realZeros * realPoles + imagZeros * imagPoles) / divider;\n const imagHw: f32 = (imagZeros * realPoles - realZeros * imagPoles) / divider;\n \n this.magnitude = Mathf.sqrt(realHw * realHw + imagHw * imagHw);\n\n const phase: f32 = Mathf.atan2(imagHw, realHw);\n \n this.phaseSamples = -(phase / (2*Mathf.PI)) * (SAMPLERATE / freq);\n }\n}\n\nexport class BiQuadFilter {\n y1: f32 = 0;\n y2: f32 = 0;\n x1: f32 = 0;\n x2: f32 = 0;\n s1: f32 = 0;\n s2: f32 = 0;\n readonly coeffs: Coefficients = new Coefficients();\n\n processForm2(input: f32): f32 {\n let out = this.s1 + this.coeffs.b0 * input;\n this.s1 = this.s2 + this.coeffs.b1 * input - this.coeffs.a1 * out;\n this.s2 = this.coeffs.b2 * input - this.coeffs.a2 * out;\n\n return out;\n }\n\n process(input: f32): f32 {\n let out = this.coeffs.b0 * input + this.coeffs.b1 * this.x1 + this.coeffs.b2 * this.x2\n - this.coeffs.a1 * this.y1\n - this.coeffs.a2 * this.y2;\n\n this.x2 = this.x1;\n this.x1 = input;\n this.y2 = this.y1;\n this.y1 = out;\n\n return out;\n }\n\n clearBuffers(): void {\n this.y1 = 0;\n this.y2 = 0;\n this.x1 = 0;\n this.x2 = 0;\n this.s1 = 0;\n this.s2 = 0; \n }\n\n /// Creates coefficients based on the biquad filter type, sampling and cutoff frequency, and Q\n /// value. Note that the cutoff frequency must be smaller than half the sampling frequency and\n /// that Q may not be negative, this will result in an `Err()`.\n update_coeffecients(\n filtertype: FilterType,\n fsHertz: f32,\n f0Hertz: f32,\n q_value: f32\n ): void {\n const fLimit = (fsHertz / 2.0) - 1000;\n if (f0Hertz > fLimit) {\n f0Hertz = fLimit;\n }\n\n if (q_value < 0.0) {\n q_value = 0;\n }\n\n let omega: f32 = 2.0 * PI * f0Hertz / fsHertz;\n let alpha: f32;\n let omega_s: f32;\n let omega_c: f32;\n let b0: f32;\n let b1: f32;\n let b2: f32;\n let a0: f32;\n let a1: f32;\n let a2: f32;\n\n\n switch (filtertype) {\n case FilterType.SinglePoleLowPass:\n alpha = omega / (omega + 1.0);\n\n this.coeffs.a1 = alpha - 1.0;\n this.coeffs.a2 = 0.0;\n this.coeffs.b0 = alpha;\n this.coeffs.b1 = 0.0;\n this.coeffs.b2 = 0.0;\n\n break;\n case FilterType.LowPass:\n // The code for omega_s/c and alpha is currently duplicated due to the single pole\n // low pass filter not needing it and when creating coefficients are commonly\n // assumed to be of low computational complexity.\n omega_s = sin(omega);\n omega_c = cos(omega);\n alpha = omega_s / (2.0 * q_value);\n\n b0 = (1.0 - omega_c) * 0.5;\n b1 = 1.0 - omega_c;\n b2 = (1.0 - omega_c) * 0.5;\n a0 = 1.0 + alpha;\n a1 = -2.0 * omega_c;\n a2 = 1.0 - alpha;\n\n this.coeffs.a1 = a1 / a0;\n this.coeffs.a2 = a2 / a0;\n this.coeffs.b0 = b0 / a0;\n this.coeffs.b1 = b1 / a0;\n this.coeffs.b2 = b2 / a0;\n\n break;\n case FilterType.HighPass:\n omega_s = sin(omega);\n omega_c = cos(omega);\n alpha = omega_s / (2.0 * q_value);\n\n b0 = (1.0 + omega_c) * 0.5;\n b1 = -(1.0 + omega_c);\n b2 = (1.0 + omega_c) * 0.5;\n a0 = 1.0 + alpha;\n a1 = -2.0 * omega_c;\n a2 = 1.0 - alpha;\n\n this.coeffs.a1 = a1 / a0;\n this.coeffs.a2 = a2 / a0;\n this.coeffs.b0 = b0 / a0;\n this.coeffs.b1 = b1 / a0;\n this.coeffs.b2 = b2 / a0;\n\n break;\n case FilterType.Notch:\n omega_s = sin(omega);\n omega_c = cos(omega);\n alpha = omega_s / (2.0 * q_value);\n\n b0 = 1.0;\n b1 = -2.0 * omega_c;\n b2 = 1.0;\n a0 = 1.0 + alpha;\n a1 = -2.0 * omega_c;\n a2 = 1.0 - alpha;\n\n this.coeffs.a1 = a1 / a0;\n this.coeffs.a2 = a2 / a0;\n this.coeffs.b0 = b0 / a0;\n this.coeffs.b1 = b1 / a0;\n this.coeffs.b2 = b2 / a0;\n\n break;\n }\n }\n}\n\nexport class LoPassBiQuadFilter extends BiQuadFilter {\n update(frequency: f32, Q: f32): void {\n this.update_coeffecients(FilterType.LowPass, SAMPLERATE, frequency , Q);\n }\n}\n\nexport class HiPassBiQuadFilter extends BiQuadFilter {\n update(frequency: f32, Q: f32): void {\n this.update_coeffecients(FilterType.HighPass, SAMPLERATE, frequency , Q);\n }\n}\n","synth/bpm.ts":"import { SAMPLERATE } from \"../environment\";\n\nexport function beatToFrame(beat: f64, bpm: f32): usize {\n return (SAMPLERATE * beat * 60 / bpm) as usize;\n}\n","synth/clip.ts":"// From https://ccrma.stanford.edu/~jos/pasp/Soft_Clipping.html#29695\n\n/**\n * soft clip signal with 1/3 headroom as result\n * @param signal signal to be clipped\n */\nexport function softclip(signal: f32): f32 {\n if(signal > 1.0) {\n return 2.0/3.0;\n } else if(signal < -1.0) {\n return -2.0/3.0;\n } else {\n return (signal - ((signal * signal * signal) / 3.0));\n }\n}\n\nexport function hardclip(signal: f32): f32 {\n if(signal > 1.0) {\n return 1.0;\n } else if(signal < -1.0) {\n return -1.0;\n } else {\n return signal;\n }\n}","synth/decibel.ts":"export function decibelToGain(dB: f32): f32 {\n return NativeMathf.pow(10, dB/20.0);\n}\n\nexport function midiLevelToDecibel(midiLevel: u8): f32 {\n return 40 * NativeMathf.log10(midiLevel as f32/127);\n}\n\nexport function midiLevelToGain(midiLevel: u8): f32 {\n return decibelToGain(midiLevelToDecibel(midiLevel));\n}","synth/envelope.class.ts":"import { SAMPLERATE } from \"../environment\";\n\nexport enum EnvelopeState {\n ATTACK = 0,\n DECAY = 1,\n SUSTAIN = 2,\n RELEASE = 3,\n DONE = 4\n}\n\nexport class Envelope {\n attackStep: f32;\n decayStep: f32;\n sustainLevel: f32;\n releaseStep: f32;\n \n val: f32 = 0;\n state: EnvelopeState = EnvelopeState.DONE;\n\n constructor(attackTime: f32, decayTime: f32, sustainLevel: f32, releaseTime: f32) {\n this.attackStep = 1.0 / (attackTime * SAMPLERATE);\n this.decayStep = 1.0 / (decayTime * SAMPLERATE);\n this.releaseStep = 1.0 / (releaseTime * SAMPLERATE);\n this.sustainLevel = sustainLevel;\n }\n\n next(): f32 {\n switch(this.state) {\n case EnvelopeState.ATTACK:\n this.val += this.attackStep;\n if(this.val >= 1.0) {\n this.val = 1.0;\n this.state = EnvelopeState.DECAY;\n }\n break;\n case EnvelopeState.DECAY:\n this.val -= this.decayStep;\n if(this.val <= this.sustainLevel) {\n this.val = this.sustainLevel;\n this.state = EnvelopeState.SUSTAIN;\n }\n break;\n case EnvelopeState.SUSTAIN:\n break;\n case EnvelopeState.RELEASE:\n this.val -= this.releaseStep;\n if(this.val <= 0) {\n this.val = 0;\n this.state = EnvelopeState.DONE;\n }\n break;\n case EnvelopeState.DONE:\n break;\n }\n return this.val;\n }\n\n attack(): void {\n this.state = EnvelopeState.ATTACK;\n }\n \n release(): void {\n this.state = EnvelopeState.RELEASE;\n }\n\n isDone(): boolean {\n return this.state === EnvelopeState.DONE;\n }\n}","synth/ifftoscillator.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { FFT } from '../math/fft';\n\nexport class IFFTOscillator {\n position: f32 = 0;\n positionincrement: f32 = 0;\n buffersize: f32;\n buffermask: u32;\n fft: FFT;\n scalefactor: f32;\n\n constructor(buffersize_shift: i32) {\n this.fft = new FFT(buffersize_shift);\n this.buffersize = (1 << buffersize_shift) as f32;\n this.buffermask = ~(0xffffffff << buffersize_shift);\n this.scalefactor = (this.buffersize / 2) - 1;\n }\n\n set frequency(frequency: f32) {\n this.positionincrement = (frequency * this.buffersize) / SAMPLERATE;\n }\n\n createWave(real: f32[], imaginary: f32[]): void { \n for (let n = 1; n <= real.length &&\n n <= imaginary.length &&\n n < (this.fft.buffer.length / 2) - 1; n++) {\n this.fft.buffer[n].re = -real[n - 1] * this.scalefactor;\n this.fft.buffer[this.fft.buffer.length - n].re = real[n -1] * this.scalefactor;\n\n this.fft.buffer[n].im = -imaginary[n -1] * this.scalefactor;\n this.fft.buffer[this.fft.buffer.length - n].im = imaginary[n -1] * this.scalefactor;\n }\n }\n\n next(): f32 {\n const bufferposfloor = NativeMathf.floor(this.position);\n const bufferpos = bufferposfloor as i32;\n const t = this.position - bufferposfloor;\n\n const x0 = this.fft.buffer[(bufferpos - 1) & this.buffermask].re;\n const x1 = this.fft.buffer[bufferpos].re;\n const x2 = this.fft.buffer[(bufferpos + 1) & this.buffermask].re;\n const x3 = this.fft.buffer[(bufferpos + 2) & this.buffermask].re;\n \n // cubic interpolation\n \n const a0 = x3 - x2 - x0 + x1;\n const a1 = x0 - x1 - a0;\n const a2 = x2 - x0;\n const a3 = x1;\n const ret = (a0 * (t * t * t)) + (a1 * (t * t)) + (a2 * t) + (a3);\n\n // increment position\n this.position += this.positionincrement;\n this.position %= this.buffersize;\n \n return ret; \n }\n}\n","synth/noise.class.ts":"let x: i32 = 123456789;\nlet y: i32=234567891;\nlet z: i32=345678912;\nlet w: i32=456789123;\nlet c: i32=0; \n\nexport class Noise {\n \n next(): f32 { \n y ^= (y<<5); y ^= (y>>7); y ^= (y<<22); \n\n let t = z+w+c; z = w;\n c = t < 0 ? 1 : 0;\n w = t & 2147483647; \n \n x += 1411392427; \n \n let rnd: f32 = ((x + y + w) & 0xffff) as f32;\n return ((rnd / (1 << 16 as f32))) - 0.5;\n }\n }\n ","synth/note.ts":"const pitchstep: f64 = 1.0004513695322617; // Math.pow(2, (1/128) / 12);\nconst c0: f64 = 8.175798915643707; // 440 * Math.pow(2, -69 / 12);\nlet pitchtable = __new(128 * 128 * 4, idof>());\nlet pitch: f64 = c0;\n\nfor (let n: usize = 0; n < (128 * 128); n++) {\n store(pitchtable + (n << 2), pitch as f32);\n pitch *= pitchstep;\n}\n\nexport function notefreq(note: f32): f32 {\n let pitchtableIndex: usize = (note * 128.0) as usize;\n return load(pitchtable + (pitchtableIndex << 2));\n}","synth/pan.class.ts":"import { StereoSignal } from \"./stereosignal.class\";\n\nconst HALF_OF_SQRT_2 = NativeMathf.sqrt(2) / 2;\n\nexport class Pan {\n leftLevel: f32;\n rightLevel: f32;\n \n constructor() {\n this.setPan(0.5); \n }\n\n /**\n * Don't use as part of the rendering process. Use to calculate pan levels on controller changes\n * @param pan from 0.0 (left) to 1.0 (right). 0.5 is center\n */\n setPan(pan: f32): void {\n const angle = (pan - 0.5) * NativeMathf.PI / 2;\n // left channel\n this.leftLevel = HALF_OF_SQRT_2 * (NativeMathf.cos(angle) - NativeMathf.sin(angle));\n // right channel\n this.rightLevel = HALF_OF_SQRT_2 * (NativeMathf.cos(angle) + NativeMathf.sin(angle));\n }\n}\n","synth/sawoscillator.class.ts":"\nimport { SAMPLERATE } from '../environment';\n\nexport class SawOscillator {\n position: u32 = 0;\n frequency: f32 = 0;\n\n next(): f32 {\n if(this.frequency > 0) {\n let ret = (this.position as f32 / 0x10000 as f32) - 0.5;\n this.position = (((this.position as f32) + (this.frequency/SAMPLERATE)\n * 0x10000 as f32) as u32) & 0xffff;\n \n \n return ret as f32;\n } else {\n return 0;\n }\n }\n }\n ","synth/shaper.ts":"/**\n * Taken from https://github.com/hzdgopher/64klang/blob/master/Player/Player/SynthNode.cpp#L2050\n */\n\nconst NOISEGEN_B0: f32 = 0.99765014648437500;\n\nexport class WaveShaper {\n drive: f32 = 0.5;\n \n process(input: f32): f32 { \n // clamp to -1..1 (a little less)\n let f: f32 = this.drive < NOISEGEN_B0 ? this.drive > -NOISEGEN_B0 ?\n this.drive : -NOISEGEN_B0 : \n NOISEGEN_B0;\n\n // k = 2*amount/(1-amount);\n let v = (f+f)/(1.0-f);\n\n // process f(x) = (1+k)*x/(1+k*abs(x))\n return (1.0 + v) *\n input/\n (1.0 + v * min(abs(input), 1.0)); \n }\n}","synth/sineoscillator.class.ts":"\nimport { SAMPLERATE } from '../environment';\nimport { sin, PI } from '../math/sin';\n\nexport class SineOscillator {\n position: u32 = 0;\n frequency: f32 = 0;\n\n next(): f32 {\n let ret = sin(PI * 2 * (this.position as f32) / (1 << 16 as f32));\n this.position = (((this.position as f32) + (this.frequency/SAMPLERATE)\n * 0x10000 as f32) as u32) & 0xffff;\n \n return ret as f32;\n }\n }\n ","synth/squareoscillator.class.ts":"\nimport { SAMPLERATE } from '../environment';\n\nexport class SquareOscillator {\n position: u32 = 0;\n frequency: f32 = 0;\n\n next(): f32 {\n if(this.frequency > 0) {\n let ret: f32 = this.position as f32 > 0x8000 ? 0.5 : -0.5;\n this.position = (((this.position as f32) + (this.frequency/SAMPLERATE)\n * 0x10000 as f32) as u32) & 0xffff;\n \n \n return ret;\n } else {\n return 0;\n }\n }\n}\n ","synth/stereosignal.class.ts":"import { Pan } from './pan.class';\n\nexport class StereoSignal {\n left: f32 = 0;\n right: f32 = 0;\n\n clear(): void {\n this.left = 0;\n this.right = 0;\n }\n\n /**\n * Add left and right values directly to the signal\n * @param left\n * @param right \n */\n @inline\n add(left: f32, right:f32): void {\n this.left += left;\n this.right += right;\n }\n\n /**\n * Add stereo signal with simple (not proper) panning\n * @param signal \n * @param level \n * @param pan 0.0 - 1.0\n */\n addStereoSignal(signal: StereoSignal, level: f32, pan: f32): void {\n this.left += signal.left * pan * level;\n this.right += signal.right * (1 - pan) * level;\n }\n\n addMonoSignal(signal: f32, level: f32, pan: f32): void {\n this.left += signal * pan * level;\n this.right += signal * (1 - pan) * level;\n }\n}","synth/triangleoscillator.class.ts":"import { SAMPLERATE } from '../environment';\n\nexport class TriangleOscillator {\n position: i32 = 0;\n frequency: f32 = 0;\n\n next(): f32 {\n if (this.frequency > 0) {\n const pos: i32 = this.position;\n let ret: f32;\n if (pos < 0x8000) {\n ret = (pos as f32 / 0x8000 as f32);\n } else {\n ret = (- (pos - 0x8000) as f32 / 0x8000 as f32) + 1.0;\n }\n\n this.position = (((this.position as f32) + (this.frequency / SAMPLERATE)\n * 0x10000 as f32) as i32) & 0xffff;\n\n return ret * 2 - 1 as f32;\n } else {\n return 0;\n }\n }\n}\n","synth/waveguide.ts":"import { SAMPLERATE } from \"../environment\";\nimport { DelayLineFloat } from \"../fx/delayline\";\nimport { MonoAudioPlayer } from \"../midi/instruments/audioplayer\";\nimport { BiQuadFilter, FilterType, LoPassBiQuadFilter, Q_BUTTERWORTH } from \"./biquad\";\nimport { Envelope } from \"./envelope.class\";\nimport { notefreq } from \"./note\";\n\nlet seed: i32 = 1;\n\nexport function noise(): f32 {\n seed = (seed * 1103515245 + 12345) & 0x7fffffff;\n return ((seed as f32 % 1000000 / 1000000) - 0.5) as f32;\n}\n\nexport class WaveGuide {\n envExciter: Envelope;\n filterExciter: BiQuadFilter = new BiQuadFilter();\n delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);\n filterFeedback: BiQuadFilter = new BiQuadFilter();\n feedbackLevel: f32;\n feedbackFilterFreq: f32;\n freq: f32;\n exciterenvlevel: f32;\n\n constructor(exciterAttack: f32, exciterRelease: f32, exciterFilterFreq: f32, feedbackLevel: f32) {\n this.envExciter = new Envelope(exciterAttack,\n exciterRelease, 0,\n exciterRelease);\n this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n exciterFilterFreq, Q_BUTTERWORTH);\n\n this.feedbackLevel = feedbackLevel;\n }\n\n setFilterExciterFreq(freq: f32): void {\n this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n freq, Q_BUTTERWORTH);\n\n }\n\n start(freq: f32, feedbackFilterFreq: f32): void {\n if (freq != this.freq) {\n this.freq = freq;\n const maxFeedbackFilterFreq: f32 = 20000;\n if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {\n feedbackFilterFreq = maxFeedbackFilterFreq as f32;\n } else if (feedbackFilterFreq < 10) {\n feedbackFilterFreq = 10;\n }\n this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n feedbackFilterFreq, Q_BUTTERWORTH);\n\n this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);\n const filterphase = this.filterFeedback.coeffs.phaseSamples;\n\n this.filterFeedback.clearBuffers(); \n this.filterExciter.clearBuffers();\n\n this.feedbackFilterFreq = feedbackFilterFreq;\n this.delay.setNumFramesAndClear(\n (SAMPLERATE /\n (freq)\n ) - filterphase\n );\n this.envExciter.val = 0;\n\n }\n this.exciterenvlevel = 1;\n this.envExciter.attack();\n\n }\n\n process(): f32 {\n const envexciter = this.envExciter.next() * this.exciterenvlevel;\n let exciterSignal: f32 = noise() * envexciter;\n exciterSignal = this.filterExciter.process(exciterSignal);\n\n const feedback = this.delay.read();\n let signal = exciterSignal + feedback;\n\n signal = this.filterFeedback.processForm2(signal);\n this.delay.write_and_advance(\n signal * this.feedbackLevel\n );\n return signal;\n\n }\n}\n\nexport class AuxExciterWaveGuide {\n delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);\n filterFeedback: BiQuadFilter = new BiQuadFilter();\n feedbackFilterFreq: f32;\n feedbackLevel: f32;\n freq: f32;\n\n constructor(public exciter: WaveGuide) {\n\n }\n\n start(freq: f32, feedbackFilterFreq: f32): void {\n if (freq != this.freq) {\n this.freq = freq;\n const maxFeedbackFilterFreq: f32 = 20000;\n if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {\n feedbackFilterFreq = maxFeedbackFilterFreq as f32;\n } else if (feedbackFilterFreq < 10) {\n feedbackFilterFreq = 10;\n }\n this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n feedbackFilterFreq, Q_BUTTERWORTH);\n this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);\n const filterphase: f32 = this.filterFeedback.coeffs.phaseSamples;\n\n this.filterFeedback.clearBuffers();\n \n this.feedbackFilterFreq = feedbackFilterFreq;\n this.delay.setNumFramesAndClear(\n (SAMPLERATE /\n (freq)\n ) - filterphase\n );\n\n }\n }\n\n process(): f32 {\n let exciterSignal: f32 = this.exciter.process();\n\n const feedback = this.delay.read();\n let signal = exciterSignal + feedback;\n\n signal = this.filterFeedback.processForm2(signal);\n this.delay.write_and_advance(\n signal * this.feedbackLevel\n );\n return signal;\n }\n}\n\nexport class AudioExciterWaveGuide {\n delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);\n filterFeedback: BiQuadFilter = new BiQuadFilter();\n exciterFilter: LoPassBiQuadFilter = new LoPassBiQuadFilter();\n feedbackFilterFreq: f32;\n feedbackLevel: f32;\n freq: f32;\n\n constructor(public exciter: MonoAudioPlayer) {\n\n }\n\n start(freq: f32, feedbackFilterFreq: f32): void {\n this.exciter.restart();\n if (freq != this.freq) {\n this.freq = freq;\n const maxFeedbackFilterFreq: f32 = 20000;\n if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {\n feedbackFilterFreq = maxFeedbackFilterFreq as f32;\n } else if (feedbackFilterFreq < 10) {\n feedbackFilterFreq = 10;\n }\n this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n feedbackFilterFreq, Q_BUTTERWORTH);\n this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);\n const filterphase: f32 = this.filterFeedback.coeffs.phaseSamples;\n\n this.filterFeedback.clearBuffers();\n this.exciterFilter.clearBuffers();\n \n this.feedbackFilterFreq = feedbackFilterFreq;\n this.delay.setNumFramesAndClear(\n (SAMPLERATE /\n (freq)\n ) - filterphase\n );\n }\n }\n\n reset(): void {\n this.delay.reset();;\n this.filterFeedback.clearBuffers();\n this.exciterFilter.clearBuffers();\n }\n\n process(): f32 {\n let exciterSignal: f32 = this.exciter.nextframe();\n exciterSignal = this.exciterFilter.process(exciterSignal);\n\n const feedback = this.delay.read();\n let signal = exciterSignal + feedback;\n\n signal = this.filterFeedback.processForm2(signal);\n this.delay.write_and_advance(\n signal * this.feedbackLevel\n );\n return signal;\n }\n}\n\nexport class CustomExciterWaveGuide {\n delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);\n filterFeedback: BiQuadFilter = new BiQuadFilter();\n feedbackFilterFreq: f32;\n feedbackLevel: f32;\n freq: f32;\n exciterSignal: f32;\n\n start(freq: f32, feedbackFilterFreq: f32): void {\n if (freq != this.freq) {\n this.freq = freq;\n const maxFeedbackFilterFreq: f32 = 20000;\n if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {\n feedbackFilterFreq = maxFeedbackFilterFreq as f32;\n } else if (feedbackFilterFreq < 10) {\n feedbackFilterFreq = 10;\n }\n this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,\n feedbackFilterFreq, Q_BUTTERWORTH);\n this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);\n const filterphase: f32 = this.filterFeedback.coeffs.phaseSamples;\n\n this.filterFeedback.clearBuffers();\n \n this.feedbackFilterFreq = feedbackFilterFreq;\n this.delay.setNumFramesAndClear(\n (SAMPLERATE /\n (freq)\n ) - filterphase\n );\n }\n }\n\n process(): f32 {\n const feedback = this.delay.read();\n let signal = this.exciterSignal + feedback;\n\n signal = this.filterFeedback.processForm2(signal);\n this.delay.write_and_advance(\n signal * this.feedbackLevel\n );\n return signal;\n }\n}","wasi_main.ts":"import { fd_write, iovec} from 'bindings/wasi';\nimport { allocateSampleBuffer, getTick, setBPM, setPatternsPtr, setInstrumentPatternListPtr, fillSampleBufferInterleaved } from './index';\n\nconst patterns: i8[] = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,1,1,1,33,1,36,38,0,36,1,33,36,0,38,1,33,1,45,1,0,0,33,1,36,1,48,1,36,48,0,50,100,0,0,0,100,0,0,10,100,0,0,0,100,0,0,0,90,20,90,20,90,20,90,20,90,20,90,20,90,20,90,20,0,0,0,0,60,0,0,0,0,0,0,0,60,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,1,1,1,0,0,0,0,0,0,0,0,62,1,1,1,64,1,1,1,0,0,0,0,0,0,0,0,64,1,1,1,62,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,64,1,1,64,0,0,0,0,62,1,1,62,0,0,0,0,66,1,1,1,0,0,0,0,0,0,0,0,66,1,1,1,67,1,1,1,0,0,0,0,0,0,0,0,67,1,1,1,66,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,67,1,1,67,0,0,0,0,67,1,1,67,0,0,0,0,57,1,1,1,0,0,0,0,0,0,0,0,57,1,1,1,60,1,1,1,0,0,0,0,0,0,0,0,71,1,1,1,69,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,72,1,1,72,0,0,0,0,71,1,1,71,0,0,0,0,0,0,0,0,60,0,0,0,0,0,0,30,60,0,0,40,0,0,57,1,62,1,57,1,62,1,1,64,1,1,60,1,1,1,59,1,60,1,59,1,60,1,1,59,1,1,57,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,1,67,1,67,1,67,1,1,69,1,1,66,0,62,64,67,0,71,0,0,74,0,67,0,0,0,0,0,0,31,1,43,1,0,0,0,0,26,38,0,41,0,41,43,0,26,1,38,1,0,0,0,0,21,33,0,36,0,36,38,0,29,1,41,1,0,0,0,0,24,36,0,39,0,39,41,0,24,1,36,1,0,0,0,0,19,31,0,34,0,34,36,0,0,0,67,0,67,0,67,71,0,72,0,71,0,67,65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,0,65,62,0,65,0,67,0,69,0,0,67,0,0,64,0,62,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,65,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,67,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,69,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,71,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,72,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,62,0,65,0,67,0,69,0,0,67,0,0,0,72,0,72,71,0,72,0,74,0,71,0,0,67,0,0,0,0,62,74,0,62,74,0,62,0,69,1,1,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,0,67,0,74,72,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,71,1,1,1,67,1,1,1,0,0,0,0,1,1,1,1,71,1,1,1,67,1,1,1,69,1,1,1,72,1,1,1,1,1,1,1,1,1,1,1,71,1,69,1,67,1,1,1,1,1,1,1,1,1,1,1,1,1,64,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,16,32,48,64,0,0,0,0,0,0,0,0,0,0,0,32,40,48,64,0,0,0,0,0,0,0,0,0,0,0,0,74,1,1,1,1,1,1,1,1,1,1,1,1,1,1,77,1,1,1,1,1,1,1,1,1,1,1,1,76,1,74,1,72,1,1,1,1,1,1,1,1,1,1,1,1,1,79,1,2,16,32,48,64,0,0,0,0,0,0,0,0,80,96,32,36,40,48,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,96,112,127,0,0,0,0,0,20,0,30,60,0,0,20,0,20,0,30,60,20,60,40,81,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,64,0,48,32,16,0,0,0,0,64,0,0,0,0,0,0,57,0,57,0,62,0,62,0,69,0,69,0,72,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,78,74,69,0,0,0,0,62,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,0,0,10,0,10,0,0,60,0,0,25,0,20,0,0,60,10,0,10,0,10,35,0,60,10,0,35,0,0,69,0,69,0,74,0,74,0,81,0,81,0,83,0,83,0,81,0,81,0,74,0,76,0,74,0,74,0,0,0,0,0,62,1,1,1,69,1,71,1,1,1,69,1,1,1,64,1,1,69,1,1,62,1,1,1,1,1,1,1,0,0,64,0,0,0,0,0,0,0,2,32,64,0,0,0,0,0,64,1,1,69,1,1,62,1,1,1,64,1,66,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,67,1,1,1,66,1,1,1,64,1,62,1,1,1,59,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,32,48,64,0,0,69,0,69,0,74,86,74,0,81,0,81,0,83,91,83,0,81,0,81,0,74,86,76,0,74,86,91,90,86,81,83,0,81,0,81,0,74,0,76,0,74,0,74,0,86,0,69,1,1,1,0,0,0,0,0,0,0,0,69,1,1,1,67,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,69,1,1,69,0,0,0,0,67,1,1,67,0,0,0,0,71,1,1,1,0,0,0,0,0,0,0,0,71,1,1,1,72,1,1,1,0,0,0,0,0,0,0,0,72,1,1,1,71,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,72,1,1,67,0,0,0,0,72,1,1,67,0,0,0,0,65,1,1,1,0,0,0,0,0,0,0,0,76,1,1,1,74,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,77,1,1,72,0,0,0,0,76,1,1,71,0,0,0,0,31,1,1,1,38,1,41,43,0,41,1,38,41,0,43,1,38,1,50,1,0,0,38,1,41,1,53,1,41,53,0,55,0,0,74,0,74,0,79,0,79,0,86,0,86,0,88,0,88,0,86,0,86,0,79,0,81,0,79,0,79,0,0,0,0,0,74,0,74,0,79,91,79,0,86,0,86,0,88,96,88,0,86,0,86,0,79,91,81,0,79,91,96,95,91,86,0,0,67,1,1,1,74,1,76,1,1,1,74,1,1,1,69,1,1,74,1,1,67,1,1,1,1,1,1,1,0,0,88,0,86,0,86,0,79,0,81,0,79,0,79,0,91,0,69,1,1,74,1,1,67,1,1,1,69,1,71,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,72,1,1,1,71,1,1,1,69,1,67,1,1,1,64,1,1,1,26,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,100,0,0,0,100,0,0,30,100,0,0,0,100,0,0,0,90,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,1,1,1,0,0,0,0,0,0,0,0,60,1,1,1,57,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,66,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,69,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,69,74,81,0,74,81,86,0,0,0,0,0,0,0,0,91,90,86,81,0,0,0,0,0,0,0,0,0,0,0,0,93,86,81,78,74,69,74,78,0,0,0,0,0,74,81,74,81,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];\nconst instrumentspatternlists: i8[] = [1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,25,26,27,28,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,88,88,88,89,88,88,88,89,1,1,1,100,0,0,0,0,0,0,0,0,20,21,22,23,20,21,22,24,0,0,0,0,0,0,0,0,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,0,0,0,0,0,0,63,0,20,21,22,23,20,21,22,24,0,0,0,0,0,0,0,0,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,105,35,106,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,31,0,29,30,40,41,29,30,31,0,29,30,31,0,29,30,31,0,29,30,31,0,0,0,0,0,61,62,0,0,0,0,0,0,0,0,0,0,29,30,31,0,29,30,40,41,29,30,31,0,29,30,31,0,29,30,31,0,29,30,31,0,0,0,0,0,0,0,0,0,66,67,0,0,66,67,0,0,66,67,75,76,66,77,75,76,90,91,92,93,90,96,92,93,107,108,109,110,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,101,101,101,6,5,5,5,5,5,5,5,19,5,5,5,5,5,5,5,19,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,58,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,19,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,58,5,5,5,5,64,64,64,65,64,64,64,65,64,64,64,65,64,64,64,65,64,64,64,65,64,64,64,65,64,64,64,65,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,102,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,32,33,33,34,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,7,8,9,10,12,78,79,80,12,78,79,80,7,8,9,0,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,35,36,36,35,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,11,12,13,14,81,82,83,84,81,82,83,84,11,12,13,0,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,37,38,38,38,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,15,16,17,18,7,85,86,87,7,85,86,87,15,103,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,39,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,43,45,43,44,43,46,37,47,48,49,52,53,54,49,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,43,45,43,44,43,46,37,47,48,49,52,53,54,49,22,0,0,0,0,0,0,0,68,69,0,0,68,71,72,73,68,69,0,0,68,71,72,73,94,95,0,0,94,97,98,99,105,35,106,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,51,51,0,55,56,51,57,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,51,51,0,55,56,51,57,0,0,0,0,0,0,0,0,70,0,0,0,70,0,74,0,70,0,0,0,70,0,74,0,70,0,0,0,70,0,74,0,0,0,50,0];\n\n\n// ./node_modules/.bin/asc --runtime none assembly/wasi_main.ts --noAssert --use abort= -O3 -o build/index.wasm\n// wasmer build/index.wasm | sox -S -t raw -b 32 -e float -r 44100 -c 2 - -d\nexport function _start(): void {\n const samplebuf = allocateSampleBuffer(128);\n setPatternsPtr(load(changetype(patterns)));\n setInstrumentPatternListPtr(load(changetype(instrumentspatternlists)), 116, 19);\n setBPM(123);\n \n const iov = new iovec();\n iov.buf = samplebuf;\n iov.buf_len = 128 * 8;\n \n const written_ptr = changetype(new ArrayBuffer(sizeof()));\n \n let previousTick: f64;\n do {\n previousTick = getTick();\n fillSampleBufferInterleaved();\n fd_write(1, changetype(iov), 1, written_ptr);\n } while(previousTick < getTick())\n}"} \ No newline at end of file