inline multichannel scopes

This commit is contained in:
Felix Roos 2024-03-16 02:14:24 +01:00
parent d9d05e21c0
commit f4032dad22
3 changed files with 47 additions and 32 deletions

View File

@ -215,35 +215,34 @@ function getReverb(orbit, duration, fade, lp, dim, ir) {
return reverbs[orbit]; return reverbs[orbit];
} }
export let analyser, analyserData /* s = {} */; export let analysers = {},
analysersData = {};
export function getAnalyser(/* orbit, */ fftSize = 2048) { export function getAnalyserById(id, fftSize = 1024) {
if (!analyser /*s [orbit] */) { if (!analysers[id]) {
const analyserNode = getAudioContext().createAnalyser(); const analyserNode = getAudioContext().createAnalyser();
analyserNode.fftSize = fftSize; analyserNode.fftSize = fftSize;
// getDestination().connect(analyserNode); // getDestination().connect(analyserNode);
analyser /* s[orbit] */ = analyserNode; analysers[id] = analyserNode;
//analyserData = new Uint8Array(analyser.frequencyBinCount); analysersData[id] = new Float32Array(analysers[id].frequencyBinCount);
analyserData = new Float32Array(analyser.frequencyBinCount);
} }
if (analyser /* s[orbit] */.fftSize !== fftSize) { if (analysers[id].fftSize !== fftSize) {
analyser /* s[orbit] */.fftSize = fftSize; analysers[id].fftSize = fftSize;
//analyserData = new Uint8Array(analyser.frequencyBinCount); analysersData[id] = new Float32Array(analysers[id].frequencyBinCount);
analyserData = new Float32Array(analyser.frequencyBinCount);
} }
return analyser /* s[orbit] */; return analysers[id];
} }
export function getAnalyzerData(type = 'time') { export function getAnalyzerData(type = 'time', id = 1) {
const getter = { const getter = {
time: () => analyser?.getFloatTimeDomainData(analyserData), time: () => analysers[id]?.getFloatTimeDomainData(analysersData[id]),
frequency: () => analyser?.getFloatFrequencyData(analyserData), frequency: () => analyser[id]?.getFloatFrequencyData(analysersData[id]),
}[type]; }[type];
if (!getter) { if (!getter) {
throw new Error(`getAnalyzerData: ${type} not supported. use one of ${Object.keys(getter).join(', ')}`); throw new Error(`getAnalyzerData: ${type} not supported. use one of ${Object.keys(getter).join(', ')}`);
} }
getter(); getter();
return analyserData; return analysersData[id];
} }
function effectSend(input, effect, wet) { function effectSend(input, effect, wet) {
@ -256,6 +255,8 @@ function effectSend(input, effect, wet) {
export function resetGlobalEffects() { export function resetGlobalEffects() {
delays = {}; delays = {};
reverbs = {}; reverbs = {};
analysers = {};
analysersData = {};
} }
export const superdough = async (value, deadline, hapDuration) => { export const superdough = async (value, deadline, hapDuration) => {
@ -512,8 +513,8 @@ export const superdough = async (value, deadline, hapDuration) => {
// analyser // analyser
let analyserSend; let analyserSend;
if (analyze) { if (analyze) {
const analyserNode = getAnalyser(/* orbit, */ 2 ** (fft + 5)); const analyserNode = getAnalyserById(analyze, 2 ** (fft + 5));
analyserSend = effectSend(post, analyserNode, analyze); analyserSend = effectSend(post, analyserNode, 1);
} }
// connect chain elements together // connect chain elements together

View File

@ -1,13 +1,21 @@
import { Pattern, clamp } from '@strudel/core'; import { Pattern, clamp } from '@strudel/core';
import { getDrawContext } from '../draw/index.mjs'; import { getDrawContext } from '../draw/index.mjs';
import { analyser, getAnalyzerData } from 'superdough'; import { getAnalyzerData } from 'superdough';
export function drawTimeScope( export function drawTimeScope(
analyser, analyser,
{ align = true, color = 'white', thickness = 3, scale = 0.25, pos = 0.75, trigger = 0 } = {}, {
align = true,
color = 'white',
thickness = 3,
scale = 0.25,
pos = 0.75,
trigger = 0,
ctx = getDrawContext(),
id = 1,
} = {},
) { ) {
const ctx = getDrawContext(); const dataArray = getAnalyzerData('time', id);
const dataArray = getAnalyzerData('time');
ctx.lineWidth = thickness; ctx.lineWidth = thickness;
ctx.strokeStyle = color; ctx.strokeStyle = color;
@ -39,10 +47,9 @@ export function drawTimeScope(
export function drawFrequencyScope( export function drawFrequencyScope(
analyser, analyser,
{ color = 'white', scale = 0.25, pos = 0.75, lean = 0.5, min = -150, max = 0 } = {}, { color = 'white', scale = 0.25, pos = 0.75, lean = 0.5, min = -150, max = 0, ctx = getDrawContext(), id = 1 } = {},
) { ) {
const dataArray = getAnalyzerData('frequency'); const dataArray = getAnalyzerData('frequency', id);
const ctx = getDrawContext();
const canvas = ctx.canvas; const canvas = ctx.canvas;
ctx.fillStyle = color; ctx.fillStyle = color;
@ -61,8 +68,7 @@ export function drawFrequencyScope(
} }
} }
function clearScreen(smear = 0, smearRGB = `0,0,0`) { function clearScreen(smear = 0, smearRGB = `0,0,0`, ctx = getDrawContext()) {
const ctx = getDrawContext();
if (!smear) { if (!smear) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
} else { } else {
@ -84,9 +90,10 @@ function clearScreen(smear = 0, smearRGB = `0,0,0`) {
* s("sawtooth").fscope() * s("sawtooth").fscope()
*/ */
Pattern.prototype.fscope = function (config = {}) { Pattern.prototype.fscope = function (config = {}) {
return this.analyze(1).draw(() => { let id = config.id ?? 1;
clearScreen(config.smear); return this.analyze(id).draw(() => {
analyser && drawFrequencyScope(analyser, config); clearScreen(config.smear, '0,0,0', config.ctx);
analysers[id] && drawFrequencyScope(analyser, config);
}); });
}; };
@ -105,9 +112,10 @@ Pattern.prototype.fscope = function (config = {}) {
* s("sawtooth").scope() * s("sawtooth").scope()
*/ */
Pattern.prototype.tscope = function (config = {}) { Pattern.prototype.tscope = function (config = {}) {
return this.analyze(1).draw(() => { let id = config.id ?? 1;
clearScreen(config.smear); return this.analyze(id).draw(() => {
analyser && drawTimeScope(analyser, config); clearScreen(config.smear, '0,0,0', config.ctx);
analysers[id] && drawTimeScope(analysers[id], config);
}); });
}; };

View File

@ -21,3 +21,9 @@ registerWidget('twist', (id, options = {}, pat) => {
const ctx = getCanvasWidget(id, options).getContext('2d'); const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.spiral({ ...options, ctx, id }); return pat.spiral({ ...options, ctx, id });
}); });
registerWidget('osci', (id, options = {}, pat) => {
options = { width: 500, height: 60, pos: 0.5, scale: 1, ...options };
const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.scope({ ...options, ctx, id });
});