From d0d739e61ff3cd1c9eba6663792b364b823f4e06 Mon Sep 17 00:00:00 2001 From: JellyBrick Date: Mon, 18 Sep 2023 06:44:48 +0900 Subject: [PATCH] fix: add back butterchurn --- config/defaults.ts | 7 ++- package-lock.json | 63 +++++++++++++++++++ package.json | 2 + plugins/visualizer/butterchurn.d.ts | 53 ++++++++++++++++ plugins/visualizer/front.ts | 8 ++- plugins/visualizer/visualizers/butterchurn.ts | 63 +++++++++++++++++++ 6 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 plugins/visualizer/butterchurn.d.ts create mode 100644 plugins/visualizer/visualizers/butterchurn.ts diff --git a/config/defaults.ts b/config/defaults.ts index 8aeb13cb..1378826e 100644 --- a/config/defaults.ts +++ b/config/defaults.ts @@ -191,8 +191,13 @@ const defaultConfig = { }, 'visualizer': { enabled: false, - type: 'vudio', + type: 'butterchurn', // Config per visualizer + butterchurn: { + preset: 'martin [shadow harlequins shape code] - fata morgana', + renderingFrequencyInMs: 500, + blendTimeInSeconds: 2.7, + }, vudio: { effect: 'lighting', accuracy: 128, diff --git a/package-lock.json b/package-lock.json index 932fb2dc..c6996fd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,8 @@ "@foobar404/wave": "2.0.4", "@xhayper/discord-rpc": "1.0.22", "async-mutex": "0.4.0", + "butterchurn": "2.6.7", + "butterchurn-presets": "2.4.7", "conf": "10.2.0", "custom-electron-prompt": "1.5.7", "custom-electron-titlebar": "4.1.6", @@ -250,6 +252,22 @@ "node": ">=4" } }, + "node_modules/@babel/runtime": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, "node_modules/@cliqz/adblocker": { "version": "1.26.7--canary.50688cf.0", "resolved": "https://registry.npmjs.org/@cliqz/adblocker/-/adblocker-1.26.7--canary.50688cf.0.tgz", @@ -2315,6 +2333,20 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/babel-runtime/node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2560,6 +2592,25 @@ "node": ">=10.16.0" } }, + "node_modules/butterchurn": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/butterchurn/-/butterchurn-2.6.7.tgz", + "integrity": "sha512-BJiRA8L0L2+84uoG2SSfkp0kclBuN+vQKf217pK7pMlwEO2ZEg3MtO2/o+l8Qpr8Nbejg8tmL1ZHD1jmhiaaqg==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "ecma-proposal-math-extensions": "0.0.2" + } + }, + "node_modules/butterchurn-presets": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/butterchurn-presets/-/butterchurn-presets-2.4.7.tgz", + "integrity": "sha512-4MdM8ripz/VfH1BCldrIKdAc/1ryJFBDvqlyow6Ivo1frwj0H3duzvSMFC7/wIjAjxb1QpwVHVqGqS9uAFKhpg==", + "dependencies": { + "babel-runtime": "^6.26.0", + "ecma-proposal-math-extensions": "0.0.2", + "lodash": "^4.17.4" + } + }, "node_modules/cacache": { "version": "17.1.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", @@ -3063,6 +3114,13 @@ "node": ">=10" } }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true + }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -3626,6 +3684,11 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/ecma-proposal-math-extensions": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ecma-proposal-math-extensions/-/ecma-proposal-math-extensions-0.0.2.tgz", + "integrity": "sha512-80BnDp2Fn7RxXlEr5HHZblniY4aQ97MOAicdWWpSo0vkQiISSE9wLR4SqxKsu4gCtXFBIPPzy8JMhay4NWRg/Q==" + }, "node_modules/ejs": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", diff --git a/package.json b/package.json index e6b21e70..c14f1316 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,8 @@ "@foobar404/wave": "2.0.4", "@xhayper/discord-rpc": "1.0.22", "async-mutex": "0.4.0", + "butterchurn": "2.6.7", + "butterchurn-presets": "2.4.7", "conf": "10.2.0", "custom-electron-prompt": "1.5.7", "custom-electron-titlebar": "4.1.6", diff --git a/plugins/visualizer/butterchurn.d.ts b/plugins/visualizer/butterchurn.d.ts new file mode 100644 index 00000000..bd8df9e5 --- /dev/null +++ b/plugins/visualizer/butterchurn.d.ts @@ -0,0 +1,53 @@ +declare module 'butterchurn' { + interface VisualizerOptions { + width?: number; + height?: number; + meshWidth?: number; + meshHeight?: number; + pixelRatio?: number; + textureRatio?: number; + outputFXAA?: boolean; + } + + class Visualizer { + constructor(audioContext: AudioContext, canvas: HTMLCanvasElement, opts: ButterchurnOptions); + loseGLContext(): void; + connectAudio(audioNode: AudioNode): void; + disconnectAudio(audioNode: AudioNode): void; + static overrideDefaultVars(baseValsDefaults: unknown, baseVals: unknown): unknown; + createQVars(): Record; + createTVars(): Record; + createPerFramePool(baseVals: unknown): Record; + createPerPixelPool(baseVals: unknown): Record; + createCustomShapePerFramePool(baseVals: unknown): Record; + createCustomWavePerFramePool(baseVals: unknown): Record; + static makeShapeResetPool(pool: Record, variables: string[], idx: number): Record; + static base64ToArrayBuffer(base64: string): ArrayBuffer; + loadPreset(presetMap: unknown, blendTime?: number): Promise; + async loadWASMPreset(preset: unknown, blendTime: number): Promise; + loadJSPreset(preset: unknown, blendTime: number): void; + loadExtraImages(imageData: unknown): void; + setRendererSize(width: number, height: number, opts?: VisualizerOptions): void; + setInternalMeshSize(width: number, height: number): void; + setOutputAA(useAA: boolean): void; + setCanvas(canvas: HTMLCanvasElement): void; + render(opts?: VisualizerOptions): unknown; + launchSongTitleAnim(text: string): void; + toDataURL(): string; + warpBufferToDataURL(): string; + } + + interface ButterchurnOptions { + width?: number; + height?: number; + onlyUseWASM?: boolean; + } + + export default class Butterchurn { + static createVisualizer(audioContext: AudioContext, canvas: HTMLCanvasElement, options?: ButterchurnOptions): Visualizer; + } +} + +declare module 'butterchurn-presets' { + export function getPresets(): Record; +} diff --git a/plugins/visualizer/front.ts b/plugins/visualizer/front.ts index 9de40808..9274a3cd 100644 --- a/plugins/visualizer/front.ts +++ b/plugins/visualizer/front.ts @@ -2,6 +2,7 @@ import { Visualizer } from './visualizers/visualizer'; import vudio from './visualizers/vudio'; import wave from './visualizers/wave'; +import butterchurn from './visualizers/butterchurn'; import defaultConfig from '../../config/defaults'; @@ -15,7 +16,12 @@ export default (options: ConfigType<'visualizer'>) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any let visualizerType: { new(...args: any[]): Visualizer } = vudio; - if (optionsWithDefaults.type === 'wave') visualizerType = wave; + + if (optionsWithDefaults.type === 'wave') { + visualizerType = wave; + } else if (optionsWithDefaults.type === 'butterchurn') { + visualizerType = butterchurn; + } document.addEventListener( 'audioCanPlay', diff --git a/plugins/visualizer/visualizers/butterchurn.ts b/plugins/visualizer/visualizers/butterchurn.ts new file mode 100644 index 00000000..de9b8058 --- /dev/null +++ b/plugins/visualizer/visualizers/butterchurn.ts @@ -0,0 +1,63 @@ +import Butterchurn from 'butterchurn'; +import ButterchurnPresets from 'butterchurn-presets'; + +import { Visualizer } from './visualizer'; + +import { ConfigType } from '../../../config/dynamic'; + +const presets = ButterchurnPresets.getPresets(); + +class ButterchurnVisualizer extends Visualizer { + visualizer: ReturnType; + private readonly renderingFrequencyInMs: number; + + constructor( + audioContext: AudioContext, + audioSource: MediaElementAudioSourceNode, + visualizerContainer: HTMLElement, + canvas: HTMLCanvasElement, + audioNode: GainNode, + stream: MediaStream, + options: ConfigType<'visualizer'>, + ) { + super( + audioContext, + audioSource, + visualizerContainer, + canvas, + audioNode, + stream, + options, + ); + + this.visualizer = Butterchurn.createVisualizer( + audioContext, + canvas, + { + width: canvas.width, + height: canvas.height, + } + ); + + const preset = presets[options.butterchurn.preset]; + this.visualizer.loadPreset(preset, options.butterchurn.blendTimeInSeconds); + + this.visualizer.connectAudio(audioNode); + + this.renderingFrequencyInMs = options.butterchurn.renderingFrequencyInMs; + } + + resize(width: number, height: number) { + this.visualizer.setRendererSize(width, height); + } + + render() { + const renderVisualizer = () => { + requestAnimationFrame(renderVisualizer); + this.visualizer.render(); + }; + setTimeout(renderVisualizer, this.renderingFrequencyInMs); + } +} + +export default ButterchurnVisualizer;