Repository navigation
0.3.0
Changes since the last Release
Fixed
-
MHS REPL Echoed Every Line Twice And Printed Results Late: psnd's editor draws the line, then writes it into the PTY, where the terminal driver echoes it back and psnd printed that too. Output was also collected after a fixed 100ms sleep rather than read until MicroHs prompted again, so a result slower than that --
midiInitopening CoreMIDI, for one -- appeared under the next prompt, and the echo split across reads showed up as lines missing their first character. psnd now matches the echo against what it just sent and drops it, and drains the PTY until the prompt returns or 5s pass, so a result lands under the line that produced it (repl.c) -
Schedule Growth Ignored
reallocFailure:schedule_grow()assigned the result ofrealloc()straight tosched->eventsand raisedcapacitywhether or not the allocation succeeded, so a failed grow lost the existing buffer and the caller then wrote an event through a null pointer. It now grows through a temporary, rejects a capacity whose byte size would overflowsize_t, and reports failure; all thirteen scheduling entry points drop the event instead of writing past the buffer (shared_async.c) -
Tracker Gate Wrapped Instead Of Clamping:
tracker_notes_parse_gate()cast an unboundedintto itsint16_toutput, so~65536became a gate of 0 and other values became negative durations. Gates now clamp toINT16_MAX, matching the clamp velocity already applies at 127.parse_int()saturates as well, having been undefined behaviour on any expression carrying more digits than anintholds (tracker_plugin_notes.c) -
MHS Package Preload Grew
.mhscacheWithout Bound: psnd passed-pbase -pmusicon everymhsinvocation. MicroHs appends preloaded packages to the cache it just read without checking whether they are already there, so each run added ~2.3MB and about a second of load time: 3s at run 1, 25s by run 12, and eventually amhs_smoke_teststimeout whose kill left a zero-length cache that every later run aborted on. The packages survive in the cache, so psnd now preloads only when the cache is missing, empty, or older than the binary, and deletes the cache in the latter two cases rather than mixing package copies.mhs_cache_needs_preload()sits invfs.cso the standalonemhs-midivariants get the same guard. Upstream MicroHs has the same unconditionaladdPackageonmaster, so the version bump does not fix it (vfs.c,repl.c,mhs_midi_standalone_main.c) -
Edited MHS Files Kept Running Their Old Code:
psnd mhs -r file.hsandpsnd play file.hsserved whatever was compiled the first time, until.mhscachewas deleted by hand. MicroHs keys a cached module by the identifier the command line gave it, so a file argument is stored underfile.hswhilevalidateCachelooks the entry up under the module's declared name, finds nothing, and checksums nothing; passing the same module by name validates correctly. psnd now reads the declared module name out of the file and passes it with-ifor the directory the name implies, falling back to the path when the file does not sit where its module name says it should, which is the one case that stays stale.mhs_reload_testscovers it: run a module, rewrite it, run again, assert the new output. Present since MicroHs 0.15.0.0, reported upstream with a patch inpatch-mhs-validate-file-arg.diff(repl.c) -
Every MHS Run Rewrote The Whole Compile Cache: psnd passed
-C, so each run re-serialized.mhscacheeven when nothing in it changed. MicroHs 0.16 compresses that file with LZMA instead of LZ77, which put ~60% of a warm run inside the LZMA encoder: 1.85s of the 2.15s upstreammhsspends on one warm file, against 0.30s with-CR. psnd now passes-CRon a warm cache and-Conly when cold, keyed off the same test that gates the preload flags. A warmpsnd mhs -r Smoke.hsis 0.41s, from 4.25s;mhs_smoke_testsis 0.49s, from 4.37s. A warm run no longer persists a module it just compiled, which costs 0.3s on an unchanged small file and nothing on a changed one (vfs.c,vfs.h,repl.c,mhs_midi_standalone_main.c) -
macOS Link Flags Overflowed The MHS argv Array:
LINK_EXTRA_ARGSwas 14 in both branches of its#ifdef __APPLE__, but the macOS branch pushes 20 entries -- three static libraries, three frameworks, and-lc++. Everypsnd mhs -o exe file.hswrote four pointers past the allocated argv and mhs then read heap garbage as a module name, failing withFile not found: "(". The macOS count is now 20 (repl.c) -
make testHad No Per-Test Timeout: a test blocking on stdin ran until the caller's own timeout with no indication of which test hung. The tenctesttargets now share onePSND_CTESTvariable carrying--timeout 120, the ceilingscripts/build_release.pyalready used (Makefile)
Changed
- Vendored MicroHs 0.15.0.0 -> 0.16.5.0: 553 upstream commits. The predicted blocker, 0.16's
getPathsreturning no package directory whenMHSDIRis set, does not apply:-afillspkgPathsindependently and psnd already passes it. What the bump did need wasmhs.conf, renamed fromtargets.confupstream and now fatal rather than advisory on the compile-to-executable path, somhs-embedgained--confand serves it from the virtual root. Compilation itself is unchanged: the same six modules compile to C in 1.44s under 0.15.0.0 and 1.42s under 0.16.5.0, a three-line module in 0.50s under both, and a warm run that only reads the cache is 0.28s against 0.30s. What did change is the cache write, 0.71s against 1.88s, because 0.16 compresses.mhscachewith LZMA rather than LZ77; the file is smaller for it, 730,587 bytes against 1,324,707. A coldpsnd mhs -rpays that write once and went 2.77s -> 5.62s, while the warm path is faster than either version was, for the reasons in the two entries above.docs/dev/updating-microhs.mdrecords the measurements and why Path A was taken over adopting upstream--embed-packages(source/thirdparty/MicroHs,mhs-embed.c,langs/mhs/CMakeLists.txt)
Added
-
Local Patches To Vendored MicroHs, Applied At Build Time:
source/langs/mhs/patches/holds fixes psnd needs before upstream takes them, with a README saying what each one is for. The build copies the vendored tree, patches the copy, and rebuilds the compiler from it withbin/mhs, sosource/thirdparty/MicroHsis never modified. The first patch makes the REPL run anIOaction that returns a value instead of refusing it:midiInitat the prompt reportedCannot satisfy constraint: Show (IO Bool), as didmidiListPorts,midiIsOpen,midiRandomand the three record queries. Cost is one 39.7s self-compile, cached until a patch orbin/mhschanges;-DMHS_PATCH_MHS=OFFbuilds against upstream's committedgenerated/mhs.c(langs/mhs/CMakeLists.txt,patches/) -
Third-Party License Texts In Release Archives:
docs/licenses/holds the license text of each vendored dependency, andbuild_release.pycopies it into every archive, failing if the directory is absent. Archives carried only psnd's ownLICENSEwhile the binaries link LGPL (Csound, FluidSynth, libsndfile, liblo) and GPL-2.0 (Ableton Link) code. zstd and JUCE ship no text in-tree and the mongoose GPL-2.0-only conflict still blocks the web variants;docs/licenses/README.mdrecords both gaps (build_release.py)