5623b11Recorder simulator: MATLAB jet-drive model and interactive web appJeremy Magland 1// Small multiples of the pressure standing wave |p(x)| along the bore for
2// the lowest resonances of the first note's fingering. The window is at the
3// left, the foot at the right; an open tone hole shows up as the profile
4// being pinned near zero beyond it, which is how a fingering shortens the
5// instrument without shortening the tube.
7import { useCanvas, drawFrame, PLOT_COLORS } from './canvasUtils';
9interface Props {
10 profX: Float32Array;
11 profP: Float32Array; // nsta x n, column-major
12 modeF: Float32Array;
13}
15const SHOWN = 8;
16const CELL_H = 100;
18export default function BoreProfile({ profX, profP, modeF }: Props) {
19 const nShown = Math.min(SHOWN, modeF.length);
20 const rows = Math.ceil(nShown / 4);
21 const ref = useCanvas(
22 (ctx, w, h) => {
23 drawFrame(ctx, w, h);
24 const nsta = profX.length;
25 if (nsta === 0 || nShown === 0) return;
26 const cols = 4;
27 const cw = w / cols;
28 const ch = h / rows;
29 const xMax = profX[nsta - 1];
31 for (let m = 0; m < nShown; m++) {
32 const x0 = (m % cols) * cw + 10;
33 const y0 = Math.floor(m / cols) * ch + 12;
34 const iw = cw - 20;
35 const ih = ch - 34;
36 const off = m * nsta;
38 let pMax = 1e-12;
39 for (let i = 0; i < nsta; i++) pMax = Math.max(pMax, profP[off + i]);
41 // bore axis
42 ctx.strokeStyle = 'rgba(139, 147, 161, 0.3)';
43 ctx.beginPath();
44 ctx.moveTo(x0, y0 + ih);
45 ctx.lineTo(x0 + iw, y0 + ih);
46 ctx.stroke();
48 ctx.strokeStyle = PLOT_COLORS.trace;
49 ctx.lineWidth = 1.6;
50 ctx.beginPath();
51 for (let i = 0; i < nsta; i++) {
52 const x = x0 + (profX[i] / xMax) * iw;
53 const y = y0 + ih - (profP[off + i] / pMax) * ih;
54 if (i === 0) ctx.moveTo(x, y);
55 else ctx.lineTo(x, y);
56 }
57 ctx.stroke();
58 ctx.lineWidth = 1;
60 ctx.font = '10px system-ui';
61 ctx.textAlign = 'center';
62 ctx.fillStyle = PLOT_COLORS.accent;
63 ctx.fillText(`${modeF[m].toFixed(0)} Hz`, x0 + iw / 2, y0 + ih + 14);
64 }
65 ctx.textAlign = 'left';
66 ctx.fillStyle = PLOT_COLORS.axis;
67 ctx.font = '10px system-ui';
68 ctx.fillText('window → foot', 10, 9);
69 },
70 [profX, profP, modeF, nShown, rows],
71 rows * CELL_H,
72 );
73 return <canvas ref={ref} />;
74}