Skip to content

Instantly share code, notes, and snippets.

@petersalomonsen
Created May 21, 2022 06:17
Show Gist options
  • Save petersalomonsen/9f13d0071940df891c253ee022f083ba to your computer and use it in GitHub Desktop.
Save petersalomonsen/9f13d0071940df891c253ee022f083ba to your computer and use it in GitHub Desktop.
WebAssembly Music - Veronika's Waltz
/*
* Copyright (c) 2022 - Peter Johan Salomonsen
*/
setBPM(50);
addInstrument('piano');
addInstrument('string');
addInstrument('drums');
addInstrument('guitar');
addInstrument('bass');
addInstrument('tubelead');
addInstrument('flute');
addInstrument('padsynth');
addInstrument('brass');
addInstrument('choir');
//solo(0);
//solo(2);
//solo(6);
const emptypattern = () => createTrack(0).steps(1/16,[,]);
const beat = () => createTrack(2).steps(12, [
[c5,fs5],,,fs5(0.5,10),fs5(0.5,35),,,,fs5(0.5,35),,,fs5(0.5,10),
[d5,fs5],,,,fs5(0.5,35),,,fs5(0.5,10),[c5,fs5(0.5,35)],,,,
[c5,fs5],,,fs5(0.5,10),fs5(0.5,35),,,,fs5(0.5,35),,,fs5(0.5,10),
[d5,fs5],,,,fs5(0.01,35),,,fs5(0.01,10),fs5(0.01,35),,c5(0.01,10),c5(0.01,30),
]);
const cymbals = () => createTrack(2).steps(12, [
[cs6(0.02,50)],,,cs6(0.02,10),cs6(0.02,35),,,,cs6(0.02,35),,,cs6(0.02,10),
[cs6(0.02,50)],,,cs6(0.02,10),cs6(0.02,35),,,,cs6(0.02,35),,,cs6(0.02,10),
[cs6(0.02,50)],,,cs6(0.02,10),cs6(0.02,35),,,,cs6(0.02,35),,,cs6(0.02,10),
[cs6(0.02,50)],,,cs6(0.02,10),cs6(0.02,35),,,,cs6(0.02,35),,,cs6(0.02,10),
]);
const choir = () => createTrack(9).play([[ 0.09, controlchange(64, 127) ],
[ 0.03, cs7(2.93, 82) ],
[ 0.04, cs6(2.93, 56) ],
[ 0.03, f7(2.96, 75) ],
[ 3.05, controlchange(64, 0) ],
[ 3.15, controlchange(64, 127) ],
[ 2.99, c7(0.63, 87) ],
[ 0.02, gs6(3.66, 77) ],
[ 2.98, ds7(0.73, 72) ],
[ 2.99, gs5(0.75, 62) ],
[ 4.10, controlchange(64, 0) ],
[ 6.14, controlchange(64, 127) ],
[ 3.98, f6(2.63, 75) ],
[ 3.98, as6(2.64, 81) ],
[ 3.96, cs7(2.69, 84) ],
[ 3.98, as5(2.68, 68) ],
[ 7.06, controlchange(64, 0) ],
[ 7.46, controlchange(64, 127) ],
[ 6.98, as6(0.68, 86) ],
[ 6.98, fs6(0.70, 86) ],
[ 6.99, fs5(0.72, 78) ],
[ 6.97, ds7(0.75, 88) ],
[ 8.01, controlchange(64, 0) ],
[ 8.0, f6(2.88, 75) ],
[ 8.0, cs7(3.03, 76) ],
[ 8.0, gs5(3.03, 76) ],
[ 8.0, gs6(3.07, 84) ],
[ 11.0, a5(1.00, 79) ],
[ 11.0, ds7(1.02, 82) ],
[ 11.0, c7(1.04, 78) ],
[ 11.0, f6(3.81, 78) ],
[ 12.0, as5(3.04, 80) ],
[ 15.19, controlchange(64, 127) ],
[ 15.0, fs6(0.60, 82) ],
[ 15.0, fs7(0.67, 81) ],
[ 12.0, as6(3.80, 81) ],
[ 12.0, cs7(3.82, 83) ],
[ 15.0, fs5(0.87, 82) ],
[ 16.14, controlchange(64, 0) ],
[ 16.53, controlchange(64, 127) ],
[ 16.0, gs6(2.48, 73) ],
[ 16.51, f7(2.03, 50) ],
[ 16.0, cs7(2.47, 102) ],
[ 16.0, gs7(2.60, 69) ],
[ 16.0, gs5(2.84, 73) ],
[ 19.14, controlchange(64, 0) ],
[ 19.33, controlchange(64, 127) ],
[ 19.02, a5(0.55, 67) ],
[ 19.02, c7(0.59, 94) ],
[ 19.00, a7(0.60, 88) ],
[ 19.00, f7(0.61, 87) ],
[ 20.08, controlchange(64, 0) ],
[ 22.49, controlchange(64, 127) ],
[ 20.00, f7(2.83, 87) ],
[ 20.00, cs7(2.86, 91) ],
[ 19.98, as7(2.92, 94) ],
[ 20.00, as5(2.97, 81) ],
[ 23.06, controlchange(64, 0) ],
[ 23.46, controlchange(64, 127) ],
[ 23.0, cs7(0.73, 102) ],
[ 23.0, as7(0.75, 101) ],
[ 23.0, fs7(0.75, 94) ],
[ 23.0, fs5(0.75, 62) ],
[ 24.03, controlchange(64, 0) ],
[ 24.00, cs5(0.46, 54) ],
[ 24.50, d5(0.03, 15) ],
[ 25.10, controlchange(64, 127) ],
[ 23.99, f7(2.78, 87) ],
[ 23.98, cs7(2.82, 91) ],
[ 27.11, controlchange(64, 0) ],
[ 27.41, controlchange(64, 127) ],
[ 27.05, ds7(0.52, 83) ],
[ 27.06, c7(0.53, 94) ],
[ 27.06, gs5(0.53, 66) ],
[ 23.99, gs7(3.66, 81) ],
[ 28.09, controlchange(64, 0) ],
[ 28.00, gs6(3.89, 73) ],
[ 28.00, cs6(3.90, 59) ],
[ 28.01, f7(3.90, 75) ],
[ 27.99, cs7(3.92, 86) ]]);
const piano = () => createTrack(0).play([[ 0.06, controlchange(64, 127) ],
[ 0.03, f5(0.29, 77) ],
[ 0.68, cs5(0.30, 23) ],
[ 0.37, f4(0.63, 38) ],
[ 1.01, f5(0.23, 63) ],
[ 1.34, f4(0.62, 34) ],
[ 1.67, cs5(0.30, 32) ],
[ 0.03, cs3(2.34, 71) ],
[ 2.01, f5(0.37, 65) ],
[ 2.33, f4(0.31, 29) ],
[ 2.66, cs5(0.16, 33) ],
[ 2.96, controlchange(64, 0) ],
[ 3.04, controlchange(64, 127) ],
[ 3.0, ds5(0.44, 71) ],
[ 3.0, gs2(0.45, 54) ],
[ 3.33, ds4(0.23, 32) ],
[ 3.66, c5(0.33, 42) ],
[ 3.98, controlchange(64, 0) ],
[ 4.09, controlchange(64, 127) ],
[ 4.0, cs5(0.30, 61) ],
[ 4.0, as2(0.53, 54) ],
[ 4.33, f4(0.63, 32) ],
[ 4.66, as4(0.35, 38) ],
[ 5.0, cs5(0.32, 62) ],
[ 5.33, f4(0.61, 39) ],
[ 5.66, as4(0.32, 33) ],
[ 6.0, cs5(0.33, 58) ],
[ 6.33, f4(0.30, 43) ],
[ 6.66, as4(0.28, 41) ],
[ 6.94, controlchange(64, 0) ],
[ 7.04, controlchange(64, 127) ],
[ 7.0, fs2(0.36, 57) ],
[ 7.0, ds5(0.60, 81) ],
[ 7.33, fs4(0.36, 36) ],
[ 7.66, as4(0.28, 41) ],
[ 8.06, controlchange(64, 0) ],
[ 8.15, controlchange(64, 127) ],
[ 8.00, cs5(0.28, 62) ],
[ 8.33, f4(0.60, 43) ],
[ 8.66, gs4(0.34, 38) ],
[ 8.99, cs5(0.28, 62) ],
[ 9.33, f4(0.63, 47) ],
[ 9.66, gs4(0.33, 37) ],
[ 10.01, cs5(0.28, 56) ],
[ 10.33, f4(0.43, 43) ],
[ 8.00, gs2(2.74, 54) ],
[ 10.66, gs4(0.12, 49) ],
[ 10.97, controlchange(64, 0) ],
[ 11.07, controlchange(64, 127) ],
[ 10.99, c5(0.29, 72) ],
[ 11.33, c4(0.15, 44) ],
[ 11.00, a2(0.62, 52) ],
[ 11.66, f4(0.12, 48) ],
[ 11.95, controlchange(64, 0) ],
[ 12.07, controlchange(64, 127) ],
[ 12.00, cs5(0.35, 64) ],
[ 12.33, cs4(0.16, 33) ],
[ 12.66, f4(0.32, 28) ],
[ 13.00, cs5(0.29, 61) ],
[ 13.33, cs4(0.20, 38) ],
[ 13.66, f4(0.30, 38) ],
[ 13.99, cs5(0.27, 59) ],
[ 14.33, cs4(0.30, 33) ],
[ 14.66, f4(0.02, 44) ],
[ 12.00, as2(2.73, 38) ],
[ 14.97, controlchange(64, 0) ],
[ 14.92, fs4(0.08, 48) ],
[ 15.07, controlchange(64, 127) ],
[ 15.01, ds5(0.39, 69) ],
[ 15.00, fs2(0.55, 43) ],
[ 15.33, fs4(0.28, 37) ],
[ 15.66, as4(0.12, 43) ],
[ 15.95, controlchange(64, 0) ],
[ 16.06, controlchange(64, 127) ],
[ 16.00, f5(0.33, 63) ],
[ 16.33, gs4(0.53, 32) ],
[ 16.66, cs5(0.29, 26) ],
[ 17.00, f5(0.40, 55) ],
[ 17.33, gs4(0.37, 41) ],
[ 17.66, cs5(0.32, 36) ],
[ 18.00, f5(0.62, 65) ],
[ 16.00, gs2(2.70, 48) ],
[ 18.66, cs5(0.04, 37) ],
[ 18.33, gs4(0.44, 32) ],
[ 18.99, controlchange(64, 0) ],
[ 19.08, controlchange(64, 127) ],
[ 19.00, a2(0.53, 62) ],
[ 18.99, ds5(0.58, 62) ],
[ 19.33, fs4(0.28, 11) ],
[ 19.66, c5(0.36, 48) ],
[ 20.02, controlchange(64, 0) ],
[ 20.13, controlchange(64, 127) ],
[ 20.00, cs5(0.28, 54) ],
[ 20.33, f4(0.58, 38) ],
[ 20.66, as4(0.33, 37) ],
[ 20.99, cs5(0.29, 48) ],
[ 21.33, f4(0.60, 37) ],
[ 21.66, as4(0.31, 41) ],
[ 21.99, cs5(0.35, 58) ],
[ 22.33, f4(0.41, 27) ],
[ 20.0, as2(2.75, 52) ],
[ 22.66, as4(0.30, 48) ],
[ 23.02, controlchange(64, 0) ],
[ 23.12, controlchange(64, 127) ],
[ 23.0, ds5(0.40, 77) ],
[ 23.33, fs4(0.34, 42) ],
[ 23.00, fs2(0.68, 48) ],
[ 23.66, as4(0.29, 43) ],
[ 23.99, controlchange(64, 0) ],
[ 24.10, controlchange(64, 127) ],
[ 24.00, cs5(0.28, 61) ],
[ 24.33, f4(0.62, 38) ],
[ 24.66, gs4(0.38, 37) ],
[ 25.00, cs5(0.26, 54) ],
[ 25.33, f4(0.59, 42) ],
[ 25.66, gs4(0.34, 38) ],
[ 25.99, cs5(0.31, 56) ],
[ 24.0, gs2(2.70, 52) ],
[ 26.33, f4(0.38, 42) ],
[ 26.66, gs4(0.11, 46) ],
[ 26.97, controlchange(64, 0) ],
[ 27.06, controlchange(64, 127) ],
[ 27.0, c5(0.30, 60) ],
[ 27.33, ds4(0.34, 29) ],
[ 27.0, gs2(0.70, 48) ],
[ 27.66, fs4(0.32, 51) ],
[ 28.02, controlchange(64, 0) ],
[ 28.12, controlchange(64, 127) ],
[ 28.0, cs5(0.29, 54) ],
[ 28.33, f4(0.44, 34) ],
[ 28.66, gs4(0.36, 33) ],
[ 28.99, cs5(0.26, 48) ],
[ 29.33, f4(0.32, 27) ],
[ 29.66, gs4(0.33, 42) ],
[ 30.00, cs5(0.15, 46) ],
[ 30.33, gs4(0.32, 36) ],
[ 30.66, cs5(0.32, 43) ],
[ 31.01, f5(0.23, 55) ],
[ 31.33, cs5(0.37, 37) ],
[ 28.0, cs3(3.83, 37) ],
[ 31.66, f5(0.18, 59) ],
[ 32.00, controlchange(64, 0) ]]);
const strings = () => createTrack(1).play([[ 0.05, controlchange(64, 127) ],
[ 0.02, f5(2.52, 43) ],
[ 0.01, f4(2.54, 49) ],
[ 0.01, cs3(2.78, 53) ],
[ 3.11, controlchange(64, 0) ],
[ 3.27, controlchange(64, 127) ],
[ 2.97, gs4(0.59, 59) ],
[ 2.97, ds5(0.71, 58) ],
[ 2.98, c5(0.71, 60) ],
[ 2.98, gs2(0.78, 49) ],
[ 4.06, controlchange(64, 0) ],
[ 5.07, controlchange(64, 127) ],
[ 3.93, f4(2.63, 60) ],
[ 3.94, as2(2.63, 48) ],
[ 3.93, as4(2.65, 62) ],
[ 3.93, cs5(2.70, 52) ],
[ 7.06, controlchange(64, 0) ],
[ 7.40, controlchange(64, 127) ],
[ 6.97, as4(0.67, 69) ],
[ 6.98, fs4(0.69, 68) ],
[ 6.97, ds5(0.74, 62) ],
[ 6.98, fs3(0.83, 54) ],
[ 8.05, controlchange(64, 0) ],
[ 9.08, controlchange(64, 127) ],
[ 8.00, f4(2.54, 60) ],
[ 8.01, gs3(2.62, 48) ],
[ 7.99, gs4(2.65, 58) ],
[ 7.99, cs5(2.68, 54) ],
[ 11.03, controlchange(64, 0) ],
[ 11.45, controlchange(64, 127) ],
[ 10.98, f4(0.97, 62) ],
[ 10.98, a3(1.01, 59) ],
[ 10.98, c5(1.04, 63) ],
[ 12.08, controlchange(64, 0) ],
[ 14.06, controlchange(64, 127) ],
[ 12.02, f4(2.41, 2) ],
[ 12.05, as4(2.41, 43) ],
[ 12.04, as3(2.43, 37) ],
[ 12.05, cs5(2.46, 41) ],
[ 15.12, controlchange(64, 0) ],
[ 15.58, controlchange(64, 127) ],
[ 15.02, fs4(0.72, 62) ],
[ 15.02, as4(0.72, 58) ],
[ 15.02, ds5(0.74, 56) ],
[ 15.04, fs3(0.80, 44) ],
[ 16.04, controlchange(64, 0) ],
[ 17.11, controlchange(64, 127) ],
[ 16.02, f5(2.64, 59) ],
[ 16.01, gs4(2.67, 63) ],
[ 16.02, cs5(2.66, 59) ],
[ 16.02, gs3(2.79, 52) ],
[ 19.08, controlchange(64, 0) ],
[ 19.30, controlchange(64, 127) ],
[ 19.00, a3(0.92, 47) ],
[ 18.98, c5(0.97, 77) ],
[ 18.99, ds5(1.02, 59) ],
[ 20.07, controlchange(64, 0) ],
[ 21.09, controlchange(64, 127) ],
[ 20.01, as4(2.34, 72) ],
[ 20.01, as3(2.40, 54) ],
[ 20.00, cs5(2.42, 69) ],
[ 23.07, controlchange(64, 0) ],
[ 23.41, controlchange(64, 127) ],
[ 22.98, as4(0.60, 53) ],
[ 22.99, fs4(0.64, 61) ],
[ 22.98, ds5(0.67, 56) ],
[ 23.01, fs3(0.65, 47) ],
[ 24.02, controlchange(64, 0) ],
[ 25.18, controlchange(64, 127) ],
[ 23.96, f4(2.51, 60) ],
[ 23.96, cs5(2.63, 54) ],
[ 23.96, gs4(2.63, 58) ],
[ 23.98, gs3(2.74, 43) ],
[ 27.10, controlchange(64, 0) ],
[ 27.42, controlchange(64, 127) ],
[ 27.04, c5(0.62, 72) ],
[ 27.03, fs4(0.66, 72) ],
[ 27.03, gs2(0.68, 56) ],
[ 28.07, controlchange(64, 0) ],
[ 28.00, f4(3.96, 54) ],
[ 28.02, cs3(3.96, 38) ],
[ 28.00, cs5(3.99, 48) ]]);
const flute = () => createTrack(6).play([[ 2.68, cs6(0.12, 81) ],
[ 2.84, ds6(0.10, 84) ],
[ 3.01, ds6(0.10, 82) ],
[ 3.10, f6(0.50, 77) ],
[ 3.62, ds6(0.09, 54) ],
[ 3.72, f6(0.07, 57) ],
[ 3.79, ds6(0.10, 76) ],
[ 3.90, cs6(1.33, 68) ],
[ 6.58, ds6(0.08, 81) ],
[ 6.64, f6(0.11, 77) ],
[ 6.82, gs6(0.12, 91) ],
[ 7.05, gs6(0.11, 69) ],
[ 7.08, as6(0.51, 76) ],
[ 7.60, gs6(0.07, 57) ],
[ 7.68, as6(0.09, 83) ],
[ 7.76, gs6(0.07, 66) ],
[ 7.84, f6(0.10, 64) ],
[ 7.96, gs6(1.0, 91) ],
[ 10.57, gs6(0.09, 81) ],
[ 10.63, as6(0.13, 63) ],
[ 10.84, cs7(0.11, 94) ],
[ 11.04, ds7(0.42, 77) ],
[ 11.72, ds7(0.08, 91) ],
[ 11.78, f7(0.11, 82) ],
[ 11.86, ds7(0.13, 72) ],
[ 12.00, cs7(0.95, 92) ],
[ 12.95, as6(1.00, 58) ],
[ 15.58, cs7(0.08, 92) ],
[ 15.73, cs7(0.07, 96) ],
[ 15.79, ds7(0.09, 68) ],
[ 15.91, cs7(0.09, 87) ],
[ 16.10, ds7(0.12, 77) ],
[ 16.16, f7(0.23, 54) ],
[ 16.41, gs7(0.17, 89) ],
[ 16.60, f7(1.28, 59) ],
[ 18.60, ds7(0.07, 49) ],
[ 18.66, f7(0.11, 65) ],
[ 18.74, ds7(0.08, 69) ],
[ 18.84, cs7(0.12, 72) ],
[ 19.0, ds7(0.54, 59) ],
[ 19.68, f7(0.12, 55) ],
[ 19.77, ds7(0.12, 59) ],
[ 19.88, cs7(0.20, 73) ],
[ 20.12, as6(1.5, 46) ],
[ 22.56, gs6(0.12, 69) ],
[ 22.74, f6(0.07, 65) ],
[ 22.93, gs6(0.07, 81) ],
[ 22.99, as6(0.60, 69) ],
[ 23.58, gs6(0.07, 51) ],
[ 23.67, as6(0.11, 69) ],
[ 23.76, gs6(0.09, 63) ],
[ 23.85, f6(2.21, 59) ],
[ 26.81, ds6(0.06, 59) ],
[ 26.88, f6(0.06, 65) ],
[ 26.95, ds6(0.06, 77) ],
[ 27.03, cs6(0.06, 83) ],
[ 27.11, ds6(0.39, 86) ],
[ 27.63, ds6(0.07, 56) ],
[ 27.69, f6(0.08, 63) ],
[ 27.77, ds6(0.12, 73) ],
[ 27.98, cs6(2.45, 58) ]]);
const bass = () => createTrack(4).play([[ 0.00, cs2(2.92, 81) ],
[ 2.99, gs2(0.84, 73) ],
[ 3.88, a2(0.10, 64) ],
[ 3.98, as2(2.96, 69) ],
[ 6.92, gs2(0.08, 47) ],
[ 7.02, fs2(1.00, 68) ],
[ 8.02, gs2(2.93, 72) ],
[ 11.00, a2(0.94, 77) ],
[ 12.00, as2(2.91, 62) ],
[ 14.94, gs2(0.04, 48) ],
[ 15.08, fs2(0.93, 78) ],
[ 16.00, gs2(1.87, 64) ],
[ 17.88, cs3(0.11, 56) ],
[ 18.01, gs3(0.96, 97) ],
[ 19.00, a2(1.01, 83) ],
[ 20.00, as2(1.93, 66) ],
[ 21.94, f2(0.11, 70) ],
[ 22.02, as2(0.11, 72) ],
[ 22.32, as2(0.35, 64) ],
[ 22.66, gs2(0.35, 68) ],
[ 23.04, fs2(0.96, 77) ],
[ 24.00, gs2(2.91, 72) ],
[ 26.93, cs3(0.11, 52) ],
[ 27.03, gs3(0.99, 87) ],
[ 28.03, cs3(1.92, 66) ],
[ 29.95, gs2(0.06, 56) ],
[ 30.02, cs2(1.91, 81) ]]);
const beatloop = async () => {
for (var n=0;n<8;n++) {
await beat();
}
};
const cymbalsandbeatloop = async () => {
for (var n=0;n<8;n++) {
cymbals();
await beat();
}
};
bass();
piano();
await beatloop();
piano();
bass();
strings();
flute();
await beatloop();
const guitar = () => createTrack(3).play([
[ 1.33, f5(0.17, 68) ],
[ 1.5, gs5(0.21, 63) ],
[ 1.66, as5(0.15, 64) ],
[ 1.83, cs6(0.21, 62) ],
[ 2.00, as5(0.64, 65) ],
[ 2.66, gs5(0.17, 66) ],
[ 2.83, f5(0.06, 67) ],
[ 3.00, gs5(0.12, 67) ],
[ 3.10, as5(0.58, 68) ],
[ 3.65, gs5(0.33, 66) ],
[ 4.00, f5(2.25, 69) ],
[ 6.66, ds5(0.13, 70) ],
[ 6.83, cs5(0.04, 56) ],
[ 7.0, ds5(0.33, 67) ],
[ 7.58, ds5(0.07, 52) ],
[ 7.66, f5(0.07, 65) ],
[ 7.75, ds5(0.10, 72) ],
[ 7.91, cs5(0.14, 44) ],
[ 8.00, as4(0.14, 66) ],
[ 8.17, gs4(1.57, 69) ],
[ 9.99, ds5(0.05, 67) ],
[ 10.02, f5(0.36, 68) ],
[ 10.36, fs5(0.30, 66) ],
[ 10.66, f5(0.35, 64) ],
[ 11.00, ds5(0.16, 66) ],
[ 11.34, ds5(0.10, 63) ],
[ 11.40, f5(0.28, 66) ],
[ 11.69, ds5(0.08, 62) ],
[ 11.77, f5(0.07, 65) ],
[ 11.83, ds5(0.12, 68) ],
[ 12.0, cs5(1.79, 62) ],
[ 14.69, c5(0.14, 72) ],
[ 14.84, c5(0.03, 53) ],
[ 14.91, cs5(0.11, 68) ],
[ 15.04, c5(0.03, 74) ],
[ 15.06, as4(0.52, 73) ],
[ 15.58, c5(0.14, 70) ],
[ 15.72, cs5(0.17, 59) ],
[ 15.86, ds5(0.15, 51) ],
[ 16.11, f5(1.55, 73) ],
[ 17.64, gs5(0.11, 73) ],
[ 17.83, gs5(0.10, 71) ],
[ 17.90, as5(0.12, 74) ],
[ 17.99, gs5(0.54, 74) ],
[ 18.50, as5(0.19, 71) ],
[ 18.68, cs6(0.12, 72) ],
[ 18.87, ds6(0.07, 73) ],
[ 19.10, ds6(0.09, 59) ],
[ 19.19, e6(0.02, 15) ],
[ 19.18, f6(0.55, 75) ],
[ 19.72, ds6(0.07, 64) ],
[ 19.81, f6(0.06, 68) ],
[ 19.86, ds6(0.07, 66) ],
[ 19.93, cs6(0.10, 71) ],
[ 20.06, as5(0.12, 69) ],
[ 20.18, cs6(0.19, 43) ],
[ 20.38, as5(2.02, 63) ],
[ 22.36, gs5(0.30, 78) ],
[ 22.36, cs5(0.30, 78) ],
[ 22.68, f5(0.09, 69) ],
[ 22.97, gs5(0.11, 68) ],
[ 23.04, fs5(0.66, 77) ],
[ 23.04, as5(0.66, 77) ],
[ 23.69, gs5(0.09, 68) ],
[ 23.78, as5(0.11, 62) ],
[ 23.86, gs5(0.10, 56) ],
[ 24.0, gs4(2.29, 68) ],
[ 24.0, f5(2.29, 68) ],
[ 26.70, ds5(0.12, 76) ],
[ 26.86, cs5(0.03, 15) ],
[ 27.01, cs5(0.08, 71) ],
[ 27.08, ds5(0.59, 74) ],
[ 27.08, gs4(0.59, 64) ],
[ 27.74, f5(0.10, 60) ],
[ 27.83, ds5(0.06, 77) ],
[ 27.90, cs5(0.12, 56) ],
[ 28.0, as4(0.03, 64) ],
[ 28.17, cs4(2.34, 44) ],
[ 28.17, cs5(2.34, 54) ]]);
const upperpiano = () => createTrack(0).play([[ 0.05, controlchange(64, 127) ],
[ 0.0, f6(0.30, 79) ],
[ 0.33, gs5(0.34, 63) ],
[ 0.66, cs6(0.31, 44) ],
[ 1.0, f6(0.26, 62) ],
[ 1.33, gs5(0.33, 37) ],
[ 1.66, cs6(0.32, 36) ],
[ 2.0, f6(0.28, 60) ],
[ 2.33, gs5(0.28, 33) ],
[ 2.66, cs6(0.07, 33) ],
[ 2.96, controlchange(64, 0) ],
[ 2.93, fs5(0.04, 37) ],
[ 3.04, controlchange(64, 127) ],
[ 3.00, ds6(0.33, 78) ],
[ 3.32, fs5(0.33, 43) ],
[ 3.66, c6(0.30, 43) ],
[ 3.96, controlchange(64, 0) ],
[ 4.06, controlchange(64, 127) ],
[ 4.00, cs6(0.28, 63) ],
[ 4.36, f5(0.36, 48) ],
[ 4.66, as5(0.31, 44) ],
[ 5.00, cs6(0.30, 54) ],
[ 5.33, f5(0.60, 39) ],
[ 5.66, as5(0.34, 42) ],
[ 6.01, cs6(0.28, 59) ],
[ 6.34, f5(0.33, 28) ],
[ 6.68, as5(0.09, 51) ],
[ 6.92, controlchange(64, 0) ],
[ 6.93, fs5(0.07, 61) ],
[ 7.03, controlchange(64, 127) ],
[ 7.02, ds6(0.29, 83) ],
[ 7.32, fs5(0.36, 41) ],
[ 7.69, as5(0.08, 51) ],
[ 7.97, controlchange(64, 0) ],
[ 8.06, controlchange(64, 127) ],
[ 8.03, f6(0.32, 62) ],
[ 8.36, gs5(0.56, 37) ],
[ 8.66, cs6(0.31, 38) ],
[ 9.00, f6(0.32, 65) ],
[ 9.34, gs5(0.40, 29) ],
[ 9.67, cs6(0.32, 42) ],
[ 10.01, f6(0.32, 68) ],
[ 10.35, gs5(0.36, 24) ],
[ 10.68, cs6(0.36, 32) ],
[ 11.04, controlchange(64, 0) ],
[ 11.12, controlchange(64, 127) ],
[ 11.03, ds6(0.27, 68) ],
[ 11.34, a5(0.34, 54) ],
[ 11.68, c6(0.20, 49) ],
[ 12.00, controlchange(64, 0) ],
[ 12.10, controlchange(64, 127) ],
[ 12.03, cs6(0.31, 59) ],
[ 12.37, f5(0.34, 38) ],
[ 12.68, as5(0.29, 36) ],
[ 13.00, cs6(0.29, 51) ],
[ 13.35, f5(0.34, 34) ],
[ 13.70, as5(0.29, 41) ],
[ 14.03, cs6(0.29, 42) ],
[ 14.35, f5(0.32, 37) ],
[ 14.69, as5(0.15, 49) ],
[ 14.93, controlchange(64, 0) ],
[ 14.95, fs5(0.04, 59) ],
[ 15.04, controlchange(64, 127) ],
[ 15.04, ds6(0.28, 71) ],
[ 15.33, fs5(0.33, 51) ],
[ 15.67, as5(0.09, 38) ],
[ 16.01, controlchange(64, 0) ],
[ 16.01, gs5(0.02, 15) ],
[ 16.10, controlchange(64, 127) ],
[ 16.08, f6(0.28, 65) ],
[ 16.39, gs5(0.46, 33) ],
[ 16.72, cs6(0.25, 38) ],
[ 17.02, f6(0.24, 43) ],
[ 17.32, gs5(0.33, 28) ],
[ 17.64, cs6(0.31, 48) ],
[ 18.00, f6(0.24, 60) ],
[ 18.34, gs5(0.33, 36) ],
[ 18.68, cs6(0.16, 54) ],
[ 19.00, controlchange(64, 0) ],
[ 19.08, controlchange(64, 127) ],
[ 19.02, fs6(0.28, 69) ],
[ 19.32, a5(0.32, 54) ],
[ 19.66, c6(0.24, 54) ],
[ 19.98, controlchange(64, 0) ],
[ 20.09, controlchange(64, 127) ],
[ 20.04, cs6(0.58, 48) ],
[ 20.47, f5(0.22, 27) ],
[ 20.70, as5(0.30, 51) ],
[ 21.04, controlchange(64, 0) ],
[ 21.10, controlchange(64, 127) ],
[ 21.01, cs6(0.32, 56) ],
[ 21.37, f5(0.35, 32) ],
[ 21.67, as5(0.33, 36) ],
[ 22.01, cs6(0.30, 53) ],
[ 22.36, f5(0.29, 29) ],
[ 22.67, as5(0.12, 42) ],
[ 22.89, controlchange(64, 0) ],
[ 22.99, controlchange(64, 127) ],
[ 22.91, fs5(0.08, 51) ],
[ 23.01, ds6(0.30, 71) ],
[ 23.32, fs5(0.34, 37) ],
[ 23.66, as5(0.20, 44) ],
[ 23.94, controlchange(64, 0) ],
[ 24.05, controlchange(64, 127) ],
[ 23.99, cs6(0.28, 56) ],
[ 24.31, f5(0.33, 44) ],
[ 24.65, gs5(0.31, 38) ],
[ 25.00, cs6(0.31, 62) ],
[ 25.33, f5(0.33, 42) ],
[ 25.65, gs5(0.33, 43) ],
[ 26.02, cs6(0.31, 62) ],
[ 26.33, f5(0.33, 37) ],
[ 26.68, gs5(0.12, 56) ],
[ 26.96, controlchange(64, 0) ],
[ 27.06, controlchange(64, 127) ],
[ 27.00, c6(0.32, 60) ],
[ 27.36, ds5(0.29, 41) ],
[ 27.65, fs5(0.32, 49) ],
[ 28.03, controlchange(64, 0) ],
[ 28.09, controlchange(64, 127) ],
[ 28.28, cs5(0.72, 42) ],
[ 28.68, f5(0.36, 39) ],
[ 29.02, gs5(0.28, 58) ],
[ 29.63, f5(0.34, 35) ],
[ 30.00, cs6(0.25, 62) ],
[ 30.36, f5(0.37, 35) ],
[ 30.69, gs5(0.28, 24) ],
[ 31.01, cs6(0.27, 57) ],
[ 31.35, f5(0.32, 23) ],
[ 31.68, gs5(0.10, 48) ],
[ 31.81, controlchange(64, 0) ]]);
const toms = () => createTrack(2).play([[ 29.56, b5(0.07, 87) ],
[ 29.69, b5(0.06, 83) ],
[ 30.00, b5(0.01, 100) ],
[ 30.53, a5(0.07, 64) ],
[ 30.67, a5(0.06, 97) ],
[ 30.99, a5(0.27, 90) ],
[ 31.35, g5(0.28, 100) ],
[ 31.70, f5(0.24, 97) ]]);
piano();
bass();
strings();
choir();
toms();
const crecendingCymbals = [];
for (var n=4/12;n<1;n+=1/12) {
crecendingCymbals.push([n+31, cs6(1/12, n * 70)]);
}
createTrack(2).play(crecendingCymbals);
await beatloop();
upperpiano();
strings();
bass();
guitar();
choir();
await cymbalsandbeatloop();
flute();
createTrack(0).play([[ 0.34, controlchange(64, 127) ],
[ 0.02, f5(2.59, 60) ],
[ 0.02, cs3(2.60, 49) ],
[ 0.02, f4(2.61, 53) ],
[ 0.01, cs5(2.63, 57) ],
[ 3.15, controlchange(64, 0) ],
[ 3.34, controlchange(64, 127) ],
[ 3.10, gs2(0.48, 38) ],
[ 3.09, ds5(0.54, 38) ],
[ 3.08, fs4(0.56, 44) ],
[ 3.10, c5(0.59, 43) ],
[ 4.07, controlchange(64, 0) ],
[ 6.00, controlchange(64, 127) ],
[ 4.06, f4(2.29, 29) ],
[ 4.06, as2(2.30, 38) ],
[ 4.08, as4(2.35, 23) ],
[ 4.04, cs5(2.43, 28) ],
[ 7.06, controlchange(64, 0) ],
[ 7.56, controlchange(64, 127) ],
[ 7.10, fs2(0.62, 36) ],
[ 7.08, fs4(0.66, 49) ],
[ 7.08, as4(0.67, 49) ],
[ 7.08, ds5(0.68, 48) ],
[ 8.04, controlchange(64, 0) ],
[ 10.02, controlchange(64, 127) ],
[ 8.02, cs5(2.37, 37) ],
[ 8.03, f5(2.37, 35) ],
[ 8.02, gs4(2.38, 36) ],
[ 8.02, gs2(2.43, 41) ],
[ 11.14, controlchange(64, 0) ],
[ 11.35, controlchange(64, 127) ],
[ 11.11, a2(0.43, 47) ],
[ 11.09, c5(0.49, 55) ],
[ 11.09, a5(0.48, 53) ],
[ 11.10, f5(0.49, 49) ],
[ 12.02, controlchange(64, 0) ],
[ 13.97, controlchange(64, 127) ],
[ 12.07, as2(2.31, 26) ],
[ 12.06, f5(2.43, 39) ],
[ 12.04, cs5(2.55, 26) ],
[ 12.06, as5(2.57, 29) ],
[ 15.11, controlchange(64, 0) ],
[ 15.20, controlchange(64, 127) ],
[ 14.96, as5(0.49, 48) ],
[ 14.98, fs5(0.51, 42) ],
[ 14.96, cs5(0.54, 36) ],
[ 15.02, fs3(0.51, 15) ],
[ 16.08, controlchange(64, 0) ],
[ 18.13, controlchange(64, 127) ],
[ 16.07, cs5(2.27, 37) ],
[ 16.08, gs5(2.28, 43) ],
[ 16.09, f3(2.66, 22) ],
[ 18.94, controlchange(64, 0) ],
[ 19.08, controlchange(64, 127) ],
[ 18.88, a4(0.33, 47) ],
[ 18.87, a5(0.38, 49) ],
[ 18.90, ds5(0.39, 37) ],
[ 18.90, f5(0.40, 43) ],
[ 18.90, a3(0.53, 30) ],
[ 19.94, controlchange(64, 0) ],
[ 21.96, controlchange(64, 127) ],
[ 19.95, as2(2.32, 13) ],
[ 19.92, f5(2.45, 24) ],
[ 19.81, cs5(2.58, 11) ],
[ 19.93, as5(2.48, 47) ],
[ 23.07, controlchange(64, 0) ],
[ 23.43, controlchange(64, 127) ],
[ 23.02, fs2(0.57, 36) ],
[ 23.00, as5(0.60, 57) ],
[ 23.00, cs5(0.61, 49) ],
[ 23.92, controlchange(64, 0) ],
[ 26.10, controlchange(64, 127) ],
[ 23.96, cs3(2.54, 31) ],
[ 23.97, f5(2.63, 24) ],
[ 23.94, cs5(2.68, 36) ],
[ 23.94, gs5(2.69, 31) ],
[ 27.21, controlchange(64, 0) ],
[ 27.66, controlchange(64, 127) ],
[ 27.23, fs5(0.55, 53) ],
[ 27.23, c5(0.55, 44) ],
[ 27.22, gs2(0.60, 42) ],
[ 28.10, controlchange(64, 0) ],
[ 28.14, f5(3.55, 34) ],
[ 28.14, gs4(3.56, 28) ],
[ 28.15, cs2(3.55, 24) ]]);
createTrack(2).steps(6, [cs6(3.0,60)]);
const endbeat = () => createTrack(2).steps(12, [
[f5(0.1)],,,,,,,,,,,,
,,,,,,,,,,,,
[f5(0.1)],,,,,,,,,,,,
,,,,,,,,,,b5(0.05,10),a5(0.05,40),
]);
await endbeat();
await endbeat();
await endbeat();
await endbeat();
await endbeat();
await endbeat();
await endbeat();
await createTrack(2).steps(3, [
[f5],,,,,,,,,,,,]);
loopHere();
/*
* (c) Peter Johan Salomonsen 2022
*/
import { DelayLineFloat, outputline, CustomExciterWaveGuide, Comb, MonoAudioPlayer, hardclip, AuxExciterWaveGuide, allocateAudioBuffer, LoPassBiQuadFilter, HiPassBiQuadFilter, noise, Freeverb, WaveGuide, AllPassFloat, beatToFrame, AudioPlayer, cos, outputline, Limiter, TriangleOscillator, PI, sin, cos, FFT, EQBand, TriBandEQ, EnvelopeState, Pan, SineOscillator, IFFTOscillator, BiQuadFilter, FilterType, Q_BUTTERWORTH, DelayLine, BandPass,SawOscillator,softclip, midichannels, MidiChannel, MidiVoice, StereoSignal, SineOscillator, Envelope } from '../mixes/globalimports';
import { SAMPLERATE } from '../environment';
const BPM: f32 = 122;
function notefreq(note: f32): f32 {
return 440 * Mathf.pow(2, (-69 + note) / 12);
}
const delayframes = (SAMPLERATE * (6/8) * 50 / BPM) as usize;
const echoLeft = new DelayLine(delayframes);
const echoRight = new DelayLine(delayframes);
const echoline = new StereoSignal();
class MultiBandEQ {
bands: StaticArray<EQBand>;
constructor(freqs: f32[]) {
this.bands = new StaticArray<EQBand>(freqs.length - 1);
for ( let n=1; n<freqs.length; n++) {
this.bands[n-1] = new EQBand(freqs[n-1], freqs[n]);
}
}
process(signal: f32, levels: f32[]): f32 {
let ret: f32 = 0;
for (let n = 0;n<this.bands.length; n++) {
ret += this.bands[n].process(signal) * levels[n];
}
return ret;
}
}
export class WaveGuideFeedbackLimit {
envExciter: Envelope;
filterExciter: BiQuadFilter = new BiQuadFilter();
delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);
filterFeedback: BiQuadFilter = new BiQuadFilter();
feedbackLevel: f32;
feedbackFilterFreq: f32;
freq: f32;
exciterenvlevel: f32;
constructor(exciterAttack: f32, exciterRelease: f32, exciterFilterFreq: f32, feedbackLevel: f32) {
this.envExciter = new Envelope(exciterAttack,
exciterRelease, 0,
exciterRelease);
this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,
exciterFilterFreq, Q_BUTTERWORTH);
this.feedbackLevel = feedbackLevel;
}
setFilterExciterFreq(freq: f32): void {
this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,
freq, Q_BUTTERWORTH);
}
start(freq: f32, feedbackFilterFreq: f32): void {
if (freq != this.freq) {
this.freq = freq;
const maxFeedbackFilterFreq: f32 = 20000;
if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {
feedbackFilterFreq = maxFeedbackFilterFreq as f32;
} else if (feedbackFilterFreq < 10) {
feedbackFilterFreq = 10;
}
this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,
feedbackFilterFreq, Q_BUTTERWORTH);
this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);
const filterphase = this.filterFeedback.coeffs.phaseSamples;
this.filterFeedback.clearBuffers();
this.filterExciter.clearBuffers();
this.feedbackFilterFreq = feedbackFilterFreq;
this.delay.setNumFramesAndClear(
(SAMPLERATE /
(freq)
) - filterphase
);
this.envExciter.val = 0;
}
this.exciterenvlevel = 1;
this.envExciter.attack();
}
process(): f32 {
const envexciter = this.envExciter.next() * this.exciterenvlevel;
let exciterSignal: f32 = noise() * envexciter;
exciterSignal = this.filterExciter.process(exciterSignal);
const feedback = this.delay.read();
let signal = exciterSignal + feedback;
signal = this.filterFeedback.processForm2(signal);
this.delay.write_and_advance(
Mathf.tanh(signal * this.feedbackLevel)
);
return signal;
}
}
export class BandPassWaveGuide {
envExciter: Envelope;
filterExciter: BiQuadFilter = new BiQuadFilter();
delay: DelayLineFloat = new DelayLineFloat((SAMPLERATE / notefreq(1)) as i32);
hipass: HiPassBiQuadFilter = new HiPassBiQuadFilter();
filterFeedback: BiQuadFilter = new BiQuadFilter();
feedbackLevel: f32;
feedbackFilterFreq: f32;
freq: f32;
exciterenvlevel: f32;
constructor(exciterAttack: f32, exciterRelease: f32, exciterFilterFreq: f32, feedbackLevel: f32) {
this.envExciter = new Envelope(exciterAttack,
exciterRelease, 0,
exciterRelease);
this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,
exciterFilterFreq, Q_BUTTERWORTH);
this.feedbackLevel = feedbackLevel;
}
setFilterExciterFreq(freq: f32): void {
this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,
freq, Q_BUTTERWORTH);
}
start(freq: f32, feedbackFilterFreq: f32): void {
freq*=1.6;
if (freq != this.freq) {
this.freq = freq;
const maxFeedbackFilterFreq: f32 = 20000;
if (feedbackFilterFreq > maxFeedbackFilterFreq as f32) {
feedbackFilterFreq = maxFeedbackFilterFreq as f32;
} else if (feedbackFilterFreq < 10) {
feedbackFilterFreq = 10;
}
this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE,
feedbackFilterFreq, Q_BUTTERWORTH);
this.hipass.update(freq * 0.5 , 0.93);
this.hipass.coeffs.calculatePhaseAndMagnitudeForFreq(freq);
this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);
const filterphase = this.filterFeedback.coeffs.phaseSamples +
this.hipass.coeffs.phaseSamples;
this.hipass.clearBuffers();
this.filterFeedback.clearBuffers();
this.filterExciter.clearBuffers();
this.feedbackFilterFreq = feedbackFilterFreq;
this.delay.setNumFramesAndClear(
(SAMPLERATE /
(freq)
) - filterphase
);
this.envExciter.val = 0;
}
this.exciterenvlevel = 1;
this.envExciter.attack();
}
process(): f32 {
const envexciter = this.envExciter.next() * this.exciterenvlevel;
let exciterSignal: f32 = noise() * envexciter;
exciterSignal = this.filterExciter.process(exciterSignal);
const feedback = this.delay.read();
let signal = exciterSignal + feedback;
signal = this.filterFeedback.processForm2(signal);
signal = this.hipass.process(signal);
this.delay.write_and_advance(
Mathf.tanh(signal * this.feedbackLevel)
);
return signal;
}
}
export class PianoExciterWaveGuide {
filterExciter: BiQuadFilter = new BiQuadFilter();
hipass: BiQuadFilter = new BiQuadFilter();
freq: f32;
t: f32;
constructor() {
}
start(lo: f32): void {
this.freq = lo;
this.t = 0;
this.filterExciter.clearBuffers();
this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,
20 + lo, Q_BUTTERWORTH);
this.hipass.clearBuffers();
this.hipass.update_coeffecients(FilterType.HighPass, SAMPLERATE,
110, Q_BUTTERWORTH);
}
process(): f32 {
const env = Mathf.pow(100000, -this.t);
// shorter gives longer feedback
this.t += Mathf.PI * 0.24/ SAMPLERATE;
let signal: f32 = noise();
signal *= env;
this.filterExciter.update_coeffecients(FilterType.LowPass, SAMPLERATE,
20 + (this.freq * env), Q_BUTTERWORTH);
signal = this.filterExciter.process(signal);
signal = this.hipass.process(signal);
return signal;
}
}
class PianoWaveGuide extends WaveGuide {
exciterWaveGuide: PianoExciterWaveGuide = new PianoExciterWaveGuide();
allpasses: StaticArray<AllPassFloat> = new StaticArray<AllPassFloat>(12);
hipass: BiQuadFilter = new BiQuadFilter();
note: u8;
level: f32;
constructor() {
super(0.001,0.06,100,0.2);
for(let n=0;n<this.allpasses.length;n++) {
this.allpasses[n] = new AllPassFloat();
}
}
start2(note: u8, velocity: u8): void {
this.note = note;
const velocitylevel = (velocity as f32 / 127);
const freq: f32 = notefreq(note);
this.exciterWaveGuide.start((1 + (note * 0.00)) * velocity * 30 as f32);
let feedbackFilterFreq: f32 = (10000 + note * 120) as f32;
//if (feedbackFilterFreq < 4000) feedbackFilterFreq = 4000;
//if (feedbackFilterFreq > 13000) feedbackFilterFreq = 13000;
this.filterFeedback.update_coeffecients(FilterType.LowPass, SAMPLERATE, feedbackFilterFreq, Q_BUTTERWORTH);
this.filterFeedback.coeffs.calculatePhaseAndMagnitudeForFreq(freq);
if (freq != this.freq) {
for(let n=0;n<this.allpasses.length;n++) {
this.allpasses[n].setDelta(16.0 - (note as f32/ 127) * 11);
this.allpasses[n].clearBuffers();
}
this.hipass.clearBuffers();
this.hipass.update_coeffecients(FilterType.HighPass, SAMPLERATE,
130 + freq * 0.1 as f32, Q_BUTTERWORTH);
this.filterFeedback.clearBuffers();
this.delay.setNumFramesAndClear(
(SAMPLERATE /
(freq)
)
//- ((D as f32) * (this.allpasses.length as f32))
- this.filterFeedback.coeffs.phaseSamples
);
}
let feedbacklevel: f32 = 0.999 - 0.7 / Mathf.pow(freq,1.0) as f32;
if (feedbacklevel > 0.999) {
feedbacklevel = 0.999;
} else if (feedbacklevel < 0) {
feedbacklevel = 0;
}
this.feedbackLevel = feedbacklevel;
this.freq = freq;
}
process(): f32 {
let exciterSignal: f32 = this.exciterWaveGuide.process() ;
let feedback = this.delay.read();
let signal = exciterSignal;
signal+=this.filterFeedback.process(feedback);
this.delay.write_and_advance(
signal * this.feedbackLevel
);
for(let n=0;n<this.allpasses.length;n++) signal += this.allpasses[n].process(signal);
signal = this.hipass.process(signal);
return signal * 0.003;
}
}
class Piano extends MidiVoice {
env: Envelope = new Envelope(0.001, 0.17, 1.0, 0.17);
waveguide1: PianoWaveGuide = new PianoWaveGuide();
waveguide2: PianoWaveGuide = new PianoWaveGuide();
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
this.waveguide1.start2(note, velocity);
this.waveguide2.start2(note, velocity);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
let env = this.env.next();
const wg1: f32 = this.waveguide1.process() * env;
const wg2: f32 = this.waveguide2.process() * env;
this.channel.signal.add(wg1, wg2);
}
}
class String extends MidiVoice {
env: Envelope = new Envelope(0.001, 1, 0.9, 0.3);
waveguide1: WaveGuide = new WaveGuide(0.01, 20.0, 610, 0.995);
waveguide2: WaveGuide = new WaveGuide(0.01, 20.0, 620, 0.995);
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq = notefreq(note);
this.waveguide1.start(freq, freq * 4000 / Mathf.pow(note, 1.3) );
this.waveguide2.start(freq, freq * 4000 / Mathf.pow(note, 1.3) );
this.env.attack();
}
noteoff(): void {
this.env.release();
this.waveguide1.envExciter.releaseStep = 0.05;
this.waveguide2.envExciter.releaseStep = 0.05;
this.waveguide1.envExciter.release();
this.waveguide2.envExciter.release();
}
isDone(): boolean {
return this.env.isDone() &&
this.waveguide1.envExciter.isDone() &&
this.waveguide2.envExciter.isDone();
}
nextframe(): void {
const env:f32 = this.env.next() * this.velocity * 0.01;
const left =
this.waveguide1.process()
* env;
const right =
this.waveguide2.process()
* env;
this.channel.signal.add(
left, right
);
}
}
class Brass extends MidiVoice {
env: Envelope = new Envelope(0.01, 1.0, 1.0, 0.1);
waveguide1: WaveGuide = new WaveGuide(0.02, 0.15, 1000, 0.99999);
waveguide2: WaveGuide = new WaveGuide(0.03, 0.2, 5000, 1.0);
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq = notefreq(note);
this.waveguide1.start(freq, freq * 10);
this.waveguide2.start(freq, freq * 8);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next();
let signal = (
this.waveguide1.process() +
this.waveguide2.process()
)
* env * this.velocity / 127 as f32;
this.channel.signal.add(
signal, signal
);
}
}
class Guitar extends MidiVoice {
env: Envelope = new Envelope(0.002, 1, 1.0, 0.1);
waveguide1: WaveGuide = new WaveGuide(0.002, 0.03, 5000, 0.999);
waveguide2: WaveGuide = new WaveGuide(0.002, 0.03, 5000, 0.999);
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq = notefreq(note);
this.waveguide1.start(freq * 1.001, freq * 3000 / Mathf.pow(note, 1.28) );
this.waveguide2.start(freq * 0.999, freq * 3000 / Mathf.pow(note, 1.28) );
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next();
const signal = ((
this.waveguide1.process()
)
* env * this.velocity * 0.04) as f32;
const signal2 = ((
this.waveguide2.process()
)
* env * this.velocity * 0.04) as f32;
this.channel.signal.add(
signal, signal2
);
}
}
class GuitarChannel extends MidiChannel {
bandpassleft: BandPass = new BandPass(150,4000);
bandpassright: BandPass = new BandPass(150,4000);
feedbackleft: f32 = 0;
feedbackright: f32 = 0;
preprocess(): void {
let left = this.signal.left;
let right = this.signal.right;
const feedbackleft = this.feedbackleft;
const feedbackright = this.feedbackleft;
left = softclip(left * 0.5);
right = softclip(right * 0.5);
this.feedbackleft += this.bandpassleft.process(left * 1.5);
this.feedbackright += this.bandpassright.process(right * 1.5);
left += feedbackleft;
left *= 0.5;
right += feedbackright;
right *= 0.5;
echoline.left += (left) * this.volume;
echoline.right += (right) * this.volume;
this.signal.left = left;
this.signal.right = right;
}
}
class Bass extends MidiVoice {
env: Envelope = new Envelope(0.001, 1, 1.0, 0.1);
waveguide1: WaveGuide = new WaveGuide(0.001, 0.01, 200, 0.999);
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq = notefreq(note);
this.waveguide1.start(freq, freq * 8000 / Mathf.pow(note, 1.7));
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next();
const signal = (
this.waveguide1.process()
)
* env * this.velocity * 0.25 as f32;
this.channel.signal.add(
signal, signal
);
}
}
class TubeLead extends MidiVoice {
env: Envelope = new Envelope(0.05, 1, 1.0, 0.1);
waveguide1: WaveGuideFeedbackLimit = new WaveGuideFeedbackLimit(0.001, 0.01,200, -1.12);
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq = notefreq(note);
this.waveguide1.start(freq, 230 * Mathf.pow(freq, 0.36 ));
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next() * 0.02;
const signal = (
this.waveguide1.process()
)
* env * this.velocity as f32;
this.channel.signal.add(
signal, signal
);
}
}
class FluteChannel extends MidiChannel {
preprocess(): void {
let signal = this.signal.left;
echoline.left += (signal) * this.volume;
echoline.right += (signal) * this.volume;
}
}
class Flute extends MidiVoice {
env: Envelope = new Envelope(0.05, 1, 1.0, 0.01);
waveguide1: BandPassWaveGuide = new BandPassWaveGuide(0.001, 0.01,150, -1.1);
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq = notefreq(note);
this.waveguide1.start(freq, 80 * Mathf.pow(freq, 0.5 ));
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next() * 0.01;
const signal = (
this.waveguide1.process()
)
* env * this.velocity as f32;
this.channel.signal.add(
signal, signal
);
}
}
class HihatGuide extends WaveGuide {
allpasses: StaticArray<AllPassFloat> = new StaticArray<AllPassFloat>(3);
constructor(attack: f32, decay: f32, feedbackfreq: f32, feedback: f32) {
super(attack, decay, feedbackfreq, feedback);
for(var n=0;n<this.allpasses.length;n++) {
this.allpasses[n] = new AllPassFloat();
this.allpasses[n].setDelta(5);
}
}
process(): f32 {
const envexciter = this.envExciter.next() * this.exciterenvlevel;
let exciterSignal: f32 = noise() * envexciter;
exciterSignal = this.filterExciter.process(exciterSignal);
const feedback = this.delay.read();
let signal = exciterSignal + feedback;
for(let n=0;n<this.allpasses.length;n++) signal = this.allpasses[n].process(signal);
signal = this.filterFeedback.processForm2(signal);
this.delay.write_and_advance(
signal * this.feedbackLevel
);
return signal;
}
}
class Hihat extends MidiVoice {
env: Envelope = new Envelope(0.0001, 1, 1.0, 0.2);
waveguide1: HihatGuide = new HihatGuide(0.012, 0.06, 20000, 0.6);
waveguide2: HihatGuide = new HihatGuide(0.012, 0.06, 20000, 0.6);
constructor(channel: MidiChannel) {
super(channel);
this.minnote = 66;
this.maxnote = 66;
}
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq: f32 = 7200;
this.waveguide1.start(freq, 20000);
this.waveguide2.start(freq, 20000);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next() * 0.04 * this.velocity / 30;;
let left = (
this.waveguide1.process()
)
* env as f32;
let right = (
this.waveguide2.process()
)
* env as f32;
this.channel.signal.add(
left, right
);
}
}
class OpenHihat extends MidiVoice {
env: Envelope = new Envelope(0.0001, 1, 1.0, 0.2);
waveguide1: HihatGuide = new HihatGuide(0.001, 0.5, 20000, 0.85);
waveguide2: HihatGuide = new HihatGuide(0.001, 0.5, 20000, 0.85);
constructor(channel: MidiChannel) {
super(channel);
this.minnote = 68;
this.maxnote = 68;
}
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq: f32 = 7200;
this.waveguide1.start(freq, 20000);
this.waveguide2.start(freq, 20000);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next() * 0.04 * this.velocity / 30;
let left = (
this.waveguide1.process()
)
* env as f32;
let right = (
this.waveguide2.process()
)
* env as f32;
this.channel.signal.add(
left, right
);
}
}
class KickGuide extends WaveGuide {
allpasses: StaticArray<AllPassFloat> = new StaticArray<AllPassFloat>(4);
constructor(attack: f32, decay: f32, feedbackfreq: f32, feedback: f32) {
super(attack, decay, feedbackfreq, feedback);
for(var n=0;n<this.allpasses.length;n++) {
this.allpasses[n] = new AllPassFloat();
this.allpasses[n].setDelta(20);
}
}
start(freq:f32, filterfreq: f32):void {
super.start(freq,filterfreq);
//this.filterExciter.clearBuffers();
//this.filterFeedback.clearBuffers();
for(var n=0;n<this.allpasses.length;n++) {
//this.allpasses[n].clearBuffers();
}
}
process(): f32 {
const envexciter = this.envExciter.next() * this.exciterenvlevel;
let exciterSignal: f32 = noise() * envexciter;
exciterSignal = this.filterExciter.process(exciterSignal);
const feedback = this.delay.read();
let signal = exciterSignal + feedback;
for(let n=0;n<this.allpasses.length;n++) signal = this.allpasses[n].process(signal);
signal = this.filterFeedback.processForm2(signal);
this.delay.write_and_advance(
signal * this.feedbackLevel
);
return signal;
}
}
class Kick2 extends MidiVoice {
env: Envelope = new Envelope(0.0001, 1, 1.0, 0.4);
waveguide1: KickGuide = new KickGuide(0.001, 0.1, 80, 0.5);
waveguide2: KickGuide = new KickGuide(0.001, 0.1, 80, 0.5);
chasingvelocity: f32 = 0;
constructor(channel: MidiChannel) {
super(channel);
this.minnote = 60;
this.maxnote = 60;
}
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq: f32 = 1000;
this.waveguide1.start(freq * 1.0001, 300);
this.waveguide2.start(freq * 0.9999, 300);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next() * 0.46 * this.chasingvelocity;
this.chasingvelocity += (this.velocity - this.chasingvelocity) * 0.01;
const left = (
this.waveguide1.process()
)
* env as f32;
const right = (
this.waveguide2.process()
)
* env as f32;
this.channel.signal.add(
left, right
);
}
}
class SnareGuide extends WaveGuide {
allpasses: StaticArray<AllPassFloat> = new StaticArray<AllPassFloat>(6);
constructor(attack: f32, decay: f32, feedbackfreq: f32, feedback: f32) {
super(attack, decay, feedbackfreq, feedback);
for(var n=0;n<this.allpasses.length;n++) {
this.allpasses[n] = new AllPassFloat();
this.allpasses[n].setDelta(15);
}
}
process(): f32 {
const envexciter = this.envExciter.next() * this.exciterenvlevel;
let exciterSignal: f32 = noise() * envexciter;
exciterSignal = this.filterExciter.process(exciterSignal);
const feedback = this.delay.read();
let signal = exciterSignal + feedback;
for(let n=0;n<this.allpasses.length;n++) signal = this.allpasses[n].process(signal);
signal = this.filterFeedback.processForm2(signal);
this.delay.write_and_advance(
signal * this.feedbackLevel
);
return signal;
}
}
class Snare2 extends MidiVoice {
env: Envelope = new Envelope(0.005, 0.5, 0.1, 0.3);
waveguide1: SnareGuide = new SnareGuide(0.005, 0.2, 10000, 0.8);
waveguide2: SnareGuide = new SnareGuide(0.005, 0.2, 10000, 0.8);
constructor(channel: MidiChannel) {
super(channel);
this.minnote = 62;
this.maxnote = 62;
}
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq: f32 = 1400;
this.waveguide1.start(freq, 1660);
this.waveguide2.start(freq, 1660);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next() * 1.6 * this.velocity as f32 / 127 as f32;
let left = (
this.waveguide1.process()
)
* env as f32;
let right = (
this.waveguide2.process()
)
* env as f32;
this.channel.signal.add(
left, right
);
}
}
class CymbalGuide extends WaveGuide {
allpasses: StaticArray<AllPassFloat> = new StaticArray<AllPassFloat>(6);
hipass: HiPassBiQuadFilter = new HiPassBiQuadFilter();
constructor(attack: f32, decay: f32, feedbackfreq: f32, feedback: f32) {
super(attack, decay, feedbackfreq, feedback);
for(var n=0;n<this.allpasses.length;n++) {
this.allpasses[n] = new AllPassFloat();
this.allpasses[n].setDelta(11);
}
this.hipass.update_coeffecients(FilterType.HighPass, SAMPLERATE,
1200, Q_BUTTERWORTH);
}
process(): f32 {
const envexciter = this.envExciter.next() * this.exciterenvlevel;
let exciterSignal: f32 = noise() * envexciter;
exciterSignal = this.filterExciter.process(exciterSignal);
const feedback = this.delay.read();
let signal = exciterSignal + feedback;
for(let n=0;n<this.allpasses.length;n++) signal = this.allpasses[n].process(signal);
signal = this.filterFeedback.processForm2(signal);
this.delay.write_and_advance(
signal * this.feedbackLevel
);
signal = this.hipass.process(signal);
return signal * 0.00027;
}
}
class Cymbal extends MidiVoice {
env: Envelope = new Envelope(0.0001, 3.0, 1.0, 3.0);
waveguide1: CymbalGuide = new CymbalGuide(0.001, 0.15, 20000, 0.999);
waveguide2: CymbalGuide = new CymbalGuide(0.001, 0.15, 20000, 0.999);
chasingvelocity: f32 = 0;
constructor(channel: MidiChannel, note: u8) {
super(channel);
this.minnote = note;
this.maxnote = note;
}
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq: f32 = SAMPLERATE / 2;
this.waveguide1.start(freq * 0.95, 20000);
this.waveguide2.start(freq * 1.05, 20000);
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next() * 0.5 * this.chasingvelocity;
this.chasingvelocity += 0.01 * (this.velocity-this.chasingvelocity);
const left = (
this.waveguide1.process()
)
* env as f32;
const right = (
this.waveguide2.process()
)
* env as f32;
this.channel.signal.add(
left, right
);
}
}
class TomGuide extends WaveGuide {
allpasses: StaticArray<AllPassFloat> = new StaticArray<AllPassFloat>(6);
hipass: HiPassBiQuadFilter = new HiPassBiQuadFilter();
constructor(attack: f32, decay: f32, feedbackfreq: f32, feedback: f32) {
super(attack, decay, feedbackfreq, feedback);
for(var n=0;n<this.allpasses.length;n++) {
this.allpasses[n] = new AllPassFloat();
this.allpasses[n].setDelta(20000);
}
this.hipass.update_coeffecients(FilterType.HighPass, SAMPLERATE,
200, Q_BUTTERWORTH);
}
process(): f32 {
const envexciter = this.envExciter.next() * this.exciterenvlevel;
let exciterSignal: f32 = noise() * envexciter;
exciterSignal = this.filterExciter.process(exciterSignal);
const feedback = this.delay.read();
let signal = exciterSignal + feedback;
for(let n=0;n<this.allpasses.length;n++) signal = this.allpasses[n].process(signal);
signal = this.filterFeedback.processForm2(signal);
this.delay.write_and_advance(
signal * this.feedbackLevel
);
signal = this.hipass.process(signal);
return signal * 0.022;
}
}
class Tom extends MidiVoice {
env: Envelope = new Envelope(0.0001, 1, 1.0, 0.4);
waveguide1: TomGuide = new TomGuide(0.002, 0.12, 1000, 0.998);
waveguide2: TomGuide = new TomGuide(0.002, 0.12, 1000, 0.998);
constructor(channel: MidiChannel, note: u8) {
super(channel);
this.minnote = note;
this.maxnote = note;
}
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq: f32 = 20000;
this.waveguide1.start(freq * 0.99, 1600 + ((this.minnote - 65 ) as f32 * 250));
this.waveguide2.start(freq * 1.01, 1600 + ((this.minnote - 65 ) as f32 * 250));
this.env.attack();
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
return this.env.isDone();
}
nextframe(): void {
const env = this.env.next() * 0.5 * this.velocity;
const left = (
this.waveguide1.process()
)
* env as f32;
const right = (
this.waveguide2.process()
)
* env as f32;
this.channel.signal.add(
left, right
);
}
}
class DrumChannel extends MidiChannel {
preprocess(): void {
let left = this.signal.left;
let right = this.signal.right;
//echoline.left += (left) * this.volume;
//echoline.right += (right) * this.volume;
}
}
const fft: FFT = new FFT(11);
for (let n=1; n< (fft.buffer.length / 2) - 1; n+=1) {
let v = Mathf.exp((-n as f32 ) * 0.2) * 1023 * cos((n * 5) as f32);
//fft.buffer[n].re = v;
//fft.buffer[fft.buffer.length - n].re = -v;
fft.buffer[n].im = -v;
fft.buffer[fft.buffer.length - n].im = v;
}
fft.calculateInverse();
class PadSynth extends MidiVoice {
env: Envelope = new Envelope(0.001, 2.5, 0.00, 0.2);
t: f64 = 0;
freq: f32 = 0;
spread: i32 = 9;
hprofile: StaticArray<f32> = new StaticArray<f32>(this.spread);
phase: StaticArray<f32> = new StaticArray<f32>(this.spread);
freqs: StaticArray<f32> = new StaticArray<f32>(this.spread);
level: f32 = 1.0;
constructor(channel: MidiChannel) {
super(channel);
const halfspread: f32 = (this.spread / 2) as f32;
for(let n=0;n<this.spread;n++) {
const v: f32 = 2 as f32 * (
n as f32 - halfspread);
this.hprofile[n] = Mathf.exp(v * -v);
this.phase[n] = noise() * 0x800 as f32;
}
}
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
this.env.attack();
const halfspread: f32 = (this.spread / 2) as f32;
for (let n = 0;n<this.freqs.length; n++) {
const v: f32 = 0.04 as f32 * (n as f32 - halfspread);
this.freqs[n] = notefreq((note + v));
}
this.level = (-(1/(notefreq(note)-200)) + 1) as f32;
}
noteoff(): void {
this.env.release();
}
isDone(): boolean {
const ret = this.env.isDone();
return ret;
}
nextframe(): void {
const env = this.env.next() * this.level;
let left: f32 = 0;
let right: f32 = 0;
const t = this.t;
const freq = this.freq;
for(let n = 0;n < this.spread ; n++) {
const f = this.freqs[n];
const bufferpos = t * 0x800 * f + this.phase[n];
const floorbufferpos = Math.floor(bufferpos);
const delta = (bufferpos - floorbufferpos) as f32;
const v1 = fft.buffer[((bufferpos as i64) & 0x7ff) as i32].re;
const v = v1;
const leftlevel: f32 = (((n) / 2) + 0.5) as f32;
const rightlevel: f32 = (((this.hprofile.length - n) / 2) + 0.5) as f32;
left += v* leftlevel;
right += v* rightlevel;
}
left *= env;
right *= env;
this.t += 1 / SAMPLERATE;
this.channel.signal.add(
left, right
);
}
}
class PadSynthChannel extends MidiChannel {
lopassleft: BiQuadFilter = new BiQuadFilter();
lopassright: BiQuadFilter = new BiQuadFilter();
constructor(numvoices: i32, factoryFunc: (channel: MidiChannel, voiceindex: i32) => MidiVoice) {
super(numvoices, factoryFunc);
this.lopassleft.update_coeffecients(FilterType.LowPass, SAMPLERATE,
4000, 0.3);
this.lopassright.update_coeffecients(FilterType.LowPass, SAMPLERATE,
4000, 0.3);
}
preprocess(): void {
let left = this.signal.left;
let right = this.signal.right;
const gain:f32 = 0.04;
left*=gain;
right*=gain;
left = this.lopassleft.process(left);
right = this.lopassright.process(right);
//echoline.left += (left * 0.1);
//echoline.right += (right * 0.1);
this.signal.left = left;
this.signal.right = right;
}
}
class Choir extends MidiVoice {
env: Envelope = new Envelope(0.05, 1, 1.0, 0.3);
waveguide1: CustomExciterWaveGuide = new CustomExciterWaveGuide();
waveguide2: CustomExciterWaveGuide = new CustomExciterWaveGuide();
exciterEnv: Envelope = new Envelope(0.15, 0.2, 0.6, 0.3);
saw: SawOscillator = new SawOscillator();
lopass: LoPassBiQuadFilter = new LoPassBiQuadFilter();
noteon(note: u8, velocity: u8): void {
super.noteon(note, velocity);
const freq = notefreq(note);
this.saw.frequency = freq ;
this.waveguide1.feedbackLevel = -1;
this.waveguide2.feedbackLevel = -1;
this.waveguide1.start(freq, Mathf.log(freq * 0.01) * 2000);
this.waveguide2.start(freq * 2.0, Mathf.log(freq * 0.01) * 2000);
this.lopass.update(2500,0.6);
this.env.attack();
this.exciterEnv.attack();
}
noteoff(): void {
this.env.release();
this.exciterEnv.release();
}
isDone(): boolean {
return this.env.isDone() && this.exciterEnv.isDone();
}
nextframe(): void {
const env = this.env.next() * 0.003;
const exciterSignal = this.lopass.process((noise()) * this.exciterEnv.next());
this.waveguide1.exciterSignal = exciterSignal;
this.waveguide2.exciterSignal = exciterSignal;
const signal1 = this.waveguide1.process();
const signal2 = this.waveguide2.process();
const left = (signal2 + signal1 * 0.6 ) * env * this.velocity as f32;
const right = (signal1 + signal2 * 0.6) * env * this.velocity as f32;
this.channel.signal.add(
left, right
);
}
}
export function initializeMidiSynth(): void {
midichannels[0] = new MidiChannel(10, (ch) => new Piano(ch));
midichannels[0].controlchange(7, 50);
midichannels[0].controlchange(10, 64);
midichannels[0].controlchange(91,52);
midichannels[1] = new MidiChannel(10, (ch) => new String(ch));
midichannels[1].controlchange(7,61);
midichannels[1].controlchange(10, 64);
midichannels[1].controlchange(91, 50);
midichannels[2] = new DrumChannel(9, (ch, ndx) => {
switch(ndx) {
case 1:
return new Hihat(ch);
case 2:
return new Snare2(ch);
case 3:
return new OpenHihat(ch);
case 4:
return new Tom(ch, 65);
case 5:
return new Tom(ch, 67);
case 6:
return new Tom(ch, 69);
case 7:
return new Tom(ch, 71);
case 8:
return new Cymbal(ch, 73);
default:
return new Kick2(ch);
}
});
midichannels[2].controlchange(7, 120);
midichannels[2].controlchange(91, 70);
midichannels[3] = new GuitarChannel(6, (ch) => new Guitar(ch));
midichannels[3].controlchange(7, 42);
midichannels[3].controlchange(10, 64);
midichannels[3].controlchange(91, 65);
midichannels[4] = new MidiChannel(2, (ch) => new Bass(ch));
midichannels[4].controlchange(7, 90);
midichannels[4].controlchange(10, 64);
midichannels[4].controlchange(91, 20);
midichannels[5] = new MidiChannel(1, (ch) => new TubeLead(ch));
midichannels[5].controlchange(7, 30);
midichannels[5].controlchange(10, 50);
midichannels[5].controlchange(91, 40);
midichannels[6] = new FluteChannel(1, (ch) => new Flute(ch));
midichannels[6].controlchange(7, 80);
midichannels[6].controlchange(10, 70);
midichannels[6].controlchange(91, 60);
midichannels[7] = new PadSynthChannel(15, (ch) => new PadSynth(ch));
midichannels[7].controlchange(7, 60);
midichannels[7].controlchange(10, 64);
midichannels[7].controlchange(91, 50);
midichannels[8] = new MidiChannel(5, (ch) => new Brass(ch));
midichannels[8].controlchange(7, 40);
midichannels[8].controlchange(10, 32);
midichannels[8].controlchange(91, 40);
midichannels[9] = new MidiChannel(10, (ch) => new Choir(ch));
midichannels[9].controlchange(7, 49);
midichannels[9].controlchange(10, 64);
midichannels[9].controlchange(91, 75);
}
const eqfreqs: f32[] = [20,50,150,20000]
const eqlevels: f32[] = [1.0, 1.0,1.0];
const eqleft = new MultiBandEQ(eqfreqs);
const eqright = new MultiBandEQ(eqfreqs);
export function postprocess(): void {
const gain: f32 = 0.55;
let left = outputline.left;
let right = outputline.right;
const echol = echoLeft.read() * 0.3;
const echor = echoRight.read() * 0.3;
echoLeft.write_and_advance(echol + echoline.left);
echoRight.write_and_advance(echor + echoline.right);
left+=echol;
right+=echor;
left = eqleft.process(left, eqlevels);
right = eqright.process(right, eqlevels);
left*=gain;
right*=gain;
outputline.left = left;
outputline.right = right;
echoline.clear();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment