Better Frequency scope and visualisations
This commit is contained in:
@ -123,6 +123,8 @@ export interface OscilloscopeConfig {
|
|||||||
fftSize: number; // multiples of 256
|
fftSize: number; // multiples of 256
|
||||||
orientation: "horizontal" | "vertical";
|
orientation: "horizontal" | "vertical";
|
||||||
mode: "3D" | "scope" | "freqscope";
|
mode: "3D" | "scope" | "freqscope";
|
||||||
|
offsetX: number;
|
||||||
|
offsetY: number;
|
||||||
size: number;
|
size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,47 +144,76 @@ export const runOscilloscope = (
|
|||||||
let dataArray = new Float32Array(analyzer.frequencyBinCount);
|
let dataArray = new Float32Array(analyzer.frequencyBinCount);
|
||||||
let freqDataArray = new Uint8Array(analyzer.frequencyBinCount);
|
let freqDataArray = new Uint8Array(analyzer.frequencyBinCount);
|
||||||
const canvasCtx = canvas.getContext("2d")!;
|
const canvasCtx = canvas.getContext("2d")!;
|
||||||
const WIDTH = canvas.width;
|
|
||||||
const HEIGHT = canvas.height;
|
|
||||||
let lastDrawTime = 0;
|
let lastDrawTime = 0;
|
||||||
let frameInterval = 1000 / 30;
|
let frameInterval = 1000 / 30;
|
||||||
|
|
||||||
function drawFrequencyScope() {
|
function drawFrequencyScope(
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
offset_height: number,
|
||||||
|
offset_width: number
|
||||||
|
) {
|
||||||
|
// Existing setup code...
|
||||||
|
analyzer.fftSize = app.osc.fftSize * 4;
|
||||||
analyzer.getByteFrequencyData(freqDataArray);
|
analyzer.getByteFrequencyData(freqDataArray);
|
||||||
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
|
canvasCtx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
// Ensure the number of bars does not exceed the frequency data length
|
const numBars = Math.min(
|
||||||
const numBars = freqDataArray.length;
|
freqDataArray.length,
|
||||||
const barWidth = WIDTH / numBars;
|
app.osc.orientation === "horizontal" ? width : height
|
||||||
|
);
|
||||||
|
const barWidth =
|
||||||
|
app.osc.orientation === "horizontal" ? width / numBars : height / numBars;
|
||||||
let barHeight;
|
let barHeight;
|
||||||
let x = 0;
|
let x = 0,
|
||||||
|
y = 0;
|
||||||
|
|
||||||
for (let i = 0; i < numBars; i++) {
|
for (let i = 0; i < numBars; i++) {
|
||||||
// Calculate index in the frequency data array using logarithmic scale
|
|
||||||
const logIndex = Math.floor(
|
|
||||||
Math.pow(i / numBars, 2) * freqDataArray.length
|
|
||||||
);
|
|
||||||
barHeight = Math.floor(
|
barHeight = Math.floor(
|
||||||
freqDataArray[logIndex] * ((HEIGHT / 256) * app.osc.size)
|
freqDataArray[i] * ((height / 256) * app.osc.size)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Color configuration
|
// Create gradient based on orientation
|
||||||
if (app.osc.color === "random") {
|
let gradient;
|
||||||
canvasCtx.fillStyle = `hsl(${Math.random() * 360}, 100%, 50%)`;
|
if (app.osc.orientation === "horizontal") {
|
||||||
|
gradient = canvasCtx.createLinearGradient(0, 0, width / 2, 0);
|
||||||
} else {
|
} else {
|
||||||
const gradient = canvasCtx.createLinearGradient(0, 0, WIDTH / 2, 0);
|
gradient = canvasCtx.createLinearGradient(0, 0, 0, height / 2);
|
||||||
gradient.addColorStop(0, app.osc.color || `rgb(255, 255, 255)`);
|
|
||||||
gradient.addColorStop(1, `rgb(${barHeight + 50},50,50)`);
|
|
||||||
canvasCtx.fillStyle = gradient;
|
|
||||||
}
|
}
|
||||||
|
gradient.addColorStop(0, app.osc.color || `rgb(255, 255, 255)`);
|
||||||
|
gradient.addColorStop(1, `rgb(${barHeight + 50},50,50)`);
|
||||||
|
canvasCtx.fillStyle = gradient;
|
||||||
|
|
||||||
canvasCtx.fillRect(x, (HEIGHT - barHeight) / 2, barWidth + 1, barHeight);
|
if (app.osc.orientation === "horizontal") {
|
||||||
|
canvasCtx.fillRect(
|
||||||
x += barWidth;
|
x + offset_width, // Apply horizontal offset here
|
||||||
|
(height - barHeight) / 2 + offset_height, // Apply vertical offset here
|
||||||
|
barWidth + 1,
|
||||||
|
barHeight
|
||||||
|
);
|
||||||
|
x += barWidth;
|
||||||
|
} else {
|
||||||
|
canvasCtx.fillRect(
|
||||||
|
(width - barHeight) / 2 + offset_width, // Apply horizontal offset here
|
||||||
|
y + offset_height, // Apply vertical offset here
|
||||||
|
barHeight,
|
||||||
|
barWidth + 1
|
||||||
|
);
|
||||||
|
y += barWidth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
|
// Update the canvas position on each cycle
|
||||||
|
const WIDTH = canvas.width;
|
||||||
|
const HEIGHT = canvas.height;
|
||||||
|
const OFFSET_WIDTH = app.osc.offsetX;
|
||||||
|
const OFFSET_HEIGHT = app.osc.offsetY;
|
||||||
|
|
||||||
|
// Apply an offset to the canvas!
|
||||||
|
canvasCtx.setTransform(1, 0, 0, 1, OFFSET_WIDTH, OFFSET_HEIGHT);
|
||||||
|
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
requestAnimationFrame(draw);
|
requestAnimationFrame(draw);
|
||||||
if (currentTime - lastDrawTime < frameInterval) {
|
if (currentTime - lastDrawTime < frameInterval) {
|
||||||
@ -191,7 +222,12 @@ export const runOscilloscope = (
|
|||||||
lastDrawTime = currentTime;
|
lastDrawTime = currentTime;
|
||||||
|
|
||||||
if (!app.osc.enabled) {
|
if (!app.osc.enabled) {
|
||||||
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
|
canvasCtx.clearRect(
|
||||||
|
-OFFSET_WIDTH,
|
||||||
|
-OFFSET_HEIGHT,
|
||||||
|
WIDTH + 2 * OFFSET_WIDTH,
|
||||||
|
HEIGHT + 2 * OFFSET_HEIGHT
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,9 +242,13 @@ export const runOscilloscope = (
|
|||||||
canvasCtx.fillStyle = "rgba(0, 0, 0, 0)";
|
canvasCtx.fillStyle = "rgba(0, 0, 0, 0)";
|
||||||
canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
|
canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
|
||||||
if (app.clock.time_position.pulse % app.osc.refresh == 0) {
|
if (app.clock.time_position.pulse % app.osc.refresh == 0) {
|
||||||
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
|
canvasCtx.clearRect(
|
||||||
|
-OFFSET_WIDTH,
|
||||||
|
-OFFSET_HEIGHT,
|
||||||
|
WIDTH + 2 * OFFSET_WIDTH,
|
||||||
|
HEIGHT + 2 * OFFSET_HEIGHT
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
canvasCtx.lineWidth = app.osc.thickness;
|
canvasCtx.lineWidth = app.osc.thickness;
|
||||||
|
|
||||||
if (app.osc.color === "random") {
|
if (app.osc.color === "random") {
|
||||||
@ -246,7 +286,7 @@ export const runOscilloscope = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (app.osc.mode === "freqscope") {
|
if (app.osc.mode === "freqscope") {
|
||||||
drawFrequencyScope();
|
drawFrequencyScope(WIDTH, HEIGHT, OFFSET_HEIGHT, OFFSET_WIDTH);
|
||||||
} else if (app.osc.mode === "3D") {
|
} else if (app.osc.mode === "3D") {
|
||||||
for (let i = startIndex; i < dataArray.length; i += 2) {
|
for (let i = startIndex; i < dataArray.length; i += 2) {
|
||||||
const x = (dataArray[i] * WIDTH * app.osc.size) / 2 + WIDTH / 4;
|
const x = (dataArray[i] * WIDTH * app.osc.size) / 2 + WIDTH / 4;
|
||||||
|
|||||||
@ -14,6 +14,8 @@ scope({
|
|||||||
enabled: true, // off by default
|
enabled: true, // off by default
|
||||||
color: "#fdba74", // any valid CSS color or "random"
|
color: "#fdba74", // any valid CSS color or "random"
|
||||||
thickness: 4, // stroke thickness
|
thickness: 4, // stroke thickness
|
||||||
|
offsetY: 0, // Horizontal offset
|
||||||
|
offsetX: 0, // Vertical offset
|
||||||
fftSize: 256, // multiples of 128
|
fftSize: 256, // multiples of 128
|
||||||
orientation: "horizontal", // "vertical" or "horizontal"
|
orientation: "horizontal", // "vertical" or "horizontal"
|
||||||
mode: "scope" | "3D" | "freqscope", // scope mode
|
mode: "scope" | "3D" | "freqscope", // scope mode
|
||||||
|
|||||||
@ -76,6 +76,8 @@ export class Editor {
|
|||||||
refresh: 1,
|
refresh: 1,
|
||||||
fftSize: 1024,
|
fftSize: 1024,
|
||||||
orientation: "horizontal",
|
orientation: "horizontal",
|
||||||
|
offsetX: 0,
|
||||||
|
offsetY: 0,
|
||||||
mode: "scope",
|
mode: "scope",
|
||||||
size: 1,
|
size: 1,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user