From 2209bf10311e4e0f8620f4122a31f30a83fdec41 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 21 Jun 2026 01:49:32 +0900 Subject: [PATCH] playgui: better wavescope visuals --- 2taud.sh | 6 +-- assets/disk0/tvdos/include/playgui.mjs | 39 ++++++++++++------- .../net/torvald/tsvm/peripheral/IOSpace.kt | 5 ++- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/2taud.sh b/2taud.sh index d4395bc..d93e413 100755 --- a/2taud.sh +++ b/2taud.sh @@ -11,6 +11,6 @@ for f in *.XM; python3 xm2taud.py $f assets/disk0/home/music/(basename $f .XM).t for f in *.mon; python3 mon2taud.py $f assets/disk0/home/music/(basename $f .mon).taud; end for f in *.MON; python3 mon2taud.py $f assets/disk0/home/music/(basename $f .MON).taud; end -for f in *.mid; python3 midi2taud.py $f GeneralUser-GS.sf2 assets/disk0/home/music/(basename $f .mid).taud --force-synth-loop; end -for f in *.MID; python3 midi2taud.py $f GeneralUser-GS.sf2 assets/disk0/home/music/(basename $f .MID).taud --force-synth-loop; end -for f in *.midi; python3 midi2taud.py $f GeneralUser-GS.sf2 assets/disk0/home/music/(basename $f .midi).taud --force-synth-loop; end +for f in *.mid; python3 midi2taud.py $f GeneralUser-GS.sf2 assets/disk0/home/music/(basename $f .mid).taud --force-synth-loop --mixingvol 255; end +for f in *.MID; python3 midi2taud.py $f GeneralUser-GS.sf2 assets/disk0/home/music/(basename $f .MID).taud --force-synth-loop --mixingvol 255; end +for f in *.midi; python3 midi2taud.py $f GeneralUser-GS.sf2 assets/disk0/home/music/(basename $f .midi).taud --force-synth-loop --mixingvol 255; end diff --git a/assets/disk0/tvdos/include/playgui.mjs b/assets/disk0/tvdos/include/playgui.mjs index 4ebb56d..a3da050 100644 --- a/assets/disk0/tvdos/include/playgui.mjs +++ b/assets/disk0/tvdos/include/playgui.mjs @@ -654,9 +654,13 @@ function aa_alowed(i) { const c = i & 0xff const attr = (i >>> 8) if (attr >= AA_NATTRS) return false - // printable ASCII, space, or extended (>160) — keep AA_EIGHT chars so the - // glyph palette includes the TSVM ROM's box-drawing / shade / dot range. - if (!(c >= 33 && c <= 126) && c !== 0x20 && !(c > 160)) return false + // Printable ASCII + space ONLY. Excluding the CP437 shade / solid-block / + // half-block range (▒ ▓ █ ▄ ▌ ▀, codes 0xB0-0xDF) is what keeps the + // wavescope trace thin: a fully-lit cell now resolves to a dense *ASCII* + // glyph (# a 6 J) whose inter-stroke gaps read as a fine scope line rather + // than a filled bar. The mini-AAlib has no other consumer, so this only + // affects the wavescope. + if (!(c >= 33 && c <= 126) && c !== 0x20) return false return true } @@ -914,10 +918,11 @@ function aa_render(img, scrW, scrH, tbOut, attrOut) { // then converted to ASCII glyphs by the mini-AAlib above. Mid-signal only — // stereo info lives on the bottom bar. // -// Three monochrome intensities pick out the wave's body / peaks: DIM cells -// are the dim trace, NORMAL cells are the bulk of the waveform, BOLD cells -// land on the brightest patches (full-blocked peaks). Amber → white ramp -// mimics phosphor bloom. +// The mini-AAlib palette is ASCII-only (no CP437 block glyphs), so the trace +// stays a fine line instead of a filled bar. Colour is by DENSITY, not AA +// weight: each cell's lit-pixel count drives a blue→orange ramp — sparse +// fringes read blue, the solid body reads orange — matching the VISUALS +// section's cool-ground / warm-beam language. const AA_WAVE_W = AG_LANE_W // 78 cells const AA_WAVE_H = AG_ROW_WAVE_BOT - AG_ROW_WAVE_TOP + 1 // 3 cells @@ -928,8 +933,11 @@ const ag_waveImg = new Uint8Array(AA_WAVE_IW * AA_WAVE_IH) const ag_waveTb = new Uint8Array(AA_WAVE_W * AA_WAVE_H) const ag_waveAttr = new Uint8Array(AA_WAVE_W * AA_WAVE_H) -// AA_NORMAL=0, AA_DIM=1, AA_BOLD=2 → amber phosphor palette. -const AG_WAVE_FG = [166, 130, AG_COL_LABEL] +// Per-cell colour by trace DENSITY (lit source-pixels in the cell, 0..4), +// blue→orange exactly like the VISUALS section: sparse fringes read blue (the +// cool "ground" from AG_STEREO_COL), the solid body reads orange/gold (the +// warm peak from AG_BEAM_PAL). Index 0 is background (empty cell). +const AG_WAVE_DENS_FG = [AG_COL_BG, 94, 130, 166, 220] function ag_drawWavescope() { const N = AG_SNAPSHOT_N @@ -960,16 +968,21 @@ function ag_drawWavescope() { aa_render(img, AA_WAVE_W, AA_WAVE_H, ag_waveTb, ag_waveAttr) - // Blit, skipping cells whose packed (attr<<8 | glyph) key is unchanged. + // Blit, skipping cells whose packed (density<<8 | glyph) key is unchanged. for (let r = 0; r < AA_WAVE_H; r++) { for (let c = 0; c < AA_WAVE_W; c++) { const idx = r * AA_WAVE_W + c - const att = ag_waveAttr[idx] const ch = ag_waveTb[idx] - const key = (att << 8) | ch + // Density = lit source-pixels in this cell's 2×2 block (0..4) → + // blue (sparse) … orange (dense). + const px = (2 * r) * IW + (2 * c) + const lit = (img[px] ? 1 : 0) + (img[px + 1] ? 1 : 0) + + (img[px + IW] ? 1 : 0) + (img[px + IW + 1] ? 1 : 0) + const fg = AG_WAVE_DENS_FG[lit] + const key = (lit << 8) | ch if (ag_waveGlyph[idx] === key) continue ag_waveGlyph[idx] = key - ag_color(AG_WAVE_FG[att] || AG_COL_LABEL, AG_COL_BG) + ag_color(fg, AG_COL_BG) ag_mvprn(AG_ROW_WAVE_TOP + r, AG_COL_INSIDE_L + c, ch) } } diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt index 985b197..5c6ba22 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt @@ -513,6 +513,7 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor { private class Beeper { companion object { + private const val ARPRATE = 60 private const val SAMPLE_RATE = 48000 // SN76489 NTSC colourburst clock (3579545 Hz) after the chip's internal /32 // prescaler. The square wave toggles every `divider` master ticks, so one full @@ -520,8 +521,8 @@ private class Beeper { // (divider 127 -> 440.4 Hz.) private const val MASTER_CLOCK = 3579545.4545454545 / 32.0 // Arpeggio note-effects step at 60 Hz: 48000 / 60 = 800 samples per step. - private const val SAMPLES_PER_ARP_TICK = SAMPLE_RATE / 60 - private const val CHUNK = 512 + private const val SAMPLES_PER_ARP_TICK = SAMPLE_RATE / ARPRATE + private const val CHUNK = SAMPLES_PER_ARP_TICK private const val AMPLITUDE = 8192 // ~ -12 dBFS; square waves are loud }