chiro-canto/public/larynx/v/2.0/scripts/script.js
2021-04-18 16:59:01 +02:00

264 lines
6.2 KiB
JavaScript

let analyser;
let context;
let fftsize = 2048;
let oscillator = true;
let log;
let percent;
let times;
let speed = 0.1;
let bufferLength;
let labels;
let color = true;
let width = window.innerwidth;
let height = window.innerheight;
let canvas = document.getElementById('spectrogram-canvas');
let ctx = canvas.getContext('2d');
let lastRenderTime = new Date();
let instantaneousFPS = 0;
let audio = document.getElementById('audio');
document.getElementById("launch-larynx").addEventListener('click', function () {
loadSound(audio.src)
startLarynx();
});
function loadSound(url) {
let AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
context = new AudioContext();
let source = context.createMediaElementSource(audio);
}
function startLarynx() {
analyser = context.createAnalyser();
render();
}
function render() {
let didResize = false;
analyser = context.createAnalyser();
// Ensure dimensions are accurate.
if (canvas.width != width) {
canvas.width = width;
didResize = true;
}
if (canvas.height != height) {
canvas.height = height;
didResize = true;
}
renderTimeDomain();
renderFreqDomain();
if (labels && didResize) {
renderAxesLabels();
}
let now = new Date();
if (lastRenderTime) {
instantaneousFPS = now - lastRenderTime;
}
lastRenderTime = now;
}
function draw() {
drawVisual = requestAnimationFrame(draw);
analyser.getByteTimeDomainData(times);
ctx.fillStyle = 'rgb(200, 200, 200)';
ctx.fillRect(0, 0, width, height);
ctx.linewidth = 2;
ctx.strokeStyle = 'rgb(0, 0, 0)';
ctx.beginPath();
var slicewidth = width * 1.0 / bufferLength;
var x = 0;
for (var i = 0; i < bufferLength; i++) {
var v = times[i] / 128.0;
var y = v * height / 2;
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
x += slicewidth;
}
ctx.lineTo(canvas.width, canvas.height / 2);
ctx.stroke();
}
function renderTimeDomain() {
bufferLength = analyser.frequencyBinCount;
times = new Uint8Array(bufferLength);
draw();
}
function renderFreqDomain() {
let freq = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(freq);
for (let i = 0; i < freq.length; i++) {
let value;
// Draw each pixel with the specific color.
if (log) {
logIndex = logScale(i, freq.length);
value = freq[logIndex];
} else {
value = freq[i];
}
ctx.fillStyle = (color ? getFullColor(value) : getGrayColor(value));
let perceint = i / freq.length;
let y = Math.round(percent * height);
// Draw the line at the right side of the canvas.
ctx.fillRect(width - speed, height - y, speed, speed);
}
ctx.translate(-speed, 0);
// Reset the transformation matrix
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
function logScale(index, total, opt_base) {
let base = opt_base || 2;
let logmax = logBase(total + 1, base);
let exp = logmax * index / total;
return Math.round(Math.pow(base, exp) - 1);
}
function logBase(val, base) {
return Math.log(val) / Math.log(base);
}
function renderAxesLabels() {
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext('2d');
let startFreq = 440;
let nyquist = context.sampleRate / 2;
let endFreq = nyquist - startFreq;
let step = (endFreq - startFreq) / ticks;
let yLabelOffset = 5;
// Render the vertical frequency axis.
for (let i = 0; i <= ticks; i++) {
let freq = startFreq + (step * i);
// Get the y coordinate from the current label.
let index = freqToIndex(freq);
let percent = index / getFFTBinCount();
let y = (1 - percent) * height;
let x = width - 60;
// Get the value for the current y coordinate.
let label;
if (log) {
// Handle a logarithmic scale.
let logIndex = logScale(index, getFFTBinCount());
// Never show 0 Hz.
freq = Math.max(1, indexToFreq(logIndex));
}
label = formatFreq(freq);
let units = formatUnits(freq);
ctx.font = '16px Inconsolata';
// Draw the value.
ctx.textAlign = 'right';
ctx.fillText(label, x, y + yLabelOffset);
// Draw the units.
ctx.textAlign = 'left';
ctx.fillText(units, x + 10, y + yLabelOffset);
// Draw a tick mark.
ctx.fillRect(x + 40, y, 30, 2);
}
}
function clearAxesLabels() {
let canvas = labels;
let ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, width, height);
}
function formatFreq(freq) {
return (freq >= 1000 ? (freq / 1000).toFixed(1) : Math.round(freq));
}
function formatUnits(freq) {
return (freq >= 1000 ? 'KHz' : 'Hz');
}
function indexToFreq(index) {
let nyquist = context.sampleRate / 2;
return nyquist / getFFTBinCount() * index;
}
function freqToIndex(frequency) {
let nyquist = context.sampleRate / 2;
return Math.round(frequency / nyquist * getFFTBinCount());
}
function getFFTBinCount() {
return fftsize / 2;
}
// function onStream(stream) {
// let input = context.createMediaStreamSource(stream);
// let analyser = context.createAnalyser();
// analyser.smoothingTimeConstant = 0;
// analyser.fftSize = fftsize;
// // Connect graph.
// input.connect(analyser);
// // Setup a timer to visualize some stuff.
// render();
// }
function onStreamError(e) {
console.error(e);
}
function getGrayColor(value) {
return 'rgb(V, V, V)'.replace(/V/g, 255 - value);
}
function getFullColor(value) {
let fromH = 62;
let toH = 0;
let percent = value / 255;
let delta = percent * (toH - fromH);
let hue = fromH + delta;
return 'hsl(H, 100%, 50%)'.replace(/H/g, hue);
}
function logChanged() {
if (labels) {
renderAxesLabels();
}
}
function ticksChanged() {
if (labels) {
renderAxesLabels();
}
}
function labelsChanged() {
if (labels) {
renderAxesLabels();
} else {
clearAxesLabels();
}
}