As-built: add on-page bill of materials; confirm analog click-injection

- Add a costed BOM panel below the loader, grouped by subsystem (brain &
  display, beat bar, controls, audio—analog click injection, connectors &
  power, build) with quantities and ballpark prices (~$61 one-off).
- Reflect the confirmed analog mixing in the audio path / comment: PCM5102A
  click DAC → summing op-amp (NE5532/OPA2134) with a hi-Z instrument buffer →
  balanced line driver (DRV134) to the shared 1/4" TRS out, plus a PAM8302A
  monitor amp + speaker — the instrument is never re-digitised (no latency).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Me Here 2026-05-26 07:42:38 -05:00
parent 5f18629c05
commit 3e70eadea7

View file

@ -18,8 +18,10 @@
never hides the readout) with arcade pushbuttons spread below — PREV far
left, NEXT far right, a big central PLAY — so you don't hit the wrong one;
• rear I/O: external trigger in (footswitch), a 1/4" instrument pass-through
with the click injected, and a shared 1/4" balanced-TRS main out; plus a
MAX98357A-style monitor speaker, USB-C and a PWR LED, in a compact matte case.
with the click mixed in the ANALOG domain (DAC → summing op-amp → balanced
line driver), a shared 1/4" balanced-TRS main out, plus an analog monitor
amp + speaker, USB-C and a PWR LED, in a compact matte case.
A rough bill of materials for all of this is shown below the loader on the page.
Compare with the idealized /player.html. One file, no deps; shares src/engine.js.
-->
<script>
@ -151,6 +153,17 @@
.status.ok{ color:#5fd08a } .status.err{ color:#ff7a7a }
.hint{ font-size:11px; color:var(--muted) }
code{ background:var(--field-bg); border:1px solid var(--field-bd); border-radius:4px; padding:1px 5px; font-size:11px }
/* ---- bill of materials ---- */
.bom{ width:100%; border-collapse:collapse; font-size:12px; margin-top:8px }
.bom th, .bom td{ text-align:left; padding:5px 6px; border-bottom:1px solid var(--panel-bd); vertical-align:top }
.bom th{ color:var(--muted); font-weight:600; font-size:10px; text-transform:uppercase; letter-spacing:.05em }
.bom th.q, .bom th.c, .bom td.q, .bom td.c{ text-align:right; white-space:nowrap }
.bom td.q, .bom td.c{ color:var(--muted) }
.bom .grp td{ color:var(--cyan); font-weight:700; font-size:10px; text-transform:uppercase; letter-spacing:.07em; padding-top:11px }
.bom .part{ color:var(--txt) }
.bom .part .spec{ color:var(--muted); font-weight:400 }
.bom tr.total td{ font-weight:700; color:var(--txt); border-top:2px solid var(--panel-bd); border-bottom:none; padding-top:8px }
</style>
</head>
<body>
@ -221,6 +234,44 @@
<div class="status" id="status"></div>
</div>
<!-- ===================== BILL OF MATERIALS ===================== -->
<div class="panel">
<h2>Bill of materials</h2>
<p class="sub">Rough parts list for the device above — an RP2040 build with analog click injection.
Ballpark one-off prices (USD); cheaper at volume.</p>
<table class="bom">
<thead><tr><th>Part</th><th class="q">Qty</th><th class="c">~$</th></tr></thead>
<tbody>
<tr class="grp"><td colspan="3">Brain &amp; display</td></tr>
<tr><td class="part">RP2040 board, USBC <span class="spec">— e.g. Waveshare RP2040Zero / Picoclone</span></td><td class="q">1</td><td class="c">4</td></tr>
<tr><td class="part">2.0″ 320×240 IPS TFT, ST7789 <span class="spec">— SPI</span></td><td class="q">1</td><td class="c">8</td></tr>
<tr class="grp"><td colspan="3">Beat bar</td></tr>
<tr><td class="part">WS2812B / SK6812 RGB LED <span class="spec">— 4×16 matrix (or 4× 16px strips), PIOdriven</span></td><td class="q">64</td><td class="c">6</td></tr>
<tr class="grp"><td colspan="3">Controls</td></tr>
<tr><td class="part">Arcade pushbutton, 24 mm <span class="spec">— Prev · Next · Tap</span></td><td class="q">3</td><td class="c">4</td></tr>
<tr><td class="part">Arcade pushbutton, 30 mm <span class="spec">— Play</span></td><td class="q">1</td><td class="c">2</td></tr>
<tr><td class="part">EC11 rotary encoder + knurled knob <span class="spec">— tempo</span></td><td class="q">1</td><td class="c">2</td></tr>
<tr class="grp"><td colspan="3">Audio — analog click injection</td></tr>
<tr><td class="part">PCM5102A I²S DAC <span class="spec">— linelevel click</span></td><td class="q">1</td><td class="c">3</td></tr>
<tr><td class="part">Dual opamp, NE5532 / OPA2134 <span class="spec">— hiZ instrument buffer + summing mixer</span></td><td class="q">1</td><td class="c">1</td></tr>
<tr><td class="part">Balanced line driver, DRV134 <span class="spec">— (or crosscoupled opamp) → 1/4″ TRS out</span></td><td class="q">1</td><td class="c">4</td></tr>
<tr><td class="part">PAM8302A mono ClassD + 8 Ω 2 W speaker <span class="spec">— monitor</span></td><td class="q">1</td><td class="c">4</td></tr>
<tr class="grp"><td colspan="3">Connectors &amp; power</td></tr>
<tr><td class="part">1/4″ jack <span class="spec">— Inst In (TS) · Out (TRS) · Trig In (TS)</span></td><td class="q">3</td><td class="c">3</td></tr>
<tr><td class="part">LiPo 1200 mAh + TP4056 charger + 5 V boost</td><td class="q">1</td><td class="c">6</td></tr>
<tr><td class="part">Power slide switch + PWR LED</td><td class="q">1</td><td class="c">1</td></tr>
<tr class="grp"><td colspan="3">Build</td></tr>
<tr><td class="part">Custom PCB (or perfboard)</td><td class="q">1</td><td class="c">5</td></tr>
<tr><td class="part">Passives, headers, wire <span class="spec">— R/C for the analog stage + decoupling</span></td><td class="q"></td><td class="c">3</td></tr>
<tr><td class="part">3Dprinted enclosure + screws / standoffs</td><td class="q">1</td><td class="c">5</td></tr>
<tr class="total"><td>Total (oneoff)</td><td class="q"></td><td class="c">≈ $61</td></tr>
</tbody>
</table>
<p class="sub" style="margin-top:12px">Audio is summed in the <b>analog domain</b>: the DAC's click is mixed with a highimpedance
buffer of the 1/4″ instrument input, then fed to the balanced line driver (1/4″ TRS out) and the monitor amp —
so your instrument is never redigitised (no added latency).</p>
</div>
<script>
const APP_VERSION = "v0.0.1-dev";
const $ = (id) => document.getElementById(id);