HEARO
> Music player for vintage DOS PCs.
NetISA suite app. 286 minimum. 24 audio devices, MDA through SVGA. Trackers, MIDI, WAV, and chiptunes play on the host. Compressed formats and streaming go through the NetISA card’s ESP32 in v1.1.
v1.5.1 release — 2026-05-02
Tagged at v1.5.1. v1.5.0 plus the three deferred follow-ups its release notes flagged as v1.6 work, brought forward into a same-day patch.
LHA depacker for YM5 / YM6. Every YM file in the Atari ST chiptune corpus ships LHA-compressed (typically -lh5-); v1.5.0 only accepted the rare uncompressed YM3 form. v1.5.1 adds a from-scratch implementation of the LHA level-0 / level-1 header parser and the LH5 algorithm (8 KB sliding-window LZSS with static Huffman codes for both the literal/length and offset alphabets). Wraps the existing AY synth, so YM5 / YM6 streams (which have a richer header and 16 registers per frame versus YM3’s 14, with column-major OR row-major layout depending on the A_STREAMINTERLEAVED attr bit) load and play through the same code path as YM3. Validated end-to-end on 86Box via two new wav-matrix cells: an LH0 (stored) wrap of a real YM3 file, and an LH5 (literal-only encoded) wrap of a synthetic YM5 stream. The LZ back-reference path of the LH5 decoder is verified with an additional ABABA round-trip fixture decoded by a Python port of the C decoder. Implementation in src/decode/lha.c + lha.h, ~370 LOC. Read from the Yoshizaki LHA spec; lhasa (ISC) was consulted only for the LH5 constants (DICBIT=13, NC=510, NP=14). MIT-clean, no GPL contamination.
FX:N counter coverage extended. v1.5.0 wired the FX:N activity badge on the now-playing pane only for the post-v1.4 trackers (STM / FAR / ULT) where the per-channel modulator state was already memorized for the per-tick effects pump. v1.5.1 adds *_active_fx accessors to the older trackers (MOD, S3M, XM, IT, MTM, 669) so the badge surfaces wherever the engine actually pumps a continuous effect. MOD reports tone porta, vibrato, tremolo, arpeggio, and note-delay countdowns; S3M reports tone porta (G), vibrato (H), tremor (I), retrig (Q), arpeggio (J); IT reports tone porta + vibrato. XM and 669 surface only what their MVP engines currently model (XM = Axx volume slide; 669 = no per-tick effects yet) so the badge is honest rather than misleading.
Tone-porta-without-instrument fallback fixtures. v1.5.0 implemented the “Gxx with note column populated but instrument column empty → slide using whatever sample is currently playing” semantics for STM / FAR / ULT (the convention real-world S3M/STM/FAR/ULT music routinely writes), but didn’t ship regression coverage. v1.5.1 adds three new fixtures — FXSTM5, FXFAR5, FXULT6 — each exercising the fallback path with a control row (porta with instrument) followed by two fallback rows (porta without instrument, sliding both up and down). All three pass deterministic on 86Box.
33 wav-matrix cells now PASS deterministic (was 30 in v1.5.0); HEARO.EXE grew from 231 KB to 235 KB (+4 KB for LHA + the older-tracker FX accessors).
v1.5.0 release — 2026-05-02
Tagged at v1.5.0. Six new decoders, AY chip music with streaming synth, full per-tick effects pump on STM / FAR / ULT, animated splash intro with OPL2 fanfare, four phases of UI catch-up, three new themes, and a 320CDT YMF715 research dossier with both a documented user workaround and a staged native EEPROMless wake path. Three-round pre-release quality gate caught 22 issues (3 Critical + 19 Important) before tag. 30/30 wav-matrix cells PASS deterministic.
v1.5 development log — 2026-05-01
Six new decoders shipped on top of v1.4. CMF (Creative Music File, OPL2 + embedded MIDI track), HSC (HSC AdLib Composer, pattern-based OPL2), STM (Scream Tracker 2, 4-channel PCM), RAD v1 (Reality AdLib Tracker, OPL2 with a 32-pattern offset table), FAR (Farandole Composer, 16-channel PCM, C5 reference at 16726 Hz), and ULT (UltraTracker V004 with column-major RLE patterns). Plus an AY-3-8910 / YM3 register-stream player covering the ZX Spectrum 128 / Amstrad CPC / Atari ST chip-music corpus: 3 tone channels at 12-bit period precision, 17-bit Galois LFSR noise, all 8 functional envelope shapes, per-channel envelope-follow, and a streaming synth that lifts the initial pre-render cap so songs of any length play.
Total decoder count is now 16, all covered by an end-to-end audio regression. A per-format TESTPLAY plus fixture packs into an 86Box VM, the /W render path drives the decoder and mixer with FPU forced off and writes a deterministic byte stream, then the harness mounts the VHD and hashes the rendered WAV against per-cell baselines. PCM trackers hash the mixer output directly; OPL formats route through Nuked-OPL3 host synthesis so the hash captures chip-write ordering instead of just the raw register stream; AY uses HEARO’s own software synth. A peak-amplitude floor was added after a real regression where a baseline regenerated against silence still hashed deterministically and looked healthy.
LHA-packed YM5 is the next AY follow-up. Every YM file in the wild ships LH5-compressed; the recognizer accepts raw YM3 today. Adding the LHA depacker is its own ~600 LOC chunk plus corpus-fixture sourcing, so it sits in its own session.
Effect coverage on STM, FAR, and ULT expanded into a full per-tick effects pump. STM honors Axx (set speed), Bxx (position jump), Cxx (pattern break), Dxx (volume slide), Exx / Fxx (pitch slides), Gxx (tone portamento), Hxx (vibrato), Jxx (arpeggio), and Oxx (sample offset). FAR honors Fxx (set tempo), Dxx / Exx (fine tempo deltas), 6xx / 7xx (volume slide up / down), 3xx (tone porta), and 5xx / 8xx (vibrato — FAR splits vibrato across two effect codes). ULT honors 1xx / 2xx (portamento up / down), 3xx (tone porta), 4xx (vibrato), 7xx (tremolo), 9xx (sample offset), Axx (volume slide), Bxx (position jump), Cxx (set volume in either effect column), Dxx (pattern break), and Fxx (set speed). The wav-matrix grew from 19 to 30 cells with one new fixture per format-effect-group, plus an AY-3-8910 envelope-shape regression cell that cycles all 8 functional shapes against a baseline that AYFULL (which only exercises shape 0x0A) doesn’t catch.
UI catch-up — 2026-05-01
After the post-v1.4 feature blitz the UI needed to catch up so users could see and reach what was actually shipping. Four passes landed today: Phase 1 visibility added live indicators to the bottom status bar ([EQ], [REV:Cathedral], [Wide]/[Karaoke] separation modes, [V:Plasma] for the current visualizer) plus a format badge in the now-playing pane ([STM], [AY/YM3]) that brightens when the active format has effect coverage. Discovery was previously by reading the README; now it’s by glancing at the screen.
Phase 2 promoted env-var features into the UI. The stereo-separation knob was previously reachable only by setting HEARO_SEPARATION=narrow before launch; it now lives at Settings → Stereo mode with a live picker for Full / Narrow / Mono / Wide / Karaoke. Reverb and EQ presets already had pickers; the status bar now confirms what’s active.
Phase 3 tightened discoverability. The boot screen got a “Try: Alt-S Settings, V cycles visualizers, F2 Unlock matrix, Alt-H Help” tip line below the unlock count, so first-time users have a concrete first action. The browser’s empty state replaced “(no music files in this directory)” with actionable hints (Backspace to parent, Alt-F to open by path, or filter status when an extension filter is active). The now-playing pane’s stopped state replaced the empty artist / album lines with “ENTER in browser to play. Alt-F: open by path. V: cycle viz.”
Phase 4 added curated themes. Three new built-in palettes joined the existing six: Borland Blue (Turbo Pascal IDE blue / yellow / cyan), Norton Commander (black-on-cyan with the file-manager bones), and Tokyo Night (modern dark purple with soft accents). The theme picker already had live preview, so cycling through the new palettes is instant. Total built-in count is now 9 plus the user-defined slot.
Animated splash intro — 2026-05-01
The post-v1.4 launches needed a moment of theatre, in the spirit of the old Apogee / Sierra studio splashes. HEARO now plays a brief animated intro before the diagnostic boot screen lands.
Four phases in roughly 3.5 seconds. Reveal: a column-by-column wipe walks left-to-right across the HEARO logo with a CGA-snow flicker zone behind the wavefront, evoking the CRT-warm-up feel without needing per-pixel work in Mode 13h. Fanfare: a three-note OPL2 ascending arpeggio (C5, G5, C6) keys on at 25%, 50%, and 75% through the reveal so the music and the visual land together. Hold: full-intensity logo with a "NetISA Music Player" subtitle for one second. Dissolve: the VGA palette fades to black across ten vsync-gated steps, then control returns to the boot screen.
Any keypress skips. --no-intro, HEARO_INTRO=off, or --safe on the command line opts out entirely so first-time problem diagnosis isn’t gated behind theatre. On hardware with no OPL chip the visual still plays, just silently. Implementation is text-mode + INT 10h palette tricks, ~250 lines, integrates with HEARO’s existing theme_apply for state restore. Lives in src/ui/intro.c.
scripts/capture-intro-gif.ps1 (ffmpeg gdigrab into DOSBox-X, palette-quantised to GIF). The OPL2 fanfare doesn’t survive the GIF; for the audio, reach for the binary on real iron or a DOSBox-X build.The architectural piece behind this is a process_tick() per-format that runs on every non-row tick, pushing volume and frequency deltas through the mixer in the same scaling space the row processor uses. ULT cells widened to 7 bytes to carry both effect columns natively; STM cells stayed at 5; FAR cells stayed at 4 because FAR’s effect parameter is already 4 bits, so cmd<<4 | param packs into a single byte. Tone portamento, vibrato, and tremolo are deferred — they need memorized per-channel target state (Gxx remembers a target note, Hxx remembers depth and speed) that the dispatch path doesn’t yet carry. Twenty-five-of-twenty-five cells PASS deterministic across reruns.
v1.4.0 release — 2026-04-30
Tagged at v1.4.0. The polish-and-visuals milestone: 2-pole resonant IT filter, five FPU-gated text-mode visualizers, Mode 13h fullscreen plasma, 3-band parametric EQ, light Schroeder reverb, S3M effect-set expansion (with an S/T/U dispatch bug fix that had been silent since v1.0), GENMIDI bank loader path expansion, M3U save/load, EQ + reverb preset libraries, browser extension filter, theming Layer 5 (custom palette editor + per-role override picker + .THM hot-reload + theme exporter), and a five-round red-team review campaign that caught seven real bugs that smoke tests missed.
Visualizers
Eight modes. V cycles. Spectrum, VU, Bars work on any iron; Plasma, Tunnel, Fire, Particle, Wireframe are FPU-gated and skipped on FPU-less hardware. Audio keeps playing through the cycle — the spectrum-style modes pick up the live sample feed; the demoscene-style modes self-animate from frame counters.
Plus a fullscreen Mode 13h plasma at 320×200×256 (View → Graphical viz). Pre-computed sine table + per-frame phase tables make the inner loop three array lookups per pixel; comfortably 30+ fps on a 486.
Theming
Layer 5 of the theming system shipped with v1.4: 7 palettes × 7 schemes × 6 bundles = 294 baseline combinations, plus per-role overrides for the 28 named roles, plus an in-app palette editor with live VGA DAC preview, plus .THM extension files. Two examples below.
Settings + Hall
Boot screen
The capture pipeline that produced these shots is fully automated: per-shot HEARO.CFG sets the visualizer / palette / scheme target, per-shot DOSBox-X autoexec runs DEBUG.EXE to pre-fill the BIOS keyboard buffer at 0040:001A with a navigation key sequence (Enter dismiss boot, 7 Down keys, Enter to play TONE.MOD). HEARO consumes the buffer naturally via INT 16h AH=10h. The trick bypasses DOSBox-X SDL2’s input filter that silently drops SendKeys / SendInput from PowerShell. Source at scripts/capture-v14-shots.ps1.
What shipped in v1.4, in commit order:
- IT 2-pole resonant biquad. Replaces the 1-pole IIR with a Direct Form II Transposed biquad. RBJ cookbook coefficients in Q13. Z40-Z7F sets cutoff, Z80-ZFF sets resonance independently. Filter state preserved on coefficient updates so live cutoff sweeps don’t click.
- Five text-mode visualizers. Plasma, Tunnel, Fire, Particle, Wireframe. All FPU-gated. Each one is a self-contained renderer in
src/ui/spectrum.cinteger-only on the inner loop. - Mode 13h fullscreen plasma. 320×200×256 graphics. Pre-computed sine table + per-frame phase tables keep the inner loop free of CORDIC. Audio keeps playing through the graphics mode via sb_pump / pc_pump between frames.
- 3-band parametric EQ + Schroeder reverb. Mixer output stage. EQ low/mid/high at 100 Hz / 1 kHz / 8 kHz, ±12 dB per band, with picker UI and HEARO.CFG persistence. Reverb is 4 comb + 2 allpass at ~1.5 sec tail.
- S3M effect set expansion. I (tremor), J (arpeggio), K (vibrato + volume slide), L (tone porta + volume slide), O (sample offset), Q (retrigger), V (global volume), S8x (pan position). Plus a fix for an S/T/U dispatch bug that had been off-by-one since v1.0.
- Theming Layer 5. Custom palette editor with live VGA DAC preview, per-role override picker for 28 named roles, .THM extension file format, hot-reload, theme exporter.
- Stereo widening + karaoke vocal removal. Mid/side decoder with side-gain push for widening; center-channel cancel for karaoke. Triggered via HEARO_SEPARATION env var.
- EQ + reverb preset libraries. 8 EQ presets (Flat / Rock / Jazz / Vocal / Bass Boost / Treble Boost / Classical / Loudness) and 6 reverb presets (Off / Small Room / Large Hall / Cathedral / Plate / Chamber). Each writes preset gains to HEARO.CFG.
- M3U playlist save / load. Standard M3U format with optional #EXTM3U header. Persists the user’s queue between sessions.
- Browser extension filter. ‘F’ key prompts for an extension; only matching files show until cleared.
- INT 16h AH=10h enhanced keyboard read. Some real-iron BIOSes (Toshiba 320CDT family observed) drop scan codes on Alt+letter combos via the legacy AH=00h path. Switching to AH=10h fixes Alt+menu shortcuts on real hardware.
v1.4 quality — the red-team campaign
After v1.4 shipped, a five-round red-team review campaign across all chunks (audio engine, mixer DSP, visualizers, tracker decoders, theming) caught seven real bugs that the smoke tests missed:
- EQ high band silently broken since v1.4-E — the 8 kHz omega calculation overflowed s32 (8000 × 411775 = 3.29e9), wrapped negative, clamped to 1, and the band ran as a near-DC filter instead of 8 kHz. Fixed with a Q14 pi rearrangement that fits cleanly in s32.
- Reverb 256× too quiet since v1.4-I — the wet path was clamped to s16 but the dry signal was in s24 (post-master). Effective wet/dry was ~0.1% / 99.9%; reverb was functionally inaudible. Fixed with proper scaling at the comb buffer boundary.
- S3M tremor (effect I) silenced channels instead of toggling — the on-phase comment said “volume stays” but the off-phase had set the mixer’s sticky target to 0; the on-phase needed to actively re-write the channel volume. Effect I shipped silent.
- S3M K corrupted memorized H vibrato params — K’s par is volume-slide-only per spec; the vibrato leg uses prior H’s memorized speed/depth. HEARO was overwriting H’s memory with K’s slide nibbles every K row.
- S3M V stomped user master volume — effect V was calling mixer_set_master directly, leaking song state into the user’s preferred volume. Now writes a song-internal global_volume scalar applied at the per-channel volume helper.
- IT filter persistence reset on note trigger — broke the “filter persists across notes” spec semantic. A subsequent resonance-only Z80-ZFF would silently kill the filter mid-song.
- Mode 13h palette wrote 6 bytes past its 256-entry buffer — 6 bands × 43 entries = 258 entries written into a 256-entry buffer. Direct DGROUP corruption.
Every one of these passed the smoke test (frame counts correct, no crashes) but produced wrong audible / visual output. The smoke test verifies frame counts and crash-freedom; the red-team campaign verifies what the smoke test can’t. Each fix shipped as its own commit per round and is on origin/main.
v1.3.0 release — 2026-04-28
Tagged at v1.3.0. The demoscene-polish milestone: engine fidelity for XM and IT, three visualizer modes, real now-playing metadata, plus a same-day v1.0 hardening pass that closed 12 review findings and imported five auplay-inspired SB/DMA improvements.
What shipped, in commit order:
- Cluster A — visualizer triad. The bottom-right pane cycles between three modes via the
Vkey: classic spectrum (default), a stereo VU meter with peak-hold dots, and frequency bars with floating peak caps and tri-color zones. Pure UI-side addition; no audio engine touched. Pattern observed from rajeevt2001/Dos-Music-Player. - Cluster B — XM pan envelope + IT volume envelope. XM pan envelope was parsed but not wired; the commit applies it as an additive offset to mixer pan with the FT2-compatible curve. IT instrument-mode files now run their volume envelope and fadeout end-to-end, with note-off release vs note-cut hard-silence semantics.
- Cluster C — IT pan + pitch envelopes. The pan envelope (parsed in B) wires through to mixer pan as a clamped offset. The 82-byte pitch envelope (previously
fseek’d past) applies a Q16 frequency multiplier per tick, mapping its −32…+32 semitone range through a precomputed table. Filter mode (flags bit 0x80) is honored by skipping pitch modulation, leaving the envelope intact for the lowpass pass. - Cluster D — IT lowpass filter. Per-channel 1-pole IIR lowpass, gated on
filter_activeso non-filtered channels pay only a single-byte test on the hot path. IT effect Z (letter 26, Z00…Z7F) sets cutoff via the default macro. The mixer computes the IIR alpha at the active output rate from the cutoff Hz, so the same effect plays at the same audible cutoff regardless of mixer rate. - Cluster E — IT NNAs (basic). New Note Actions are honored via a ghost-voice pool. When a logical channel triggers a new note and its instrument’s NNA byte is non-zero (Continue / Note Off / Note Fade), the existing voice migrates to a ghost slot in
chans[num_channels..31]while the logical channel proceeds with the new note. Both voices mix independently until the ghost’s envelope drains. Newmixer_clone_voiceAPI copies the full voice state underirq_save. - Cluster F — real now-playing metadata. WAV LIST/INFO sub-chunks (INAM/IART/IPRD/ICRD), MIDI track-0 sequence-name (FF 03 meta event with proper VLQ event walk, 1024-byte scan window), and VGM GD3 tag block (UTF-16LE → ASCII lossy decode for track name + author EN). The empty-state placeholder strings (“Axel F / Harold Faltermeyer / Beverly Hills Cop OST” demo defaults) were neutralized to read as ready-and-waiting.
Same-day hardening: 12 issues closed from external code reviews (mixer loop-bound clamping, safe_fmalloc 64K policy, irq_save/irq_restore helpers, MOD per-pattern allocation, S3M out-of-bounds note guard, XM short-header zero-init, mixer frequency overflow fix, modal UI audio pump, browser extension sync, nowplay_advance wiring, S3M packed/stereo flag rejection); five auplay-inspired SB/DMA improvements (DSP4 IRQ self-detection, INTSTAT-driven IRQ ack with ack-both fallback, DSP_END_DMA + 0xD9/0xDA bug fix, audio_callback returns u16 + EOF wiring, unified DMA register tables).
Three rounds of iterative code review closed clean: 5 → 1 → 0 Critical+Important findings. The Round 2 finding was a u32 overflow in IT pitch-envelope frequency multiplication on high notes (~250 kHz base_freq times max-positive envelope multiplier exceeded u32); fixed via a split-shift form. Source & commits.
Status
2026-04-30, v1.4.0 released. Compiles clean under Open Watcom V2. HEARO.EXE is 189 KB; the seven test programs build alongside it. DOSBox-X SB16 sentinels match across every commit (WAV 90112 / MOD 90112 / IT 90112 / MIDI 133120 / VGM 90112 at /T4 and /T6). Real-iron PC Speaker validation passed on the Toshiba 320CDT (8 formats decode + play, no crashes); the OPL3-SA path is hardware-blocked behind a Toshiba-specific power gate documented in 320cdt-test-methodology.md. Primary real-iron audio target is the 486 DX-2 + Vibra 16S box.
What is in the tree:
- Eight detection modules: CPU, FPU, video, audio, memory, NetISA, input, orchestrator.
- Unlock matrix, around 70 rules, data driven.
- Boot screen, layout above.
- Four-pane text-mode UI: file browser, playlist, now playing, ASCII spectrum. Pull-down menus, settings panel, Hall viewer.
- Math: 24-iteration adaptive CORDIC, 4 KB bipartite sin/cos/log/exp tables, 256-bit fixed-point accumulator.
HEARO.CFGreader/writer,HEARO.HALpersistent log.- Six test programs.
TESTBIPreports 13.4 bits sin precision against 1024 reference samples.TESTCORDshows monotonic precision improvement from 8 to 24 iterations.TESTQUIRshows the quire holding overflow that the naive 32-bit sum drops. - Watcom
wmakeMakefile. - Real probes in
src/platform/probes.c: Watcom#pragma auxwith.286/.386/.586directives for FPU presence and EFLAGS toggle and CPUID, plusint86()calls for INT 10h/12h/2Fh/33h/67h. Default build now compiles them in.HEARO_NOASMgate stays for users who want synthetic stubs. - DOSBox-X screenshot script in
hearo/scripts/.
Boot screen
One line per detected component, status word right justified, unlocked features indented under the component that enabled them. Last line: feature count.
Unlock matrix
Each detected expansion enables specific features. Around 70 rules. Each rule is one row in a table: name, description, requirement string, pure-function check against hw_profile_t. Adding a feature is one line.
- FPU (16): 256-bin FFT, sinc resampling, 16+ channel tracker mixing, plasma, tunnel, particles, fire, wireframe, karaoke, 10-band parametric EQ, convolution reverb, stereo widening, gamma-correct dithering, software quire, adaptive CORDIC, log-domain effects.
- Audio (33): RealSound PWM, Tandy/PCjr PSG, Covox, Disney Sound Source, OPL2 / OPL3 MIDI, AWE64 CQM, SB PCM tiers (mono, auto-init, stereo, 16-bit, ASP, full duplex on DSP 4.13+), GUS hardware mixing + DRAM tier + GUS MAX line-in + CS4231 codec, Ensoniq wavetable + DAC + filters, AWE SoundFont + EMU8000 DSP + 32 voices + SIMM RAM, MT-32 LA, SoundCanvas (SC-55+), Yamaha XG, AdLib Gold DAC + surround, MPU-401 + WaveBlaster, Pro Audio Spectrum 16, ESS AudioDrive, Turtle Beach 56001 DSP.
- Video (6): SVGA 1024 / 800 / 640, 256-color art, hi-res art at 1MB+ VRAM, chipset blits.
- Memory (2): full library index at 4MB+ XMS, all visualizers preloaded at 8MB+ XMS.
- Network (5, NetISA): streaming, scrobbling, cloud library, Bluetooth out, AirPlay.
- FPU-less (2): stochastic-computing particles, 64-bin bipartite-table FFT.
Detection
Eight modules, each one self-contained so a misbehaving probe can be turned off in one place.
- CPU. FLAGS bit walk classifies 8086/186/286/386+.
CPUIDwhen available. PIT-channel-2 timing measures actual core clock against the period nominal list. Anything >10% above nearest nominal flagged as overclocked. - FPU.
FNINIT/FNSTSWpresence. Control-word width separates 287 from 387+. IIT 2C87 brand probe at port 0E0Ch. Cyrix FasMath via CCR3 at 22h/23h. Integrated FPUs follow the CPU vendor. - Video. MDA at 3B4h, CGA at 3D4h. Hercules via 3BAh status toggle. EGA via INT 10h AH=12h BL=10h. VGA via INT 10h AX=1A00h. VESA via INT 10h AX=4F00h with VBE2 prestamp. Chipset probes for S3 (CR30 after 38h/39h unlock), Cirrus (3C4h:06=12h), Trident (3C4h:0Bh), Tseng ET4000 (3CDh write/readback), Paradise (3CEh:0Fh=05h), Oak (3DEh sentinel), Chips & Tech (3D6h sentinel).
- Audio. PC Speaker always set. Tandy via BIOS sig at F000:FFFEh + port C0h. LPT1 walked for Disney FIFO then Covox loopback. AdLib via OPL timer test at 388h, OPL3 mirror at base+02h/03h, AdLib Gold via CT1703 mixer at 38Ch. Sound Blaster: parse BLASTER, reset DSP, read version: 1.x / 2.x / 3.x (Pro vs Pro 2 by OPL3) / 4.x (SB16 vs ASP vs AWE32 vs AWE64). GUS: parse ULTRASND, reset GF1 reg 4Ch at base+103h, walk DRAM, probe CS4231 codec at base+10Ch for MAX. MPU-401 reset/UART handshake at 330h/300h/320h/340h. Ensoniq SoundScape via OTTO chip ID. PAS-16 via mixer signature 0x50. ESS AudioDrive via DSP cmd E7h. Turtle Beach via 56001 host port at 250h/260h/290h/320h.
- Memory. Conventional via INT 12h. XMS via INT 2Fh AX=4300h then 4310h then AH=08h. EMS via INT 67h AH=42h.
- NetISA. Read base ports 300h/320h/340h/280h, look for
NI./STUBNETsynthesises a present card. - Input. Mouse via INT 33h AX=0000h. Joystick via port 0x201.
- Orchestrator. Runs modules in dependency order. Computes 32-bit FNV-1a fingerprint over stable parts of the profile. Stamps detection date.
Per-device probe protocols: docs/hearo-soundcard-reference.md.
Video tiers
Text-mode tier (Minimal) is what shipped in v1.0. Graphical tiers are scaffolded only; real Mode 13h / VESA framebuffer code is v1.3.
Hall of Recognition
Plain text file (HEARO.HAL). Hardware first-seen dates, lifetime stats. Editable with any text editor.
Install an FPU, the next boot says it is new. A year later the boot screen says so on the same calendar day. No achievements or scores.
Format support
Host: WAV (PCM 8/16, mono/stereo), MOD (4/6/8 ch), S3M, XM, IT (envelopes + NNAs + 2-pole filter), MTM, 669, STM, FAR, ULT, MIDI (SMF), VGM (SN76489 + OPL2/3 + YM2612), CMF, HSC, RAD v1, AY/YM3.
ESP32 (v1.1+): MP3, FLAC, Opus, Vorbis, AAC, WMA, ALAC.
Streaming (v1.1+): Icecast/SHOUTcast, Bandcamp, SomaFM, Internet Archive, Nectarine Demoscene Radio, ModArchive.
Compressed formats decode on the ESP32 because real-time MP3 decode below a fast 486 does not work. Without the NetISA card those extensions are greyed out in the file browser.
Math
- Adaptive CORDIC. Iteration count varies with screen size and frame budget. 320x200 plasma at 30 fps on a 386SX = 8 iterations. 1024x768 on a 486DX2 = 24.
- Software quire. 256-bit fixed-point accumulator. Eight 32-bit words, two’s-complement, full carry. Posit Standard 2022 quire concept adapted to fixed-point.
- Bipartite tables. sin/cos/log/exp from two table lookups + add. ~8 bits accuracy in ~4 KB. Fast enough for a 286.
- Stochastic particles. Probability bits + counters. No multiplications.
- Log-domain effects. Compressor/limiter/EQ in log domain (Takum 2024). Avoids many multiplies.
- 8087 silicon fingerprint.
FPATANandFYL2Xbit patterns differ per vendor (IIT, Cyrix, ULSI, AMD, Intel). Used to identify the FPU brand without CPUID.
Roadmap
- v1.0: Foundation. Native formats, unlock matrix, boot screen, Hall, text UI. Builds clean. Toshiba 320CDT bench pass still pending.
- v1.1: Streaming. ESP32 path live, internet radio, Bandcamp, ModArchive. Single-allocation cap above 64 KB for whole-file loads (WAV / MIDI / VGM streaming, large tracker samples).
- v1.2: Library. MusicBrainz tags, scrobbling, cover art, lyrics, ReplayGain, smart playlists.
- v1.3 (released, 2026-04-28):
- Engine fidelity: XM volume + pan envelopes; IT volume + pan + pitch envelopes; IT lowpass filter (Z40…Z7F, rate-independent cutoff); IT NNAs (Cut / Continue / Off / Fade-as-Off) via ghost-voice pool.
- Visualizers: VU meter + frequency bars alongside the existing spectrum;
Vcycles modes. - Metadata: WAV LIST/INFO sub-chunks, MIDI track-0 sequence-name, VGM GD3 tag block.
- Deferred to v1.3.x / v1.4: STM / FAR / ULT loaders, EQ, skins, graphical tiers (320, 640, 800, 1024), 2-pole resonant IT filter, hardcoded fade rate for NNA=Note Fade when instrument fadeout is 0.
- v1.4 (released, 2026-04-30):
- 2-pole resonant IT filter (RBJ cookbook biquad). Five FPU-gated text-mode visualizers (plasma / tunnel / fire / particle / wireframe). Mode 13h fullscreen plasma at 320x200x256. 3-band parametric EQ at the mixer output. Light Schroeder reverb. Stereo widening + karaoke vocal removal mixer modes. M3U playlist save/load. EQ + reverb preset libraries. Theming Layer 5 (palette editor + per-role override picker + .THM hot-reload + exporter).
- Five-round red-team review caught seven real bugs the smoke tests had missed: EQ high band silently broken (s32 omega-calc overflow), reverb 256x too quiet (s24/s16 scale mismatch), S3M tremor silenced channels instead of toggling, S3M K corrupted memorized H vibrato params, S3M V stomped the user’s master-volume preference, IT filter persistence reset on note trigger, Mode 13h palette wrote 6 bytes past its buffer.
- v1.5 (active, post-v1.4 main):
- Six new decoders: CMF, HSC, STM, RAD v1, FAR, ULT.
- AY-3-8910 / YM3 register-stream player with full noise + envelope generators and a streaming synth (no length cap).
- 25-cell wav-matrix audio regression with peak-amplitude floor; Nuked-OPL3 host synth integration for OPL-format coverage.
- Shared tracker tables (vibrato sine, arpeggio Q16) consolidated to single defs in
decode.c; clears W202 noise on every consumer TU. - Per-tick effects pump on STM / FAR / ULT: sequencer control (STM Axx / Bxx / Cxx, FAR Dxx / Exx / Fxx, ULT Bxx / Dxx / Fxx), volume slides (STM Dxx, FAR 6xx / 7xx, ULT Axx), pitch slides (STM Exx / Fxx, ULT 1xx / 2xx), and ULT Cxx set-volume on either effect column. Eight FX-suffixed wav-matrix cells exercise the new paths.
- Makefile header dependencies (a struct-size mismatch from a stale
.objbit me during the streaming AY refactor; now documented and the Makefile force-rebuilds on header touch). - Open follow-ups: LHA depacker (so YM5 files in the wild can play; today’s recognizer accepts raw YM3 only); tone portamento / vibrato / tremolo on STM / FAR / ULT (need memorized per-channel target state that v1.x dispatch doesn’t yet carry).
- v1.6: Network audio. Bluetooth out, AirPlay, Chromecast, DLNA, multi-room. Bare-DOS YMF715 PnP isolation (Toshiba 320CDT cold-boot).
- v1.7: Services. Spotify Connect target, YouTube Music, podcasts, audiobooks.
Suite
HEARO is one of nine NetISA suite apps. Shared INI config grammar, Hall file format, boot-screen layout, command-line conventions (/SAFE, /REDETECT, /STUBNET).
Hardware
286 is the floor. V20 + 8087 + 640K + CGA/EGA + AdLib/SB gets a degraded path that still plays trackers and MIDI. RADIO is the lighter sibling for true XT-class machines.
Technical
HEARO.EXE: real mode, large model, 286+. HEAROXM.EXE: 32-bit flat, DOS/4GW, 386+. Both ship together; 32-bit preferred when available, 16-bit is the universal fallback.
Layout: docs/hearo-design.md, docs/hearo-soundcard-reference.md. hearo/src/ (35 modules: detect, unlock, ui, math, config, platform, stub). hearo/test/ (six test programs). hearo/data/unlocks.def. hearo/scripts/ (DOSBox-X screenshot toolkit). hearo/Makefile.
FAQ
- Will it run on my 286?
- Yes. 286 + 1 MB + MDA + PC Speaker is the floor. Text-mode UI works on every adapter from MDA up.
- What audio devices are supported?
- Twenty-four. PC Speaker, Tandy/PCjr PSG, Covox, Disney Sound Source, AdLib (OPL2), AdLib Gold (OPL3 + 12-bit DAC), Sound Blaster 1.x / 2.0 / Pro / Pro 2 / 16 / 16 ASP / AWE32 / AWE64, Gravis UltraSound Classic / MAX / ACE / PnP, MPU-401 with SysEx-identified MT-32 / CM-32L / SC-55 / SC-55mkII / SC-88 / SC-88 Pro / DB50XG / SCB-55, Ensoniq SoundScape, Pro Audio Spectrum 16, ESS AudioDrive, Turtle Beach MultiSound. Probe protocols in the soundcard reference.
- Does HEARO play MP3 / FLAC / Opus?
- Yes, on the ESP32. Compressed formats decode on the NetISA card and arrive at the host as PCM. Native formats decode on the host. Without a NetISA card, compressed extensions are greyed out. v1.0 ships native-only; v1.1 turns on the ESP32 path.
- How does the Hall of Recognition work?
- Plain text file. Each boot, HEARO compares detection against the previous fingerprint and appends new components with their first-seen date. Stats accumulate (hours played, tracks, boot count, peak features). Just a record.
- What unlocks the FFT spectrum analyzer?
- Any FPU. Without an FPU, you get a 64-bin bipartite-table FFT. Fast enough for a 286.
- What does the NetISA card do for HEARO?
- Streaming and compressed-format decode. v1.0 native-only; v1.1 turns on Internet radio (Icecast/SHOUTcast), Bandcamp, SomaFM, Internet Archive, ModArchive, plus MP3/FLAC/Opus/Vorbis/AAC.
- Does it work in DOSBox-X, 86Box, PCem?
- Yes. Standard BIOS calls + direct VRAM. Audio detection works in DOSBox-X with the standard SB + GUS emulation.
- License?
- MIT. Same as the rest of the suite.
- Where is the source?
- BarelyBooting/netisa/hearo
Links
- BarelyBooting/netisa source archive (HEARO is in
hearo/) - HEARO design document
- HEARO soundcard reference
- hearo/README.md
- NetISA project page
- CERBERUS project page
- Build log