diff --git a/data/index.html b/data/index.html index f3a1e2a..097ecdc 100644 --- a/data/index.html +++ b/data/index.html @@ -61,18 +61,36 @@ label: note })); + // Keep track of recent maximum values + const maxValueHistory = []; + const MAX_HISTORY_LENGTH = 5; + + function updateYAxisScale(newValue) { + maxValueHistory.push(newValue); + if (maxValueHistory.length > MAX_HISTORY_LENGTH) { + maxValueHistory.shift(); + } + return Math.max(...maxValueHistory) * 1.1; // Add 10% margin + } + const ctx = document.getElementById('spectrumChart').getContext('2d'); const chart = new Chart(ctx, { type: 'line', data: { - labels: Array.from({length: 134}, (_, i) => (i + 8) * (8000 / 1024)), + // Generate logarithmically spaced frequencies for labels + labels: Array.from({length: 134}, (_, i) => { + const minFreq = 60; + const maxFreq = 1100; + return Math.pow(10, Math.log10(minFreq) + (Math.log10(maxFreq) - Math.log10(minFreq)) * i / 133); + }), datasets: [{ label: 'Frequency Spectrum', data: Array(134).fill(0), borderColor: 'rgb(75, 192, 192)', tension: 0.1, fill: true, - backgroundColor: 'rgba(75, 192, 192, 0.2)' + backgroundColor: 'rgba(75, 192, 192, 0.2)', + pointRadius: 0 // Hide points for better performance }] }, options: { @@ -81,10 +99,19 @@ animation: { duration: 0 }, + parsing: { + xAxisKey: 'x', + yAxisKey: 'y' + }, scales: { y: { beginAtZero: true, max: 5000, + adapters: { + update: function(maxValue) { + return updateYAxisScale(maxValue); + } + }, title: { display: true, text: 'Magnitude' @@ -92,6 +119,7 @@ }, x: { type: 'logarithmic', + position: 'bottom', min: 60, max: 1100, title: { @@ -99,20 +127,21 @@ text: 'Frequency (Hz)' }, ticks: { - callback: function(value, index, values) { - // Find the closest note - const closestNote = Object.entries(noteFrequencies) - .reduce((closest, [note, freq]) => { - return Math.abs(freq - value) < Math.abs(freq - closest.freq) - ? { note, freq } - : closest; - }, { note: '', freq: Infinity }); + callback: function(value) { + // Show C notes and F# notes + const entries = Object.entries(noteFrequencies); + const closest = entries.reduce((prev, curr) => { + return Math.abs(curr[1] - value) < Math.abs(prev[1] - value) ? curr : prev; + }); - if (Math.abs(value - closestNote.freq) < 1) { - return closestNote.note; + if ((closest[0].includes('C') || closest[0].includes('F#')) && + Math.abs(closest[1] - value) < 1) { + return closest[0]; } return ''; - } + }, + sampleSize: 20, + autoSkip: false }, grid: { color: (ctx) => { @@ -175,21 +204,32 @@ const ws = new WebSocket(wsUrl); function interpolateSpectrum(spectrum) { - // Convert the linear frequency bins to logarithmic scale - const result = new Array(spectrum.length).fill(0); + const result = []; + const minFreq = 60; + const maxFreq = 1100; const binWidth = 8000 / 1024; // Hz per bin - for (let i = 0; i < spectrum.length; i++) { - const freq = (i + 8) * binWidth; - const logFreq = Math.log10(freq); + // Generate logarithmically spaced frequencies + for (let i = 0; i < 134; i++) { + const targetFreq = Math.pow(10, Math.log10(minFreq) + (Math.log10(maxFreq) - Math.log10(minFreq)) * i / 133); - // Find the two closest bins and interpolate - const bin1 = Math.floor((logFreq - Math.log10(60)) / (Math.log10(1100) - Math.log10(60)) * spectrum.length); - const bin2 = bin1 + 1; + // Find the corresponding linear bin + const bin = Math.floor(targetFreq / binWidth); - if (bin1 >= 0 && bin2 < spectrum.length) { - const t = (logFreq - Math.log10(60)) / (Math.log10(1100) - Math.log10(60)) * spectrum.length - bin1; - result[i] = spectrum[bin1] * (1 - t) + spectrum[bin2] * t; + if (bin >= 8 && bin < 141) { + // Linear interpolation between bins + const binFraction = (targetFreq / binWidth) - bin; + const value = spectrum[bin - 8] * (1 - binFraction) + + (bin - 7 < spectrum.length ? spectrum[bin - 7] : 0) * binFraction; + result.push({ + x: targetFreq, + y: value + }); + } else { + result.push({ + x: targetFreq, + y: 0 + }); } } @@ -198,8 +238,14 @@ ws.onmessage = function(event) { const spectrum = JSON.parse(event.data); - // Interpolate the spectrum data for logarithmic display - chart.data.datasets[0].data = interpolateSpectrum(spectrum); + const interpolatedData = interpolateSpectrum(spectrum); + + // Update y-axis scale based on new maximum value + const maxValue = Math.max(...interpolatedData.map(d => d.y)); + chart.options.scales.y.max = updateYAxisScale(maxValue); + + // Update chart data + chart.data.datasets[0].data = interpolatedData; chart.update('none'); // Use 'none' mode for maximum performance };