Created
May 21, 2022 06:17
-
-
Save petersalomonsen/9f13d0071940df891c253ee022f083ba to your computer and use it in GitHub Desktop.
WebAssembly Music - Veronika's Waltz
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* (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