Skip to content

Releases: musicastudio/FSVR

v0.5.1

Choose a tag to compare

@github-actions github-actions released this 30 Sep 00:18

Download

Installer
Windows FSVR-Windows-Installer.exe Run it; it asks for admin rights to install into Program Files
macOS FSVR-MacOS-Installer.zip Unzip and open FSVR-MacOS-Installer; it is not signed, so right-click it and choose Open the first time
Linux FSVR-Linux-Installer chmod +x FSVR-Linux-Installer, then run it

The installer puts every format in place (VST3, CLAP, VST2, the 32-bit VST2 with its DXi, AU and the standalone) and can keep FSVR up to date. To install one format by hand instead, take its own zip from the list below, FSVR-<OS>-<format>.zip. FSVR-MacOS-Update is for the updater, not for downloading.


FSVR v0.5.1: preset management in banks, dialogs in the synth's own style, and a check of the whole editor.

This round answers jameshansen's reports on managing presets: saving into banks rather than one file per performance, right-click menus in the browser, dialogs that look like the synth, the standalone's audio settings, and a saved preset that came back at a lower pitch.

Save and Import menus. The pod reads Save, Import, Editor, Keys, Tone. Save holds Save Current Preset, Export Current Preset and Export to FS1R SysEx; Import holds Import FSVR Preset and Import FS1R SysEx to New Bank. Save Current Preset opens a dialog with your banks (the read-only Yamaha FS1R bank is not offered), <New Bank> and the preset's name; the performance goes into that bank's .syx with its four voices and its Fseq, and a preset of the same name there is replaced. The new-bank name offered is always one no bank has.

.fsvr, FSVR's own preset format. XML, so it can carry more than the unit's bytes later: version 1 holds the name, the category and the performance, voice and Fseq bulks. Import FSVR Preset plays it at once and opens the save dialog on the name the file gives.

Right-click menus. On a preset: a heading naming it ("Performance: China Pop"), Rename, Delete, Edit Attributes, Copy Attributes, Paste Attributes; the row lights while its menu and dialog are up. On a bank: "Bank: CYBER", Rename, Delete. A deleted bank's file moves to the library's Deleted folder rather than going for good. The factory's presets open the same dialogs read only, and their attributes still copy.

Banks hold their own. The Yamaha FS1R bank lists the factory's presets only, where it used to append every library preset under the same names as their originals. Choosing a bank resets the category filter to All, so a filter left from another bank never makes a bank look empty. A user bank's lists light what is loaded and nothing else. A part playing a library voice shows that voice's U number, where every part read "Int U001", a stale number that an edit of the part would load (the library's first voice).

A saved preset's Fseq no longer bends its pitch. A preset saves the Fseq the unit holds, and loading it back made the engine give a performance with no Fseq part the first part (rom.cpp:91), so that Fseq's frame pitch shifted every part 1 note: CYBER's China Pop, saved and reloaded after a restart, carried Fseqs whose first frames sit 30 and 96 semitones below their note. The load now sends the performance's own Fseq part byte again after the Fseq. China Pop's copy plays at 259.5 Hz, as the original does; before the fix it had no pitch the autocorrelation could find. No bulk dump showed the fault, since which part plays the Fseq is engine state, not a stored byte.

Dialogs in the synth's style. Every dialog but the About box is a Hollow modal: a dark title bar with a close X over the page's hammered aqua and the browser's dark stripes, dimming the window behind it, closed by Escape, growing the window to hold it when the editor is hidden. Save, Delete, Rename, Attributes, Delete Bank, Rename Bank, Unsaved Changes and Audio and MIDI.

The standalone. A MIDI/Aud button above Volume opens the audio and MIDI settings: on Windows a dialog in the synth's style that works clap-wrapper's own settings window (driver, output, input, sample rate, buffer size, and the MIDI inputs as lamps), on macOS the app's window. Closing the standalone on Windows with the performance changed since it was loaded or saved asks whether to save it to a bank first. The LCD's edit mark now means exactly that. Right-clicking empty space no longer opens the 1x to 4x menu; the scale is the LCD's.

Hollow gains modals, menu headings and {cell:n} labels, a list's right-clicked row, dropdowns filled from text data, lamp columns, captions that repaint when their text data changes, the standalone's settings and close prompt, and hooks for driving a GUI without a window (hollow/docs/skin-format.md, framework.md). Hollow's own framework/ wants the same changes.

Checks. check_plugin now covers Save to Bank, .fsvr export and import, every right-click action, a saved preset coming back byte for byte and within 1 dB (a factory performance, and a bank shaped like a whole unit's dump with Int voices), and a preset's Fseq after a close and reopen (it fails without the fix: 1200 Hz where 260.9 Hz was saved). The new check_gui drives the editor over the processor without a window, as a mouse and keyboard would: the top bar, every page, the browser's right-click menus, every dialog, the modal's veil, Escape and close X, the close prompt, the scale menu and About, then 235 dials and faders, 138 dropdowns and 207 toggles across 14 pages. It fails when the stuck-highlight fault of this round is put back. build.bat test and build.bat plugin pass, both checks included; CI runs both. The engine is untouched, so the render regression was not run (its reference is still the stale one v0.5.0 noted).

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 06:01

Download

Installer
Windows FSVR-Windows-Installer.exe Run it; it asks for admin rights to install into Program Files
macOS FSVR-MacOS-Installer.zip Unzip and open FSVR-MacOS-Installer; it is not signed, so right-click it and choose Open the first time
Linux FSVR-Linux-Installer chmod +x FSVR-Linux-Installer, then run it

The installer puts every format in place (VST3, CLAP, VST2, the 32-bit VST2 with its DXi, AU and the standalone) and can keep FSVR up to date. To install one format by hand instead, take its own zip from the list below, FSVR-<OS>-<format>.zip. FSVR-MacOS-Update is for the updater, not for downloading.


FSVR v0.5.0: a new editor on Hollow, an installer for every format, and releases split per format.

Two effect faults found and fixed this round (docs/findings.md, 2026-09-28), a faster sample loop, and the plug-in around the engine rebuilt.

A071 Relaxxx was silent. Its insertion is type 26, Cmp+DS+Dly, which the engine read with Comp+Dist's word layout: drive 0 and a low-pass at the bottom of the frequency table, after the part summing. Types 26 and 27 now read the Data List's layout (p.30): the compressor at words 10 to 13, the two distortion gains at words 5 and 6, no LPF, and Distortion's and Overdrive's default Edge. The attack and release words now reach the follower for all three compressor-plus-drive types, where they were a fixed 5 and 170 ms. A071 goes from a peak of 0.0014 to 0.0498. The layout is KNOWN; every effect constant stays INFERRED.

B016 Dyno Rose's disruption while playing a passage was Auto Pan's L/R square wave flipping the whole variation return from one side to the other in one sample, every 124.16 ms (4.03 Hz). The pan position now glides with the noise gate's one-pole (0.002 per sample, about 10 ms), and the rendered passages go from eleven off-note jumps to none. INFERRED: the unit plainly does not step there, but how fast it swings is unmeasured.

The sample loop's maths (sine, 2^x, dB to linear, tanh) goes through src/fsvr/fastmath.h, with FSVR_MATH choosing raw libm, a table (the default), CORDIC or a hybrid. The table renders thirty seconds of A020 Vox Morph in 1.86 s against libm's 2.79 s, and -P 24 in 1.75 s against 3.18 s (docs/performance.md). The self check measures the built backend against libm.

Silent channels stop costing CPU. The Fat Line demo sat at 43 % of a core, because DigiSQ2's slow-release modulators kept all 32 channels alive for a one-note line. A channel whose carriers and noise are done and whose output has been under 1e-9 for 64 samples now stops rendering until the allocator may reuse it, a finished operator no longer runs its control-rate maths, and the control-rate maths reads the same tables as the sample loop. The song renders in 6.1 s instead of 12.0 s (22 % of a core), and Vox Morph's one-note render goes from 1.86 s to 1.54 s. The render moves by at most one 16-bit step in a handful of samples, and the demo ledger reads the same to the digit (docs/performance.md).

None of these changes moves any of the nineteen render regression cases, checked against a fingerprint of the tree before each change.

The editor is new. The JUCE layer and its panel GUI are gone. The plug-in is now built on Hollow (hollow/, published today as musicastudio/Hollow), whose GUI is data: the skin in plugin/skin is JSON layouts and PNG art, drawn by one software renderer that is the same in every host and on every platform, and edited in place with Hollow's web editor. The pages are a browser for performances, voices and Fseqs, the four parts, performance, effects, Fseq (which now shows where playback is, and takes the chosen Fseq's loop points), Easy, and the Expert pages for operators, envelopes, modulation, key scaling, filter and pitch. The knob, keyboard and navigator art is rendered from Blender scenes kept in blender/.

An installer for Windows, macOS and Linux, from musicastudio/Installer, built by this repository's CI: FSVR-Windows-Installer.exe, FSVR-MacOS-Installer.zip and FSVR-Linux-Installer. Every format is ticked by default, the 32-bit VST2 with its DXi included (registered for you on Windows). It uninstalls from Settings > Apps on Windows. Its optional updater never reads GitHub: it reads musica.studio's update manifest, downloads the setup from beside it and refuses it unless its SHA-256 matches. musica.studio mirrors each release off GitHub, checking every file against the digest GitHub records, so a release reaches updaters only once the mirror has taken it.

Every format is its own zip, names its assets: FSVR-<OS>-<format>.zip, so the 32-bit Windows build is FSVR-Windows-VST2-32-DXi.zip beside FSVR-Windows-VST2-64.zip. SHA256SUMS.txt covers every file. The old FSVR-plugin-<platform>.zip bundles are gone. (FSVR-MacOS-Update is the bare binary the macOS updater runs; people want the zip.)

State fixes. Fseq bulks load at the Data List's 6b 00 nn address, and a restored session keeps its system block. A saved session with an Fseq loaded but no Fseq part no longer comes back playing the last Fseq on part 1; the engine self check covers it.

FSVR's icon (icon.png in the repository root, with icon.ico and icon.icns made from icon.svg) is now the standalone's on Windows (the .exe, its window and the Start menu shortcut) and macOS (the .app), and the Linux installer gives its menu entry the same icon. The window scale shows on the LCD, and a click there opens the scale menu.

Build. GitHub's Windows runner moved to Visual Studio 18, whose MSVC 14.51 turns clap-wrapper's <experimental/coroutine> into a hard error; the standalone targets silence it. build.bat test and build.bat plugin pass, check_plugin included.

v0.4.8

Choose a tag to compare

@github-actions github-actions released this 25 Sep 14:28

FSVR v0.4.8: the frequency EG, the note-on damp and the channel allocator, all measured off the unit.

Four engine faults found and fixed against hardware this round, in answer to rgwan's report of pitch trouble on B056 Tech Lead, B049 Hollow, B115 Obie Strings and B120 Hit, and his separate report of a note-on click on B016 Dyno Rose and A020 Vox Morph. Three hardware sessions were recorded for it (FS1R.unlock captures/2026-09-25-6, -7 and -8), each with the gate clean and the EPROM and debug stub matching their images.

The pitch reports are fixed. The operator frequency EG is a linear ramp, not the exponential approach the engine had, and its rate is the amplitude EG's own ladder. Measured off 07_modulation_2's six feg-* segments by tracking the carrier rather than its envelope: a linear fit holds to 0.3-3.8 cents rms where the best exponential over the same points leaves 39-90, and 4.5x the swing takes 4.5x as long at a fixed attack time, which a ramp does and an approach cannot. The traverse is 23.99 and 23.98 semitones on two independent segments against 24.0 for a quartered 96-unit scale, so cal::FEG_TRAVERSE = 24.0 replaces the guessed FEG_TIME_K = 0.3 and the frequency EG comes off the INFERRED list. Four segments that were 200-2900 cents out now track to 1-5 cents; the worst envelope error on that file goes 2.16 -> 1.40 dB. Adjusting the PEG did nothing on B056 because that voice's PEG is entirely flat: the slide was always the per-operator frequency EG.

A fixed-frequency operator gets no frequency EG. Measured off 24_onset's onset-feg segment: with feg_init +25 at attack time 20 on a fixed carrier the unit holds 1007.6 Hz flat from the first frame while the engine started 939 cents sharp and took 25 ms to come down. Worst error over the sweep 939 -> 11.3 cents, mean +111.7 -> -1.2. This does not contradict the ramp measurement above, which used ratio-mode carriers: together they locate the envelope on the note's pitch word, which a fixed operator never takes. Formant operators take an absolute word too and would follow the same argument, but no capture drives one with a live frequency EG, so they still apply it rather than being changed on a guess.

Note-on damps the channel it takes instead of zeroing it. FUN_00023000 is what note-on calls once the allocator has a channel, from both note-on paths: it sets that channel's EG stage word to 4, the release stage, and writes YMP706 register 0xFC/FD, with the mask coming out of the one-hot table at EPROM 0x35B260. So the hardware releases the note it displaces. The engine did C = Chan(), which dropped a still-sounding channel to zero between two samples: 13 times in Vokodrone, 44 in AN Superarp, a step up to 0.15 of full scale. In a forced steal the largest step across the note-on goes from 1.61x the note's own body to 0.83x. The fade rate, cal::DAMP_MS, is the one constant in cal.h with no measurement behind it and is labelled as such: 23_damp was recorded for it and came back with no damp in it at all, because the unit did not take the channel that file aimed at, which is that file's designed-visible failure rather than a number to fit.

The channel allocator is round robin with a note-priority steal. Read directly out of the unit's memory rather than inferred from audio (session 6 reads 0x010287DC, 0x010287DE, 0x010289BC and 0x010288DC after every note-on). The per-channel priority word is the note number exactly. Filling an empty machine with notes 36..67 puts them on channels 1..31 and then 0, not 0..31: FUN_0000f7dc walks from the last channel allocated. With all 32 held, a 33rd note of 100 takes channel 2, which held note 37, not the oldest channel the engine used. Age is no longer consulted anywhere in allocation. On the demo songs this is not cosmetic: steals of a still-sounding channel go 13 -> 47 in Vokodrone, 44 -> 188 in AN Superarp and 0 -> 32 in Kalimba, and Vokodrone's onset high-frequency excess against the unit's own recording drops +1.6 -> +0.6 dB. Also measured there: a part's note reserve cannot oversubscribe the 32 channels, writing 32 with the others at 0+8+8 reads back as 16.

Known issue, not fixed in this release: the B016 Dyno Rose click. It is located and it is ours. 24_onset puts the unit at 1.68x its own body one control tick after note-on against the engine's 9.80x, with a control segment that has nothing tick-driven reading 1.08x, so the unit has no such discontinuity anywhere. Muting part-1 operators one at a time drops the engine's ratio from 4.41x to 1.77x on operator 2 alone, and switching the parts' insertion switch off removes the step entirely while zeroing the reverb send changes nothing: it is the insertion path. What does not add up yet is that B016's reverb, variation and insertion types all read 0, which is pass-through in both blocks. Deferred at rgwan's direction, since the effect blocks are to be replaced by a VOP3 model. A020 Vox Morph measures clean. Also still open and unrelated: four demo songs carry 4-10 dB of onset high-frequency energy the unit does not, unmoved by every fix above.

Tooling in this line: the render regression runs off a portable renderer so the gate works away from Windows; tools/fit_damp.py, tools/fit_onset.py (with a --check regression gate for the fixed-operator frequency EG) and the 23_damp and 24_onset request files are new; the engine selftest gained checks for the frequency EG's constant rate, the note-on damp and the allocator's measured channel numbers, each verified to fail on a deliberately broken build. A pre-existing bug where "selftest: ok" printed mid-function, hiding every check after it from the exit code, is fixed.

This version was previously erroneously released as v0.5.0.

v0.4.7

Choose a tag to compare

@github-actions github-actions released this 24 Sep 17:12

FSVR v0.4.7: every DX-bank preset was the next voice's data under this voice's name.

The EPROM's DX7 voice table starts at 0x230000 as plain 155-byte VCEDs with the name last. The extractor had read it from 0x230091, the first name, so each record carried the following voice's operators and common block; rgwan fixed the extractor (5c2a48b), but the engine's own ROM loader, the plugin's bundled voice bank and the selftest's fixture still read the old way. Every PrC to PrK voice, and every performance that names one (B014 Full Tines, B025 Tremolo, A020 and the rest of the DX-bank set), played the wrong voice with the right name. Fixed in all three places.

Verified byte for byte against the unit's own conversions: the demo songs send FullTine 1 and DX-Acrd 4 as bulks the firmware itself converted, and the engine's conversion of the same ROM records now matches each on every byte but the category, the demo's one edit (27 differing bytes before). The selftest diffs the whole DX-Acrd 4 bulk with no skip list. captures/demo_preset/02_Full Tines.mid loads B014 by bank select and program change instead of sysex, and its render against the demo's own differs only by the performance volume byte the demo edits, a flat -1.38 dB with a residual under 2e-8. check_presets now diffs the bundled bank's bytes against presets/, not just the names, so a stale blob fails the build.

Known issue, not in this release: A020 Vox Morph and any performance that layers two parts with all eight unvoiced operators live is heavy, about half a desktop core at 8 notes and beyond a laptop i7 in a DAW. Measured, with the fixes in order of cost, in docs/performance.md.

Also in this line: v0.4.6's byte-for-byte DX7 conversion, v0.4.5's formant vibrato (B011 Human Eh), v0.4.4's operator slots.

v0.4.6

Choose a tag to compare

@github-actions github-actions released this 24 Sep 14:38

Full Changelog: v0.4.5...v0.4.6

v0.4.5

Choose a tag to compare

@github-actions github-actions released this 24 Sep 14:06

Full Changelog: v0.4.4...v0.4.5

v0.4.4

Choose a tag to compare

@github-actions github-actions released this 24 Sep 13:22

Full Changelog: v0.4.3...v0.4.4

FSVR v0.4.3

Choose a tag to compare

@github-actions github-actions released this 24 Sep 12:23

FSVR v0.4.3: the amplitude EG's key code table at every semitone, the unvoiced resonance carrier against its register, and voice edits that reach sounding notes.

The key code table, all of it. rgwan's fourth hardware session (FS1R.unlock/captures/fs1r_capture_session4.py) plays one EG decay at every semitone from 12 to 120. Each of the 109 slopes lands on the chip's rate ladder outright, so the key offset the EG rate scaling adds is read at all 37 key codes rather than interpolated between ten: twelve notes had been a rate step off, an eighth to a fifth of their decay time. The same take holds 135 ms at every note, so the hold register does not scale with the key code; the engine had held note 12 for 920 ms. 21_keycode envelope shape 2.43 → 0.57 dB. docs/aeg.md.

The unvoiced resonance carrier. 22_ures reads the carrier at five bandwidth registers by the four settings that produce a tone. Its amplitude against the band depends on the register as much as on the setting (1.50 at register 10, 2.37 at 87), and the noise under it is cut, 23 dB at a narrow band and setting 7 where a wide band loses nothing. Both are tables now, interpolated over the register. 22_ures band shape 2.11 → 0.62 dB. The take also showed the capture chain's right channel lags the left by one sample, which had put a phantom decibel into every 8 kHz unvoiced take; the carrier is read off the left channel alone.

Voice edits are live. A parameter change into a voice, common or per-operator, now rebuilds the sounding channels at their own pitch and velocity, as the unit's edit buffer does: frequency, level, form, bandwidth, detune, algorithm, LFOs and the filter all move while a note holds. Envelopes in flight keep the segments they started with.

Fixes. The plugin's voice Note Shift parameter defaulted to −24 semitones (the one Data List row written (-24-0-+24) instead of with tildes was read as unipolar), so performances loaded an octave off whenever the host reset it. Parts whose voice bank is off no longer receive MIDI (A011 Sho played four parts where the unit plays two). DX7 voices are converted through the firmware's own algorithm map and rate corrections, which took a high-frequency hiss off B024 at high velocity.

Numbers. Demo set against rgwan's recording: mean band error 4.96 dB, tilt 1.95, envelope correlation median 0.976 and worst 0.912 (0.902 at v0.4.2). Twenty-seven of the 38 capture files inside half a decibel of level. docs/fidelity_plan.md has the table; docs/findings.md the working. Left: the effects DSP, and the per-channel register dump (perchan3) whose first run stopped on a script bug now fixed.

The demo clips in the README are the v0.4.2 renders.

Known issue, fixed in v0.4.4: DX7-bank voices (PrC..PrK) are converted with their operators one slot off the firmware's placement, so a carrier can land on a modulator's slot. B025 Tremolo rings a tone after note-off and Full Tines is wrong. Use v0.4.4.

v0.4.2

Choose a tag to compare

@github-actions github-actions released this 23 Sep 18:44

Full Changelog: v0.4.1...v0.4.2

FSVR v0.4.1

Choose a tag to compare

@github-actions github-actions released this 22 Sep 17:16

FSVR v0.4.1: the noise formant re-read off the hardware, and the snare traced to its carriers.

The noise band. rgwan recorded the fifteen demo songs with the effect section and the per-voice filter switched off, and Vokodrone's bass and drum parts on their own, so what is left between the unit and the engine is the tone generator alone. The drum's top octave was 3 dB bright on every hit, and following that down re-read the unvoiced operator: the band is two digital one-poles with different coefficients, and the wideband pedestal the last release could not model is the second pole's own floor. Both coefficients and the band's peak are now tables measured against the bandwidth register and the skirt, the same numbers off the 1 kHz and the 8 kHz takes, and the unvoiced output is averaged two samples at a time, a roll-off the fixed sines never show. Band shape on the four noise files went from 2.2 to 2.9 dB down to 0.5 to 1.5, and Vokodrone's top octave from +3.3 dB to -0.6. docs/noise.md, tools/fit_noise_band.py.

The snare. With the drum part isolated, the engine's snare reads 4 dB hot in the 100 to 200 Hz band its two sine carriers occupy, and muting every noise operator costs it half a decibel, so it is the FM, not the noise: the unit's modulation is deeper for the first six milliseconds. Three things behind that have never been measured, the velocity law at any sensitivity but 0, a decay to a level that is not silence, and a modulator on a modulator. tools/make_capture_tonal.py writes the four request files that do, the fourth being the demo's drum voice one hit at a time. docs/captures/capture_request_0922.md.

Also. tools/compare_isolated.py scores an isolated-part recording of a demo song hit by hit. The bass part's formants sit an octave out either side at fundamentals of 80 to 120 Hz, which is the formant window family at a note the capture set never played, and is open. tools/fs1r_demo_clip.py follows the tree reorganisation, and the song 1 and 2 clips in docs/media/ are rebuilt off this engine.

Against the effects-off take the engine sits 2.8 dB under the unit in the median octave band, flat across the bands, with four songs at zero.

Intel Macs. The macOS zip is universal now, arm64 and x86_64 in one binary, with a 10.13 deployment target. The previous release's was Apple silicon only, which is what issue #3 reported.