import { useEffect, useMemo, useState } from 'react'; import { ready, ink } from '../../lib/mrly.js'; import { Row, Slider, Pick } from '../../lib/app.jsx'; import { Sketch } from '../../lib/draw.jsx'; import { board, line, axis, tag } from '../../lib/chart.js'; import { embed } from '../../lib/widget.jsx'; const m = await ready(); export const LOW = 8; export const HIGH = 20; export const PER_OCTAVE = 16; export const ZEROS = 138; export const CURVE = 900; const SHORT = 16; const FEW = 40; export const meterChart = ({ heights, dots, curve, wave, j, k, sharp, height }) => (canvas) => { const b = board(canvas, height, { top: 26, bottom: 22 }); if (!dots.length) return; const wide = j - LOW; let span = 1e-9; for (let i = 0; i < heights.length; i++) if (heights[i] <= j) span = Math.max(span, Math.abs(dots[i])); for (const v of wave) span = Math.max(span, Math.abs(v)); span *= 1.1; b.ctx.strokeStyle = ink.line; b.ctx.lineWidth = 1; b.ctx.beginPath(); b.ctx.moveTo(b.x(0), b.y(0.5)); b.ctx.lineTo(b.x(1), b.y(0.5)); b.ctx.stroke(); if (k > 0) { const points = Array.from(wave, (v, i) => [(curve[i] - LOW) / wide, 0.5 + 0.5 * v / span]); line(b, points, ink.orange, { width: 1.5 }); } b.ctx.fillStyle = ink.blue; for (let i = 0; i < heights.length; i++) { if (heights[i] > j) break; b.ctx.beginPath(); b.ctx.arc(b.x((heights[i] - LOW) / wide), b.y(0.5 + 0.5 * dots[i] / span), 2.6, 0, Math.PI * 2); b.ctx.fill(); } axis(b, [[0, `y = 2^-${LOW}`], [1, `y = 2^-${j}`]]); tag(b, sharp ? 'E(y) / y, the sharp window' : 'E(y) / y^(3/2), the smooth window', ink.blue); const whose = k === 1 ? 'the first zero' : `the first ${k} zeros`; tag(b, k ? (sharp ? `the wave of ${whose}, times sqrt(y)` : `the wave of ${whose}`) : 'no zeros', ink.orange, 'right'); }; export function meter() { const [k, setK] = useState(1); const [cut, setCut] = useState('smooth'); const [reading, setReading] = useState(null); useEffect(() => { setReading(new m.Novelty(SHORT, PER_OCTAVE, FEW)); }, []); const sharp = cut === 'sharp'; const heights = useMemo(() => (reading ? reading.heights() : new Float64Array()), [reading]); const dots = useMemo(() => (reading ? reading.dots(sharp) : new Float64Array()), [reading, sharp]); const curve = useMemo(() => Float64Array.from({ length: CURVE + 1 }, (_, i) => LOW + (SHORT - LOW) * i / CURVE), []); const wave = useMemo(() => (reading ? reading.wave(k, sharp, curve) : new Float64Array()), [reading, k, sharp, curve]); const miss = useMemo(() => (reading ? reading.miss(k) : 1), [reading, k]); return ( <>

{reading ? (sharp ? `the sharp window's error over y, ${heights.length} readings the waves of ${k} zeros cannot reach` : `${k} of ${FEW} zeros miss the ${heights.length} smoothed readings by ${miss.toExponential(1)} of their peak`) : 'sieving the totients'}

); } embed('novelty', { meter });