mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 05:38:34 +00:00
add basic spectrum function
This commit is contained in:
parent
ae335ac40c
commit
648fbf99fa
@ -26,7 +26,7 @@ export const getDrawContext = (id = 'test-canvas', options) => {
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
return canvas.getContext(contextType);
|
||||
return canvas.getContext(contextType, { willReadFrequently: true });
|
||||
};
|
||||
|
||||
let animationFrames = {};
|
||||
|
||||
@ -270,11 +270,12 @@ function getReverb(orbit, duration, fade, lp, dim, ir) {
|
||||
export let analysers = {},
|
||||
analysersData = {};
|
||||
|
||||
export function getAnalyserById(id, fftSize = 1024) {
|
||||
export function getAnalyserById(id, fftSize = 1024, smoothingTimeConstant = 0.5) {
|
||||
if (!analysers[id]) {
|
||||
// make sure this doesn't happen too often as it piles up garbage
|
||||
const analyserNode = getAudioContext().createAnalyser();
|
||||
analyserNode.fftSize = fftSize;
|
||||
analyserNode.smoothingTimeConstant = smoothingTimeConstant;
|
||||
// getDestination().connect(analyserNode);
|
||||
analysers[id] = analyserNode;
|
||||
analysersData[id] = new Float32Array(analysers[id].frequencyBinCount);
|
||||
|
||||
@ -6,4 +6,5 @@ This program is free software: you can redistribute it and/or modify it under th
|
||||
|
||||
export * from './webaudio.mjs';
|
||||
export * from './scope.mjs';
|
||||
export * from './spectrum.mjs';
|
||||
export * from 'superdough';
|
||||
|
||||
57
packages/webaudio/spectrum.mjs
Normal file
57
packages/webaudio/spectrum.mjs
Normal file
@ -0,0 +1,57 @@
|
||||
import { Pattern, clamp } from '@strudel/core';
|
||||
import { getDrawContext, getTheme } from '@strudel/draw';
|
||||
import { analysers, getAnalyzerData } from 'superdough';
|
||||
|
||||
/**
|
||||
* Renders a spectrum analyzer for the incoming audio signal.
|
||||
* @name spectrum
|
||||
* @param {object} config optional config with options:
|
||||
*/
|
||||
let latestColor = {};
|
||||
Pattern.prototype.spectrum = function (config = {}) {
|
||||
let id = config.id ?? 1;
|
||||
return this.analyze(id).draw(
|
||||
(haps) => {
|
||||
config.color = haps[0]?.value?.color || latestColor[id] || getTheme().foreground;
|
||||
latestColor[id] = config.color;
|
||||
drawSpectrum(analysers[id], config);
|
||||
},
|
||||
{ id },
|
||||
);
|
||||
};
|
||||
|
||||
Pattern.prototype.scope = Pattern.prototype.tscope;
|
||||
|
||||
const lastFrames = new Map();
|
||||
|
||||
function drawSpectrum(
|
||||
analyser,
|
||||
{ thickness = 3, speed = 1, min = -80, max = 0, ctx = getDrawContext(), id = 1, color } = {},
|
||||
) {
|
||||
ctx.lineWidth = thickness;
|
||||
ctx.strokeStyle = color;
|
||||
|
||||
if (!analyser) {
|
||||
// if analyser is undefined, draw straight line
|
||||
// it may be undefined when no sound has been played yet
|
||||
return;
|
||||
}
|
||||
const scrollSize = speed;
|
||||
const dataArray = getAnalyzerData('frequency', id);
|
||||
const canvas = ctx.canvas;
|
||||
ctx.fillStyle = color;
|
||||
const bufferSize = analyser.frequencyBinCount;
|
||||
let imageData = lastFrames.get(id) || ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
lastFrames.set(id, imageData);
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
ctx.putImageData(imageData, -scrollSize, 0);
|
||||
let q = canvas.width - speed;
|
||||
for (let i = 0; i < bufferSize; i++) {
|
||||
const normalized = clamp((dataArray[i] - min) / (max - min), 0, 1);
|
||||
ctx.globalAlpha = normalized;
|
||||
const next = (Math.log(i + 1) / Math.log(bufferSize)) * canvas.height;
|
||||
const size = 2; //next - pos;
|
||||
ctx.fillRect(q, canvas.height - next, scrollSize, size);
|
||||
}
|
||||
lastFrames.set(id, ctx.getImageData(0, 0, canvas.width, canvas.height));
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user