From be94a2d55ec3b14adc979ac6f12411669510778c Mon Sep 17 00:00:00 2001 From: slarmoo Date: Fri, 19 Sep 2025 12:27:12 -0600 Subject: [PATCH 1/2] live-editor-typeless --- .vscode/settings.json | 3 + editor/TipPrompt.ts | 12 +- live_editor_typeless.sh | 24 ++ package-lock.json | 491 ++++++++++++++++++++++++++++++++-- package.json | 4 +- synth/SynthConfig.ts | 391 +++++++++++++-------------- tsconfig_recovery_player.json | 2 +- 7 files changed, 709 insertions(+), 218 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 live_editor_typeless.sh diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6f3a291 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} \ No newline at end of file diff --git a/editor/TipPrompt.ts b/editor/TipPrompt.ts index c0b0aaf..6c36670 100644 --- a/editor/TipPrompt.ts +++ b/editor/TipPrompt.ts @@ -442,12 +442,12 @@ export class TipPrompt implements Prompt { p("The range of the pitch shift bar goes from -1 octave [-12 semitones] at the very left side of the bar, and +1 octave [+12 semitones] at the very right. The very middle of the bar is the default pitch. If you want to change the key of more than one of your instruments at once, try song key!"), ); } break; - case "detune": { - message = div( - h2("Detune"), - p("This setting slightly adjusts the frequency of notes played by the instrument. You can use a little bit to add a shifting sound similar to the \"unison\" setting when combined with other instruments. If you use too much, then the instrument may sound unpleasantly out-of-tune. This setting can also, when appiled to the grand majority of instruments, change the feel of your song, even if ever so slightly."), - ); - } break; + // case "detune": { + // message = div( + // h2("Detune"), + // p("This setting slightly adjusts the frequency of notes played by the instrument. You can use a little bit to add a shifting sound similar to the \"unison\" setting when combined with other instruments. If you use too much, then the instrument may sound unpleasantly out-of-tune. This setting can also, when appiled to the grand majority of instruments, change the feel of your song, even if ever so slightly."), + // ); + // } break; case "wavefold": { message = div( h2("Wavefolding"), diff --git a/live_editor_typeless.sh b/live_editor_typeless.sh new file mode 100644 index 0000000..4b0d071 --- /dev/null +++ b/live_editor_typeless.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -e + +# Defaults to opening index_debug.html in a browser, but that can be disabled +# by passing the argument --headless, like this: +# npm run live-editor-fast-typeless -- --headless +open_browser_path=/index_debug.html +for arg in "$@"; do + case "$arg" in + '--headless') open_browser_path=false;; + esac +done + +# This is similar to live_editor.sh, but instead of compiling with tsc and +# bundling with rollup, this uses esbuild for both. It uses less resources and +# is faster. However, this doesn't check type safety at all! Also, the generated +# JS output has some slight differences, so check the other build strategies +# before publishing updates. +npx concurrently \ + "npx esbuild --format=iife --keep-names --global-name=beepbox --bundle ./synth/synth.js --outfile=website/beepbox_synth.js --sourcemap --watch" \ + "npx esbuild --format=iife --keep-names --global-name=beepbox --bundle ./player/main.js --outfile=website/player/beepbox_player.min.js --sourcemap --watch" \ + "npx esbuild --format=iife --keep-names --global-name=beepbox --bundle ./recovery_player/main.js --outfile=website/recovery_player/beepbox_recovery_player.min.js --sourcemap --watch" \ + "npx esbuild --format=iife --keep-names --global-name=beepbox --bundle ./editor/main.js --outfile=website/beepbox_editor.js --sourcemap --watch" \ + "npx five-server --wait=200 --watch=website --port=4100 --open=$open_browser_path website/" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d6e1b26..3ea9a66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@types/jquery": "^3.5.5", "@types/select2": "^4.0.53", + "esbuild": "^0.25.10", "imperative-html": "^0.1.0", "select2": "^4.0.13" }, @@ -22,6 +23,422 @@ "typescript": "^4.9.5" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -205,10 +622,11 @@ "dev": true }, "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10" } @@ -222,6 +640,47 @@ "node": ">=0.10.0" } }, + "node_modules/esbuild": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" + } + }, "node_modules/estree-walker": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", @@ -229,12 +688,12 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -285,10 +744,11 @@ "dev": true }, "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" }, "node_modules/picomatch": { "version": "2.2.2", @@ -316,10 +776,11 @@ } }, "node_modules/rollup": { - "version": "2.32.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.32.1.tgz", - "integrity": "sha512-Op2vWTpvK7t6/Qnm1TTh7VjEZZkN8RWgf0DHbkKzQBwNf748YhXbozHVefqpPp/Fuyk/PQPAnYsBxAEtlMvpUw==", + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, + "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -327,7 +788,7 @@ "node": ">=10.0.0" }, "optionalDependencies": { - "fsevents": "~2.1.2" + "fsevents": "~2.3.2" } }, "node_modules/rollup-plugin-sourcemaps": { diff --git a/package.json b/package.json index 65f89ee..7ab006d 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "build-synth": "bash ./compile_beepbox_synth.sh", "build-player": "bash ./compile_beepbox_player.sh", "build-editor": "bash ./compile_beepbox_editor.sh", - "build-recovery_player": "bash ./compile_beepbox_recovery_player.sh" + "build-recovery_player": "bash ./compile_beepbox_recovery_player.sh", + "let": "bash ./live_editor_typeless.sh" }, "repository": { "type": "git", @@ -27,6 +28,7 @@ "dependencies": { "@types/jquery": "^3.5.5", "@types/select2": "^4.0.53", + "esbuild": "^0.25.10", "imperative-html": "^0.1.0", "select2": "^4.0.13" } diff --git a/synth/SynthConfig.ts b/synth/SynthConfig.ts index 2f2b8cb..ec5df64 100644 --- a/synth/SynthConfig.ts +++ b/synth/SynthConfig.ts @@ -716,7 +716,7 @@ export class Config { public static readonly upperBoundMin: number = 0; public static readonly upperBoundMax: number = 8; public static readonly envelopeDelayMax: number = 32; - public static readonly envelopePhaseMax: number = this.envelopeDelayMax / 2; + public static readonly envelopePhaseMax: number = Config.envelopeDelayMax / 2; public static readonly clapMirrorsMax: number = 32; public static readonly LFOAccelerationMin: number = 0.25; public static readonly LFOAccelerationMax: number = 4; @@ -858,7 +858,155 @@ export class Config { public static readonly unisonSignMax: number = 2; public static readonly sineWaveLength: number = 1 << 8; public static readonly sineWaveMask: number = Config.sineWaveLength - 1; - public static readonly sineWave: Float32Array = generateSineWave(); + public static readonly sineWave: Float32Array = Config.generateSineWave(); + + public static generateSineWave(): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.sin(i * Math.PI * 2 / Config.sineWaveLength); + } + return wave; + } + + public static generateTriWave(): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.asin(Math.sin(i * Math.PI * 2 / Config.sineWaveLength)) / (Math.PI / 2); + } + return wave; + } + + public static generateTrapezoidWave(drive: number = 2): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.max(-1, Math.min(1, Math.asin(Math.sin(i * Math.PI * 2 / Config.sineWaveLength)) * drive)); + } + return wave; + } + + public static generateSquareWave(phaseWidth: number = 0): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + const centerPoint: number = Config.sineWaveLength / 4; + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = +((Math.abs(i - centerPoint) < phaseWidth * Config.sineWaveLength / 2) + || ((Math.abs(i - Config.sineWaveLength - centerPoint) < phaseWidth * Config.sineWaveLength / 2))) * 2 - 1; + } + return wave; + } + + public static generateSawWave(inverse: boolean = false): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = ((i + (Config.sineWaveLength / 4)) * 2 / Config.sineWaveLength) % 2 - 1; + wave[i] = inverse ? -wave[i] : wave[i]; + } + return wave; + } + + public static generateClangNoise() { + let drumBuffer: number = 1; + const wave = new Float32Array(Config.sineWaveLength + 1); + for (let i = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = (drumBuffer & 1) * 2 - 1.0; + let newBuffer: number = drumBuffer >> 1; + if (((drumBuffer + newBuffer) & 1) == 1) { + newBuffer += 2 << 14; + } + drumBuffer = newBuffer; + } + return wave; + } + + public static generateMetallicNoise() { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + let drumBuffer = 1; + for (let j = 0; j < Config.sineWaveLength; j++) { + wave[j] = (drumBuffer & 1) * 1.25 - 0.33; + let newBuffer = drumBuffer >> 1; + if (((drumBuffer + newBuffer) & 1) == 1) { + newBuffer -= 10 << 2; + } + drumBuffer = newBuffer; + } + } + return wave; + } + + public static generateQuasiSineWave() { + const wave = new Float32Array(Config.sineWaveLength + 1); + for (let i = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.round(Math.sin(i * Math.PI * 2 / Config.sineWaveLength)); + } + return wave; + } + + public static generateSecantWave() { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = 1 - (Math.sin((i / Config.sineWaveLength) * Math.PI * 2) % 2 + 2) % 2; + } + return wave; + } + + public static generateAbsineWave() { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.abs(Math.sin(i * Math.PI / Config.sineWaveLength)) * 2 - 1; + } + return wave; + } + + public static generateSemiSineWave(): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.max(Math.sin(i * Math.PI * 2 / Config.sineWaveLength), 0) * 2 - 1; + } + return wave; + } + + public static generateCamelsineWave(): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.max(Math.cos((2 * i * Math.PI + (Math.PI / 2) * 3) / Config.sineWaveLength) * Math.abs(Math.sin((Math.PI * i * 2 + (Math.PI / 2)) / Config.sineWaveLength)), 0) * 4 - 1; + } + return wave; + } + + public static generatePulsineWave(): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.cos((2 * i * Math.PI) / Config.sineWaveLength) * Math.abs(Math.sin((2 * i * Math.PI) / Config.sineWaveLength)) + (0.5 * Math.sin((4 * i * Math.PI) / Config.sineWaveLength)); + } + return wave; + } + + public static generateSharkSineWave(): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.abs(Math.sin(i * Math.PI / Config.sineWaveLength)) * Math.round(mod((i + 0.5) / Config.sineWaveLength, 1)) * 2 - 1; + } + return wave; + } + + public static generateLogSawWave(): Float32Array { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + let l1: number = mod(Math.PI * 2 * i / Config.sineWaveLength, 2 * Math.PI); + let l2: number = Math.cos(l1 / 2) < 0 ? 1 : -1; + wave[i] = l2 + Math.cos((l1 + Math.PI) / 2) * l2; + } + return wave; + } + + public static generateWhiteNoise() { + const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); + for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { + wave[i] = Math.random() * 2 - 1; + } + return wave; + } + // Picked strings have an all-pass filter with a corner frequency based on the tone fundamental frequency, in order to add a slight inharmonicity. (Which is important for distortion.) public static readonly pickedStringDispersionCenterFreq: number = 6000.0; // The tone fundamental freq is pulled toward this freq for computing the all-pass corner freq. public static readonly pickedStringDispersionFreqScale: number = 0.3; // The tone fundamental freq freq moves this much toward the center freq for computing the all-pass corner freq. @@ -914,56 +1062,56 @@ export class Config { ]); public static readonly operatorWaves: DictionaryArray = toNameMap([ - { name: "sine", samples: Config.sineWave }, - { name: "triangle", samples: generateTriWave() }, - { name: "sawtooth", samples: generateSawWave() }, - { name: "pulse width", samples: generateSquareWave() }, - { name: "ramp", samples: generateSawWave(true) }, - { name: "trapezoid", samples: generateTrapezoidWave(2) }, - { name: "clang", samples: generateClangNoise() }, - { name: "metallic", samples: generateMetallicNoise() }, - { name: "quasi-sine", samples: generateQuasiSineWave() }, - { name: "secant", samples: generateSecantWave() }, - { name: "absine", samples: generateAbsineWave() }, - { name: "semisine", samples: generateSemiSineWave() }, - { name: "camelsine", samples: generateCamelsineWave() }, - { name: "pulsine", samples: generatePulsineWave() }, - { name: "sharksine", samples: generateSharkSineWave() }, - { name: "logarithmic saw", samples: generateLogSawWave() }, - { name: "white noise", samples: generateWhiteNoise() }, + { name: "sine", samples: Config.sineWave }, + { name: "triangle", samples: Config.generateTriWave() }, + { name: "sawtooth", samples: Config.generateSawWave() }, + { name: "pulse width", samples: Config.generateSquareWave() }, + { name: "ramp", samples: Config.generateSawWave(true) }, + { name: "trapezoid", samples: Config.generateTrapezoidWave(2) }, + { name: "clang", samples: Config.generateClangNoise() }, + { name: "metallic", samples: Config.generateMetallicNoise() }, + { name: "quasi-sine", samples: Config.generateQuasiSineWave() }, + { name: "secant", samples: Config.generateSecantWave() }, + { name: "absine", samples: Config.generateAbsineWave() }, + { name: "semisine", samples: Config.generateSemiSineWave() }, + { name: "camelsine", samples: Config.generateCamelsineWave() }, + { name: "pulsine", samples: Config.generatePulsineWave() }, + { name: "sharksine", samples: Config.generateSharkSineWave() }, + { name: "logarithmic saw", samples: Config.generateLogSawWave() }, + { name: "white noise", samples: Config.generateWhiteNoise() }, ]); // Kept for compatibility. public static readonly pwmOperatorWaves: DictionaryArray = toNameMap([ - { name: "1%", samples: generateSquareWave(0.01) }, - { name: "2.5%", samples: generateSquareWave(0.025) }, - { name: "5%", samples: generateSquareWave(0.05) }, - { name: "6.25%", samples: generateSquareWave(0.0625) }, - { name: "10%", samples: generateSquareWave(0.10) }, - { name: "12.5%", samples: generateSquareWave(0.125) }, - { name: "15%", samples: generateSquareWave(0.15) }, - { name: "17.5%", samples: generateSquareWave(0.175) }, - { name: "20%", samples: generateSquareWave(0.20) }, - { name: "25%", samples: generateSquareWave(0.25) }, - { name: "30%", samples: generateSquareWave(0.30) }, - { name: "33%", samples: generateSquareWave(1 / 3) }, - { name: "40%", samples: generateSquareWave(0.40) }, - { name: "45%", samples: generateSquareWave(0.45) }, - { name: "50%", samples: generateSquareWave(0.5) }, - { name: "55%", samples: generateSquareWave(0.55) }, - { name: "60%", samples: generateSquareWave(0.60) }, - { name: "66%", samples: generateSquareWave(2 / 3) }, - { name: "70%", samples: generateSquareWave(0.70) }, - { name: "75%", samples: generateSquareWave(0.75) }, - { name: "80%", samples: generateSquareWave(0.80) }, - { name: "82.5%", samples: generateSquareWave(0.825) }, - { name: "85%", samples: generateSquareWave(0.85) }, - { name: "87.5%", samples: generateSquareWave(0.875) }, - { name: "90%", samples: generateSquareWave(0.90) }, - { name: "93.75%", samples: generateSquareWave(0.9375) }, - { name: "95%", samples: generateSquareWave(0.95) }, - { name: "97.5%", samples: generateSquareWave(0.975) }, - { name: "99%", samples: generateSquareWave(0.99) }, + { name: "1%", samples: Config.generateSquareWave(0.01) }, + { name: "2.5%", samples: Config.generateSquareWave(0.025) }, + { name: "5%", samples: Config.generateSquareWave(0.05) }, + { name: "6.25%", samples: Config.generateSquareWave(0.0625) }, + { name: "10%", samples: Config.generateSquareWave(0.10) }, + { name: "12.5%", samples: Config.generateSquareWave(0.125) }, + { name: "15%", samples: Config.generateSquareWave(0.15) }, + { name: "17.5%", samples: Config.generateSquareWave(0.175) }, + { name: "20%", samples: Config.generateSquareWave(0.20) }, + { name: "25%", samples: Config.generateSquareWave(0.25) }, + { name: "30%", samples: Config.generateSquareWave(0.30) }, + { name: "33%", samples: Config.generateSquareWave(1 / 3) }, + { name: "40%", samples: Config.generateSquareWave(0.40) }, + { name: "45%", samples: Config.generateSquareWave(0.45) }, + { name: "50%", samples: Config.generateSquareWave(0.5) }, + { name: "55%", samples: Config.generateSquareWave(0.55) }, + { name: "60%", samples: Config.generateSquareWave(0.60) }, + { name: "66%", samples: Config.generateSquareWave(2 / 3) }, + { name: "70%", samples: Config.generateSquareWave(0.70) }, + { name: "75%", samples: Config.generateSquareWave(0.75) }, + { name: "80%", samples: Config.generateSquareWave(0.80) }, + { name: "82.5%", samples: Config.generateSquareWave(0.825) }, + { name: "85%", samples: Config.generateSquareWave(0.85) }, + { name: "87.5%", samples: Config.generateSquareWave(0.875) }, + { name: "90%", samples: Config.generateSquareWave(0.90) }, + { name: "93.75%", samples: Config.generateSquareWave(0.9375) }, + { name: "95%", samples: Config.generateSquareWave(0.95) }, + { name: "97.5%", samples: Config.generateSquareWave(0.975) }, + { name: "99%", samples: Config.generateSquareWave(0.99) }, ]); // Height of the small editor column for inserting/deleting rows, in pixels. @@ -1508,153 +1656,6 @@ function perlinNoise(p: number): number { return (1.0 - fade_t) * g0 * (p - p0) + fade_t * g1 * (p - p1); } -function generateSineWave(): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.sin(i * Math.PI * 2 / Config.sineWaveLength); - } - return wave; -} - -function generateTriWave(): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.asin(Math.sin(i * Math.PI * 2 / Config.sineWaveLength)) / (Math.PI / 2); - } - return wave; -} - -function generateTrapezoidWave(drive: number = 2): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.max(-1, Math.min(1, Math.asin(Math.sin(i * Math.PI * 2 / Config.sineWaveLength)) * drive)); - } - return wave; -} - -function generateSquareWave(phaseWidth: number = 0): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - const centerPoint: number = Config.sineWaveLength / 4; - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = +((Math.abs(i - centerPoint) < phaseWidth * Config.sineWaveLength / 2) - || ((Math.abs(i - Config.sineWaveLength - centerPoint) < phaseWidth * Config.sineWaveLength / 2))) * 2 - 1; - } - return wave; -} - -function generateSawWave(inverse: boolean = false): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = ((i + (Config.sineWaveLength / 4)) * 2 / Config.sineWaveLength) % 2 - 1; - wave[i] = inverse ? -wave[i] : wave[i]; - } - return wave; -} - -function generateClangNoise() { - let drumBuffer: number = 1; - const wave = new Float32Array(Config.sineWaveLength + 1); - for (let i = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = (drumBuffer & 1) * 2 - 1.0; - let newBuffer: number = drumBuffer >> 1; - if (((drumBuffer + newBuffer) & 1) == 1) { - newBuffer += 2 << 14; - } - drumBuffer = newBuffer; - } - return wave; -} - -function generateMetallicNoise() { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - let drumBuffer = 1; - for (let j = 0; j < Config.sineWaveLength; j++) { - wave[j] = (drumBuffer & 1) * 1.25 - 0.33; - let newBuffer = drumBuffer >> 1; - if (((drumBuffer + newBuffer) & 1) == 1) { - newBuffer -= 10 << 2; - } - drumBuffer = newBuffer; - } - } - return wave; -} - -function generateQuasiSineWave() { - const wave = new Float32Array(Config.sineWaveLength + 1); - for (let i = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.round(Math.sin(i * Math.PI * 2 / Config.sineWaveLength)); - } - return wave; -} - -function generateSecantWave() { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = 1 - (Math.sin((i / Config.sineWaveLength) * Math.PI * 2) % 2 + 2) % 2; - } - return wave; -} - -function generateAbsineWave() { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.abs(Math.sin(i * Math.PI / Config.sineWaveLength)) * 2 - 1; - } - return wave; -} - -function generateSemiSineWave(): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.max(Math.sin(i * Math.PI * 2 / Config.sineWaveLength), 0) * 2 - 1; - } - return wave; -} - -function generateCamelsineWave(): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.max(Math.cos((2 * i * Math.PI + (Math.PI / 2) * 3) / Config.sineWaveLength) * Math.abs(Math.sin((Math.PI * i * 2 + (Math.PI / 2)) / Config.sineWaveLength)), 0) * 4 - 1; - } - return wave; -} - -function generatePulsineWave(): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.cos((2 * i * Math.PI) / Config.sineWaveLength) * Math.abs(Math.sin((2 * i * Math.PI) / Config.sineWaveLength)) + (0.5 * Math.sin((4 * i * Math.PI) / Config.sineWaveLength)); - } - return wave; -} - -function generateSharkSineWave(): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.abs(Math.sin(i * Math.PI / Config.sineWaveLength)) * Math.round(mod((i + 0.5) / Config.sineWaveLength, 1)) * 2 - 1; - } - return wave; -} - -function generateLogSawWave(): Float32Array { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - let l1: number = mod(Math.PI * 2 * i / Config.sineWaveLength, 2 * Math.PI); - let l2: number = Math.cos(l1 / 2) < 0 ? 1 : -1; - wave[i] = l2 + Math.cos((l1 + Math.PI) / 2) * l2; - } - return wave; -} - -function generateWhiteNoise() { - const wave: Float32Array = new Float32Array(Config.sineWaveLength + 1); - for (let i: number = 0; i < Config.sineWaveLength + 1; i++) { - wave[i] = Math.random() * 2 - 1; - } - return wave; -} - export function getArpeggioPitchIndex(pitchCount: number, useFastTwoNoteArp: boolean, arpeggioPatternType: number, arpeggio: number): number { let arpeggioPatternListPicker: any; if (arpeggioPatternType == 0) arpeggioPatternListPicker = (Config.normalArpeggioPatterns)[pitchCount - 1]; diff --git a/tsconfig_recovery_player.json b/tsconfig_recovery_player.json index 423f1ef..7dd335b 100644 --- a/tsconfig_recovery_player.json +++ b/tsconfig_recovery_player.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig_synth_only.json", - "files": [ "recovery_player/main.ts" ], + "files": [ "recovery_player/main.ts" ] } From 62c05b9fa7cc22991b5213eaf31886d8771e54ed Mon Sep 17 00:00:00 2001 From: slarmoo Date: Fri, 19 Sep 2025 13:08:19 -0600 Subject: [PATCH 2/2] fixed drumset env song corruptions --- synth/synth.ts | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/synth/synth.ts b/synth/synth.ts index 0b42d50..62b797d 100644 --- a/synth/synth.ts +++ b/synth/synth.ts @@ -133,11 +133,6 @@ function encodeEnvelopeSettings(buffer: number[], s: number, d: boolean, lb: num } function encodeDrumEnvelopeSettings(buffer: number[], s: number, d: boolean, lb: number, ub: number, dl: number, ph: number, mt: boolean, mi: number, sh: number, LFOState: number, acNum: number, r: number, w: number, sa: number, gridW: number, gridH: number, points: Point[]): void { - // IES (Speed) - let cleanS = Math.round(Math.abs(s) * 1000); - let cleanSDivided = Math.floor(cleanS / 63); - buffer.push(base64IntToCharCode[cleanS % 63], base64IntToCharCode[cleanSDivided % 63], base64IntToCharCode[Math.floor(cleanSDivided / 63)]); - // Place to store all boolean values. Drumsets use two less bits since it doesn't allow pitch envelopes. const booleanBitfield: number = ( (+d << 0) // Discrete @@ -146,26 +141,28 @@ function encodeDrumEnvelopeSettings(buffer: number[], s: number, d: boolean, lb: ); buffer.push(base64IntToCharCode[booleanBitfield]); + // IES (Speed) + let cleanS = Math.round(Math.abs(s) * 1000); + let cleanSDivided = Math.floor(cleanS / 64); + buffer.push(base64IntToCharCode[cleanS % 64], base64IntToCharCode[cleanSDivided % 64], base64IntToCharCode[Math.floor(cleanSDivided / 64)]); + // Lower/Upper Bound let cleanLB = Math.round(Math.abs(lb) * 1000); - let cleanLBDivided = Math.floor(cleanLB / 63); - buffer.push(base64IntToCharCode[cleanLB % 63], base64IntToCharCode[cleanLBDivided % 63], base64IntToCharCode[Math.floor(cleanLBDivided / 63)]); + let cleanLBDivided = Math.floor(cleanLB / 64); + buffer.push(base64IntToCharCode[cleanLB % 64], base64IntToCharCode[cleanLBDivided % 64], base64IntToCharCode[Math.floor(cleanLBDivided / 64)]); let cleanUB = Math.round(Math.abs(ub) * 1000); - let cleanUBDivided = Math.floor(cleanUB / 63); - buffer.push(base64IntToCharCode[cleanUB % 63], base64IntToCharCode[cleanUBDivided % 63], base64IntToCharCode[Math.floor(cleanUBDivided / 63)]); + let cleanUBDivided = Math.floor(cleanUB / 64); + buffer.push(base64IntToCharCode[cleanUB % 64], base64IntToCharCode[cleanUBDivided % 64], base64IntToCharCode[Math.floor(cleanUBDivided / 64)]); // Delay let cleanDL = Math.round(Math.abs(dl) * 1000); - let cleanDLDivided = Math.floor(cleanDL / 63); - buffer.push(base64IntToCharCode[cleanDL % 63], base64IntToCharCode[cleanDLDivided % 63], base64IntToCharCode[Math.floor(cleanDLDivided / 63)]); + let cleanDLDivided = Math.floor(cleanDL / 64); + buffer.push(base64IntToCharCode[cleanDL % 64], base64IntToCharCode[cleanDLDivided % 64], base64IntToCharCode[Math.floor(cleanDLDivided / 64)]); // Phase let cleanPH = Math.round(Math.abs(ph) * 1000); - let cleanPHDivided = Math.floor(cleanPH / 63); - buffer.push(base64IntToCharCode[cleanPH % 63], base64IntToCharCode[cleanPHDivided % 63], base64IntToCharCode[Math.floor(cleanPHDivided / 63)]); - - // Measurement Type - buffer.push(base64IntToCharCode[+mt]); + let cleanPHDivided = Math.floor(cleanPH / 64); + buffer.push(base64IntToCharCode[cleanPH % 64], base64IntToCharCode[cleanPHDivided % 64], base64IntToCharCode[Math.floor(cleanPHDivided / 64)]); // Mirror Amount buffer.push(base64IntToCharCode[mi]); @@ -175,8 +172,8 @@ function encodeDrumEnvelopeSettings(buffer: number[], s: number, d: boolean, lb: // LFO Acceleration Amount let cleanAC = Math.round(Math.abs(acNum) * 1000); - let cleanACDivided = Math.floor(cleanAC / 63); - buffer.push(base64IntToCharCode[cleanAC % 63], base64IntToCharCode[cleanACDivided % 63], base64IntToCharCode[Math.floor(cleanACDivided / 63)]); + let cleanACDivided = Math.floor(cleanAC / 64); + buffer.push(base64IntToCharCode[cleanAC % 64], base64IntToCharCode[cleanACDivided % 64], base64IntToCharCode[Math.floor(cleanACDivided / 64)]); // LFO Trapezoid Ratio buffer.push(base64IntToCharCode[r]);