github leonardoMirabal/frodhes v0.9.10
Frodhes 0.9.10

31 minutes ago

Frodhes 0.9.10 gives the electric piano a more natural touch (soft notes stay mellow, the bark comes in clearly when you dig in, a sweeter top and a longer-singing middle, a quicker damper), on the FM-1, the SMK-37 and the Move alike; gives RESPONSE two settings, FULL (the whole dynamic range) and LIGHT (a light touch); keeps every effect from adding level peaks; adds a two-core FM-1 package with 14 voices and the reverb at the full sample rate; lets the SMK-37 play 10 voices; and brings Frodhes to your computer as a CLAP, VST3 and Audio Unit plugin for macOS, Windows and Linux.

Download: frodhes.fwsc below (the same file as frodhes-0.9.10.fwsc; the newest is always at https://github.com/leonardoMirabal/frodhes/releases/latest/download/frodhes.fwsc). Try it first in your browser: https://leonardomirabal.github.io/frodhes/

Install

FM-1: download frodhes.fwsc below. Install it from the emulator page (Chrome or Edge, Install on your FM-1 or SMK-37), or from a terminal:

pip install mido python-rtmidi
python3 tools/fm1_install.py frodhes.fwsc

Your settings, presets and pattern are kept. If anything goes wrong, switch the FM-1 off, hold OCT− and switch it on: that is the USB rescue, and you can install again from there.

FM-1, two cores: frodhes-c1.fwsc below, installed from a terminal (python3 tools/fm1_install.py frodhes-c1.fwsc), plays 14 voices (the voices on one core, the effects on the other, with no added delay). Install either image over the other at any time; your settings, presets and pattern are kept.

Computer (plugin): frodhes-plugin-macos.pkg (or frodhes-plugin-macos.zip), frodhes-plugin-windows.zip, frodhes-plugin-linux-x86_64.zip or frodhes-plugin-linux-aarch64.zip below. How to install each: PLUGIN.md.

Move: you need Schwung on the Move. Install Frodhes with Schwung Manager in a web browser: Install Custom Module > From GitHub URL, leonardoMirabal/frodhes. Or download frodhes-module.tar.gz below and use From Tarball. Details: the Move manual.

SMK-37 Pro, SMK-37 Elite, MKE-P37: frodhes-smk37-pro.fwsc, frodhes-smk37-elite.fwsc and frodhes-mke-p37.fwsc below. Read SMK37.md first.

New in 0.9.10

  • A two-core image for the FM-1, frodhes-c1.fwsc, next to the usual frodhes.fwsc. It runs the voices on
    the chip's first core and every effect on the second: 14 voices on every instrument (10 on the one-core image),
    and the REVERB TYPEs at the full sample rate, as on the Move. The two cores add no delay: the sound reaches the
    outputs as soon as on the one-core image. Everything else is the same: the pages, the presets, your settings and
    pattern (install either one over the other at any time). frodhes.fwsc stays the default.
  • Frodhes as a plugin for computers: the FM-1's sound engine, compiled unchanged, as a CLAP, VST3 and Audio
    Unit instrument on macOS (Apple silicon and Intel) and a CLAP and VST3 instrument on Windows (x64) and Linux
    (x86_64 and ARM64). It plays the high-quality version of every instrument and effect, with 24 voices on every
    instrument; the factory presets F01-F57 and your own preset files, UNDO, program changes, MIDI CHANNEL, the
    velocity settings, the tempo source, MIDI learn, SUSTAIN latch and the effects bypass, all saved with the project.
  • It runs at any sample rate the host uses (22.05 to 192 kHz) and tells the host its latency, so the host keeps it in time with the other tracks.
  • Its own window on every system: the FM-1's pages as cards with knobs, resizable, sharp on high-resolution screens.
    Presets (the 57 factory sounds and your own, saved as files): click the preset's name for the whole list, grouped
    by instrument, and SAVE with a name of your own. MIDI learn, the effects' bypass (a bypassed effect's knobs are
    drawn inactive) and the sustain latch are in it; everything, the window's size too, is saved with your project. The SETTINGS sheet shows the version.
  • The host's tempo drives the synced effects. It runs at any sample rate (44.1 and 48 kHz exactly as the FM-1),
    reports its latency (10 ms) and plays up to 16 instances in one project.
  • Downloads: frodhes-plugin-macos.pkg (installer) or frodhes-plugin-macos.zip (macOS 11 or newer, Apple silicon
    and Intel), frodhes-plugin-windows.zip (Windows x64), frodhes-plugin-linux-x86_64.zip and
    frodhes-plugin-linux-aarch64.zip (glibc 2.31 or newer: Ubuntu 20.04, Debian 11 and later). Each is
    self-contained: nothing else to install.
  • The plugin is not signed by Apple or Microsoft yet. On macOS, open the installer with right-click > Open (or
    System Settings > Privacy & Security > Open Anyway); for the zip, clear the download flag once in Terminal with
    xattr -dr com.apple.quarantine ~/Library/Audio/Plug-Ins/*/Frodhes.*. On Windows, unblock the zip
    (right-click > Properties > Unblock) before you extract it. The steps are in the README.
  • DISPLAY 2, a new page right after DISPLAY (SELECT one page on): K1 SUSTAIN LEDS. With LEDS on ALL or SCALE, a
    key let go while the sustain keeps its note ringing stays dark until the sound stops (DARK, the default, as
    before) or lights again at once (LIT), so the map of the keys stays readable with the sustain on (issue #35).
    Kept with the settings; LEDS PLAYED and ROOTS are unchanged. The SMK-37 has no key lights and no DISPLAY 2 page.

Changes

  • The electric piano's touch (every electric piano type: STAGE 77, SUITCASE, EARLY FELT, BELL DYNO). Soft notes
    stay mellow and round up to a medium touch. Above that the bark comes in clearly, and the point where it starts
    rises with the register: from about velocity 58 in the bass to about 108 from E5 up, so a medium touch no longer
    growls in the upper keys while a firm one still barks in the bass. Soft and medium notes keep their level, so
    presets keep their balance.
  • Electric piano, the hardest strikes: notes near velocity 127 no longer overdrive the pickup. Above a knee that
    depends on the key and TYPE, the tine's swing is cut a little more with each velocity step (up to about 22 dB at
    v127 on the DYNO top keys, none on most FELT keys) and the output gain takes it back, so the fundamental keeps
    its level. The second harmonic at v127 is now at or below -12 dB re the fundamental on every TYPE, sustain and
    attack (0.9.9: up to -5 dB sustain and -2 dB attack on DYNO, -8 / -4 dB on STAGE 77 and SUITCASE). v127 is still
    louder than v110 (+3.4 to +3.9 LU K-weighted) and brighter (the attack's spectral centroid higher). Every velocity
    under the knee, and VIBES and MARIMBA, sound exactly as before.
  • Electric piano decay: held notes in the middle and upper register ring longer, closer to a real tine piano. The
    fundamental's T60 (v40 / v64, host) is now about 19-20 s from C3 to A4 (was 10-11 s), 14 s at C5 (was 8 s),
    4.2 s at A6 (was 2.2 s); C#2-D#2 a little shorter (23-25 s, was 27 s). DECAY still scales every key the same way.
  • Electric piano damper: letting go of a key stops the note faster and sooner. The release T60 is 0.25 s in the bass,
    0.18 s in the middle, 0.14 s and 0.12 s in the treble (was 0.5 / 0.4 / 0.3 / 0.2 s), and the felt lands within a few
    ms (its settle is 2.2-5.1 ms by register, was 3.6-7.3 ms): a note falls 10 dB in 25-45 ms (was 55-95 ms). RELEASE
    scales it x0.25 (0) to x8 (127): 127 keeps the long releases of before (about 2 s in the bass, 1.4 s at C4, 1 s at
    E6). Release velocity, the pedal and the
    half pedal work as before, on the new times.
  • DRIVE TSH8 and OHCD on quiet bass notes: both kept one internal signal in whole units, and on a soft low note its
    steps were a faint buzz of odd harmonics. TSH8's clipper output now carries 4 more bits into the tone stage (the
    same instructions on its longest paths); OHCD's first stage runs 16 times finer inside (2 instructions a sample,
    its budget 160 us a block, under the drive's 177). A 41 Hz sine through either at DRIVE 20: the 3rd harmonic
    re the fundamental falls from -44 / -50 / -59 dB to -67 / -79 / -90 dB (TSH8, inputs 160 / 320 / 640) and from
    -38 / -54 / -57 dB to -54 / -71 / -79 dB (OHCD, inputs 40 / 160 / 320). Loud playing is unchanged. On F05 with
    TSH8, key 28 at velocity 20: the 3rd harmonic is now -60 dB re H1 (0.9.9: -46). OHCD and BHLUE there sit on the
    output's own floor (harmonics near -115 dBFS).
  • DRIVE TONE with the compressor on (every factory preset has it): the compressor sits before the drive and now
    holds its detector over a note's cycle, so on loud chords it feeds the drive about 0.5 dB less. On such a chord
    TONE's lower half (0 to the middle) moves the treble at 8 kHz by about 2.6 dB (0.9.9: 5.7) and its upper half by
    3.5 dB (0.9.9: 4.2). With the compressor off, TONE's range is 0.9.9's (lower half 9.5 dB, upper half 4.5 dB).
    TONE's filter itself is unchanged.
  • FX (the bypass, CC 111) keeps the compressor on: it switches off every other effect. The bypass had dropped the
    compressor and its make-up, so FX off sounded 1.0-1.2 dB weaker on F01-F04 (up to 2.6 dB on other factory
    presets) and changed the piano's dynamics. With every other effect at depth 0, FX on and off now match within
    0.5 dB in level and in width (both mono), on the one-core and the two-core builds. The compressor's meter stays live
    while bypassed. (The Move had this already, FR_BYP_KEEP_CMP; it is now the default everywhere, -DFR_BYP_KEEP_CMP=0
    for the old bypass.)
  • The output level is 0.9.9's again (the default LEVEL and the limiter's threshold, LIM_T 24000), on the FM-1,
    the Move and the plugin; the factory presets' own levels: below.
  • No effect adds peak level. Each effect switched on keeps the loudest moments within 2 dB of the dry sound
    (tools/fx_pristine.py's new peak check), so none of them drives the output limiter:
    • PHASER: its level trimmed by DEPTH so a chord's peak stays within 0.5 dB of the phaser off (single notes within
      2 dB); DEPTH 0 matches by loudness, the deep settings are 2-3 dB quieter on average. The sound itself is unchanged
      (a pure gain).
    • Touch wah: the make-up capped at twice the ratio of the input's and output's peaks, so it no longer overshoots a
      note's onset (+1.6 dB at most, +7 dB before) and a soft high note under a closed resonant wah keeps its level.
    • Filter LP12 / LP18: resonance gain compensation as the cutoff falls (a resonant sweep stays within about 1 dB of
      the unfiltered level).
    • ANA delay: on a silent line its time no longer glides from the last setting, which had bunched the first repeats
      together (a chord's peak +3.1 dB before, +1.7 now; the echoes as loud as DIG's).
    • HQ HALL (Move / plugin) at MIX 127: the switch between its quiet and loud paths moved lower, so its non-linear
      residual falls from -73.7 to -76.4 dBFS.
  • The compressor is clean on chords. It holds its detector over a note's cycle (11.6 ms), smooths its reduction's
    release (about 0.1 s, never slower than half the RELEASE setting) and interpolates its gain: a v127 chord's
    intermodulation with FX off (the compressor stays on) at most -68.9 dB on every TYPE (was -45 .. -56; the limit -60).
    Loud v127 chords sit about 0.45 dB lower; v64 / v96 within 0.15 dB. Its gain no longer adds a faint 3rd harmonic to
    quiet high notes (the result rounded with a 1-bit dither from -60 dBFS up, not cut: FX off, a soft A6 on BELL DYNO
    had its 3rd harmonic 5 dB up).
  • A filter TYPE change no longer clicks with RESO up (the compensation is applied on every TYPE, so the crossfade's two
    TYPEs share one state).
  • FM-1 keys, TOUCH LIGHT / MEDIUM / HEAVY: velocity 127 is kept for the hardest hits. Each key learns its firmest
    landing (its floor). A press as firm as that now plays KEY VEL + 0.75 x (127 - KEY VEL) (119 at KEY VEL 96), and
    127 needs a press clearly firmer (half an octave of the reading under the floor). Before, every press at or under
    the floor played 127.
  • KEY VEL above 107: the medium press plays at most 107, so a harder press always has 20 steps to 127. The extra KEY
    VEL lifts the soft presses instead (at KEY VEL 127 the lightest press plays 21). Before, at KEY VEL 127 every press
    firmer than a medium one played 127: 54 % of the presses in a free-playing record. Replayed through the new curve,
    0 % play 127 and the median is 109. FIXED, MIDI notes and the SMK-37's keybed are unchanged.
  • The dry-distortion gate (tools/dry_dist.py) also measures the attack (aH2..aH6, 0..150 ms) and the FM-1's keys
    through the key path at their hardest. H2 is now held to 0.9.9 + 1.5 dB.
  • SMK-37 (Pro, Elite, MKE-P37): 10 voices on every instrument, as the FM-1 (it was 7): the same chip and the same
    audio budget.
  • Electric piano, tine ring: the tine's inharmonic second mode (at 6.3-6.9 times the note) is turned down per key from
    A3 up, so a hard attack in the upper register no longer rings with it: at v127 its band in the first 20 ms is
    -40 dB re the fundamental at C5, -55 at C6 and -65 at C7 (it was -12, -33 and -32; -12 to -24 on C#6-G#6).
    The tables generator fits it per key (tools/gen_rhodes.py strike_fit, params.json strike_fit); keys below
    A3, the bark and the levels are unchanged.
  • RESPONSE (CC 40) has two settings: FULL (the default), the full dynamic range, and LIGHT, a light touch
    with soft notes louder. FULL goes from velocity 20 to 127 over about 34.5 dB (39.4 dB from velocity 1), in steps
    of at most 0.65 dB a velocity; LIGHT keeps 0.9.9's 25.5 dB. Both play at the same level from medium velocities up,
    with the same tone at every key and velocity. On VIBES and MARIMBA, FULL is their response as in 0.9.9 (unchanged)
    and LIGHT lifts the soft notes by the electric piano's LIGHT-over-FULL amount (+9 dB at velocity 20 and below, 0
    from 60), the same tone.
  • On the electric piano TYPEs the output's silence gate opens and closes 6 dB lower (16 LSB, -66 dBFS, was 32; VIBES and MARIMBA keep 32), so FULL's softest notes and
    long tails are not cut sooner than in 0.9.9 (notes faded by the gate within 1 s, keys 21-96: velocity 1 10, 10 8,
    20 5, 30 4, each at most 0.9.9's).
  • The pedal's thud follows the note's level as heard (with RESPONSE's soft end): never louder than the note.
  • The velocity page: every TYPE's last VOICE page (VOICE 3/3 on the electric piano types and MARIMBA, VOICE 4/4 on
    VIBES) holds RESPONSE, TOUCH and KEY VEL. They were FRODHES K4 (KEY VEL), SETUP K4 (TOUCH) and MIDI K4 (RESPONSE);
    those cards are empty now. The CCs are unchanged.
  • Two layers, kept apart: TOUCH and KEY VEL set the FM-1's own keys' velocity only (a MIDI note's velocity reaches
    the engine as sent); RESPONSE changes the sound only, never the velocity (the USB-MIDI out, the sequencer's
    recording and the arpeggiator keep the velocity played).
  • Move: RESP has its own page, VELOCITY, right after the VOICE pages (it was on LFO/SETUP), on Frodhes' screen and on
    Schwung's page list alike; standard and HQ (one module).
  • SMK-37: TOUCH and KEY VEL on the velocity page too (K6, K7).
  • VERSION: the MIDI page's K4 shows the version installed (a release's number; a development build DEV and the
    first digits of its commit), read only. The Move shows it on its last page (MAPPINGS, VER).
  • The Move's higher-quality engine and the desktop plugin get the same changes.
  • On the Move: the electric piano's new touch, upper register, sustain and damper (above), in the Move's
    higher-quality version, with 16 voices on every instrument.
  • New factory presets for the new electric piano: the 19 on the FM-1 (and their 38 variants on the Move and in
    the desktop plugin) re-voiced, each at its predecessor's loudness within 1 dB, with the output limiter idle on
    every one. Six of them are quieter than before (BELL DYNO, LUSH CHO, VIBES, VIBES ECHO, MARIMBA, WOOD ECHO, by
    2.7 to 8 dB): they used to reach the limiter, which no preset may do now.
  • VIBES and MARIMBA's damper knock stays under the note it ends at every BARK: with a hard mallet, letting go of
    a chord made it about 0.5 dB louder for a moment; now the knock sits 37-41 dB under the note at any BARK.
  • COMPRESSOR: THRESH and RATIO bring their own make-up (none up to -17.6 dB, where every factory preset sits): it gives
    back the first dB of reduction, never more than the compressor takes at that moment, so no peak rises over the
    compressor-off level. MAKEUP is a trim on top.
  • COMPRESSOR: past -25 dB (faded in from -17.6) a held note relaxes to about two thirds of its reduction over 0.2 s
    (a strike gets the full RATIO), so heavy compression brings the sustain up against the attack. The factory presets
    (THRESH -14.5 .. -17.6 dB) are unaffected by both.
  • Width: with SPREAD at 0 every sound gets one side-wall reflection (570 Hz .. 4 kHz, 10 ms, about -14 dB, on the
    side only). The plain piano was a point in the middle on headphones; now it has a little room width. The mono sum is
    unchanged, the loudness by critical band within 0.05, the v127 chord peaks within 0.02 dB. Off while SPREAD is on.
  • COMPRESSOR: the auto make-up re-fitted for the width (+0.1 .. +0.5 dB from THRESH -20 dB down; the factory presets,
    -14.5 .. -17.6 dB, unchanged).

Fixed

  • COMPRESSOR MAKEUP: turning it fast (or a jump over MIDI) no longer clicks. The make-up glides to the knob's value
    in a few milliseconds; 0 to 127 in one CC was a +24 dB step over 16 samples.
  • DELAY TAPE: turning TIME no longer adds a zipper to the echoes. The playback head's tone (its low bump and its
    high-frequency loss) now follows the tape's real speed as the motor gets there, not the knob at once.
  • REVERB HALL: moving SIZE between AUTO and a fixed size (up to 35 steps apart) no longer steps the tail; HALL's size
    glides a quarter step every 0.7 ms.
  • REVERB PLATE: turning SIZE under a ringing tail is smooth: the cross-fade between the old and new reads moves every
    sample (it moved in eight steps per read, a faint buzz while SIZE turned), and it now takes 1 s (it was 0.13 s;
    0.25 s on the HQ and two-core builds), so the tail no longer bends in pitch while SIZE turns.
  • REVERB PLATE: its modulation no longer adds grain. The two modulated reads in the plate jumped 2 samples each
    time the modulation crossed a whole sample, about 20 times a second. That added a faint gritty noise to every PLATE
    tail, 8 to 10 dB of extra energy at 2 to 12 kHz. The plate now sounds as smooth at any MOD as at MOD 0, and its
    level is unchanged (within 0.1 dB).
  • CHORUS / PHASER: switching between them (CC 85) or either on or off now fades over about 0.1 s instead of 46 ms. The
    phaser now sits a few dB under the chorus, and the faster fade put that drop into one step.
  • REVERB TYPE: a new TYPE no longer starts on a step. What goes into the new TYPE fades in over 6 ms (it started at
    full level, in the middle of a ringing chord's waveform; INFINITE after PLATE was grainy for its first 0.2 s). The
    old TYPE's fade now ends at silence (it ended at 1/128 of its level, then dropped to 0 in one sample).
  • REVERB HALL: a quiet note's tail no longer carries a faint grain. On the FM-1 the hall's diffusers round their
    results instead of cutting them; the high-quality HALL (the Move, the plugin) keeps two more bits inside and rounds
    its taps and its return. A quiet note's residual (what is not the reverb's linear response) is back under 0.9.9's.
  • SEQUENCER: a note let go under the sustain (REC, or a MIDI pedal on CC 64) was recorded as long as the key was
    held and played back short. It is now recorded as long as it rang: until the sustain lets it go, or until the
    same note is struck again (issue #34). The sustain itself is still not recorded. With the arpeggiator on, its
    keys are recorded as held, as before.
  • SEQUENCER: a note held longer than the whole loop was recorded as the part past one loop (held 2.6 s on a 2 s
    loop: 0.6 s). It now plays the whole loop.
  • Two cores: a program change while many notes start (a 26-note burst) no longer takes the audio to its time limit.
    VIBES and MARIMBA now work out a new note's strike when the note arrives, outside the audio interrupt, and the
    wah, the delay and the HQ hall run in fewer steps; the sound is unchanged, sample for sample. The worst block on an
    FM-1 is now 3916-4076 us of the 4500 us limit on every instrument.
  • Two cores: the drive's fade to silence after the last note (the step that removes its small leftover DC without a
    tick) read samples the second core had not made yet and could reach into the next note. It now works piece by
    piece and gives the one-core image's samples, whenever the second core takes its pieces.
  • Two cores: the first core's sound code runs from flash, not RAM. With both cores busy, code read from RAM can come
    back with a flipped bit on this chip (the stored code is intact), and the first core stopped on an instruction that
    cannot fail (the reverb TYPE switch soak reset the FM-1 within minutes). tools/build.py --c1 fails a build that
    puts the first core's code in RAM again.
  • COMPRESSOR: a release the next peak catches again (a chord's beating) no longer pumps the gain: RATIO 4:1 with the
    default ATTACK 40 and RELEASE 48-50 (RELEASE 60 and under: a re-catch under 3.5 dB is slowed) put the loud mid chord's intermodulation at -43 dB (the dry piano -79); now
    -60 or better. F01's compressor: -72.6 .. -73.8 dB on the mid chord (was -68.8 .. -69.1). F10 (4:1, ATTACK 20, RELEASE 40): -52 (was -35).
  • USB RESCUE no longer stops answering when MIDI arrives: it drops incoming notes and controls instead of letting
    them fill the input, which held the installer's messages back.
  • The watchdog resets the FM-1 when the sound stops, not only when the whole program stops: it is fed only while the
    audio interrupt runs, the clock moves and (two cores) the second core finishes its jobs. A freeze with the main
    loop still running now ends in a reset after about 8 s instead of hanging until a power cycle. The crash screen's
    wait is bounded too.

Tools

  • tools/build.py --c1 builds the two-core image; tools/hil_c1_soak.py soaks one on the FM-1 (rows 274: 30 min,
    275: 2 h) and judges the second core's counters (CC 116 = 30 / 31); tools/hil_cpu.py and
    tools/hil_crackle.py play up to 16 voices (--voices).
  • Gate M --update regenerates the Move's reference hashes after an intended sound change, reusing the reference
    renders while they are current; a guard stops it when the engine changed but the references did not.
  • move_multi_cpu: a verdict per track count against the Move's CPU limits (exit 1 on a miss), paced parameter writes
    and the slots restored afterwards; move_hil d2 checks a slot's TUNE, MARIMBA's MUTE and the vibraphone motor.
  • gen_move_presets checks the F20-F57 records against the parameter table.
  • Gate M and Gate R no longer share a build file that another build can replace mid-run.
  • hil_scan: steadier floors for MARIMBA's jack rows (NOISE contact floor, WAH DEPTH).
  • tools/fm1_install.py and tools/hil_c1_soak.py --location: pick one FM-1 by its USB location when two are
    connected; the USB audio device is found by location too, and two FM-1 audio devices without one are refused.
  • tools/hil_c1_soak.py --no-audio (MIDI only); tools/hil_c1_burn.py finds the two-core load limit by adding a
    set amount of work to either core (development builds, CC 117 / 118).

Tested

  • Two cores on the host: the two hand-off orders, refused jobs and the one-core fallback render as designed
    (tests/py/test_c1_pipeline.py); the one-core image is the same with or without the two-core code (Gate R, the
    firmware image's sha256).
  • Two cores on an FM-1 (a development image): core 1 live; hil_cpu.py --worst --voices 14 with the drive TSH8
    and SPREAD, 3 runs per engine: the worst block 3104-3412 us, the whole ISR 3340-3652 us, 0 voices shed, the USB
    counters clean; the soaks 274 (30 min) and 275 (2 h, every engine and REVERB TYPE) passed on that image.
  • FM-1 (release build, two units): the two-core soak under the worst load (all voices, every effect, the reverb
    TYPE switches) worst block 4588 us of its 4800 us limit, no reset; tools/hil_cpu.py --worst at 14 voices
    3916-4076 us on the three instruments (the one-core build 4220 us); the full crackle test 0 events in 18 takes,
    no voice shed.
  • FM-1 (release builds): the full crackle test 0 events in 18 takes, no voice shed; tools/hil_cpu.py --worst 4220 us
    on the one-core build (limit 4500).
  • The Move (release package): the MIN tier 14 of 14; the CPU worst case 530-611 us of the 725 us limit.
  • FM-1 (release build): the crackle self-test (every injected glitch found on every engine); the full crackle test
    0 events in 18 takes on both units.
  • Gate D (tools/gate_d.py): the plugin's renders equal the host build's, byte for byte, on every MIDI-driven test
    render (78), with random and 1-frame blocks and CLAP note events; HQ against the host build with HQ on; 48 kHz
    against the FM-1's USB resampler; other rates within 1 LSB; the Intel slice under Rosetta. Under wine (Windows)
    and on Linux x86_64 and aarch64: the Gate D subset, 9 of 9 identical.
  • Gate D core: 24 voices, the state round trip (every setting, older and broken states), presets, automation (= the
    device's CC path, byte for byte), MIDI learn, the tempo sources and a synced delay at the host's tempo.
  • clap-validator, the VST3 validator, pluginval (strictness 10, VST3 and Audio Unit) and auval -strict pass on the
    release packages; every package passes the self-contained check (tools/plugin_depcheck.py).
  • Host: H2 and the attack's H2 (0-150 ms) at v110 / v127, the K-weighted loudness and the centroids on every TYPE,
    RESPONSE FULL and LIGHT (tests/py/test_rhodes_top.py, tools/rh_top.py); byte-identity under the knee and on the bars
    against a build without the cut; tools/dry_dist.py with the attack cells, 0 values over 0.9.9; make test;
    make pristine (only the 12 known effects-on v40 cells remain, as before this change); the TONE level fit
    (tools/tone_level.py) re-run for TONE above 64.
  • Host: tests/py/test_ctl_zipper.py (one test per fix, each failing before it) and
    tests/py/test_control_sweep.py: comp MAKEUP click 17.3 -> 1.2, TAPE TIME zipper 2.53 -> 1.9 (wet 2.83 -> 2.02),
    HALL SIZE wet zipper 2.15 -> 1.0, PLATE SIZE zipper 2.59 -> 1.36 (wet 3.35 -> 1.63, pitch 1.3 cents, jump 0.93),
    rev TYPE wet zipper 2.9 -> 1.22, cho/pha EFFECT jump 1.59 -> 0.93. A held PLATE's d2 4.0x -> 0.96x its MOD 0's.
    tests/py/test_ctl_zipper.py also runs the reverb SIZE and TYPE cases on the HQ and two-core builds.
  • Every static render of the control sweep (686) is sample for sample as before except the 38 PLATE renders with
    MOD on (the grain fix). The full release diff moves only the PLATE presets (F04-F09, F14, F17): their level within
    0.13 dB, the grain down. make quick: no new failing line.
  • Host: the fundamental's T60 at 31 keys, v40 and v64, against the new curve: within the per-key spread (jitter)
    everywhere. make test, the electric piano and generator pytest files (Gate B: the C engine against the golden model on
    the new tables), Gate R re-saved (only electric piano renders moved; every VIBES / MARIMBA render byte-identical),
    Gate H re-saved (the HQ electric piano on the Move uses the same tables).
  • Host: the fundamental after a 1 s hold at 9 keys, v40 and v110: release T60 on target (0.250 / 0.181 / 0.141 /
    0.120 s), damping starts 1-5 ms after the key-up, no burst at the key-up, never louder after the key-up (also
    tests/py/test_release_never_louder.py on every engine). tests/scripts/release_vel.txt checks 100 ms after the
    key-up (was 200 ms, now near silence) and seq.txt just after the loop's note; the golden model (Gate B) uses the
    same per-register settle as the engine.
  • tests/py/test_rhodes_hq.py: the live-contact check accepts a contact that lands on the neighbouring rate step
    (one case, key 86 v90).
  • Host: tests/py/test_drive_quiet.py (fails on the kernels before, passes now), the drive kernel tests (the
    reference loops in tests/c/drv_kern_ref.c and tools/drive_gen/ohcd.py updated to the same integers), the drive
    types / tail / core / OS tests, make test, make pristine (no change: the same 12 known effects-on v40 cells);
    instruction counts with tools/drive_insns.py (TSH8's longest paths unchanged, OHCD's stage 1 42 a two-sample turn,
    was 38).
  • Host: tests/py/test_fx_drive_reverb.py measures TONE's range with the compressor off (the limits unchanged) and
    reports it with the compressor on.
  • Host: tests/py/test_bypass_level.py (fails before, passes after: FX on vs off with the compressor's make-up
    +7.5 dB before, 0.00 after; F01-F04 +1.0 .. +1.15 dB before, -0.2 .. -0.08 after), test_move_bypass_comp.py,
    make test, make test-c1.
  • Not tested on the FM-1 in this change.
  • The delay's MIX law is 0.9.9's (DIG / ANA / TAPE); the FX button's level check compares the bypass with the
    compressor alone (the bypass keeps it).
  • Host: tests/py/test_fx_pristine.py (OPEN list empty on the one-core, two-core and HQ builds, presets included),
    the new tests/py/test_comp_clean.py (fails before, passes after), make test (65 scripts), make test-c1, the
    full make pytest, tests/py/test_rev_inf.py, tools/gen_move_presets.py --check. Character before / after by
    level-normalised critical-band spectra (the phaser, pan, filter and hall shapes unchanged; the wah within 0.2 dB).
  • Headroom: build/fxp/hrw.py (4-note v127 pedalled chords, two ranges, five start phases, FM-1 + HQ, the Move's
    variants): every factory preset's worst take at most -3.2 dBFS with the limiter idle. make quick 148 of 149 (the
    MARIMBA key-up cells that failed before it too).
  • Not tested on the FM-1 in this change.
  • Host: tests/scripts/keyvel.txt and keyvel_high.txt (both fail before the change), tests/c/keyvel_test.c,
    test_keyvel.py (the curves at KEY VEL 64 / 96 / 107 / 127 at every TOUCH, a free-playing record replayed),
    test_smk_app.py, test_touch.py, test_dry_distortion.py, every tests/scripts script. The MIDI path is
    byte-identical.
  • FM-1: not tested on the device in this change.
  • Host: tools/rev_lin_proof.py (the moved cells proven linear reverb content), tests/py/test_rev_hq.py,
    tools/fx_pristine.py (the HQ HALL at MIX 127: -76.4 dBFS, the limit -74.0), the release diff's reverb cells.
  • Host: tests/py/test_seq_length.py records notes of known lengths over MIDI (short, long, overlapping, across
    the loop's end, longer than the loop, QUANT OFF and 1/16 off the grid, CC 64 and REC held, a re-strike under the
    pedal, chord mode with STRUM) and checks every played-back length on MIDI out within 12 ms; it failed 3 of 7
    before the fix. tests/scripts/seq_sustain.txt hears the same on the sound (4 expects failed before).
  • Host: make test-smk (every script on the SMK build at 10 voices, tests/scripts10 for the steal scripts),
    test_smk_host.py; the SMK package builds (./build.sh --board smk37). Not tested on an SMK-37.
  • Host: tests/scripts/sus_leds.txt (the card reached, turned both ways, the key LED under the REC latch with DARK
    and LIT, the settings saved when silent); tests/py/test_sus_leds.py (the record's layout on both boards, every
    stored value including old and bad ones under ALL / SCALE / ROOTS / PLAYED, the card saved and back after a power
    cycle); on the SMK-37 build tests/smk/smk_pages.txt (SELECT stops at DISPLAY, 25/25).
  • Host: keys 28-100 at v20 / 40 / 64 / 90 / 110 / 127, before and after: the tine band (0-20 ms), H2 re H1
    (30-300 ms), the > 1 kHz attack excess, the level (50-500 ms) and the level after key-up (never louder).
    VIBES and MARIMBA byte-identical (Gate R); the HQ pulse and contact headers unchanged.
  • Host: tests/py/test_vel_layers.py (MIDI v1..127 reach the engine unchanged at every TOUCH and KEY VEL 1 / 64 /
    127, on USB and TRS; the keys' velocity is the one sent out and struck under FULL and LIGHT; the sequencer and the
    arpeggiator keep the velocity; fails when the MIDI path clips the velocity), test_vel_resp_curves.py (ranges,
    steps, gate counts vs 0.9.9), test_release_never_louder.py, test_every_control.py (a new RESPONSE case),
    the UI scripts and tests moved to the new page (touch.txt, vel_resp.txt, test_touch.py, test_vel_resp.py,
    test_ui_meters.py, test_smk_app.py, the Move's test_screen.mjs / test_chain.mjs / test_move_*),
    tests/scripts/version.txt (VERSION reads DEV on the host, a turn changes nothing), make test, make pytest.
  • FM-1, Move, plugin: not tested on the devices in this change.
  • Host: keys 28-100 at velocities 20, 40, 64, 90, 110 and 127, before and after: the velocity knee per register, the
    tine band in the first 20 ms, H2 against H1, the attack above 1 kHz, the level, the decay per register and the
    damper time; the never-louder-after-key-up check (10 ms windows sliding by 1 ms against the onset, with three
    synthetic regression cases) on every sound at the softest and the hardest velocity; VIBES and MARIMBA
    byte-identical; Gate R, Gate H and Gate M references renewed for the intended change; make test, make pytest.
  • Host: the effects and both voice engines processed in chunks render sample for sample what the one-core 14-voice
    build renders, with no added delay; the hand-off orders, refused jobs and the one-core fallback
    (tests/py/test_c1_pipeline.py); the default build unchanged (Gate R, the firmware image's sha256).
  • Host: MT0 (tools/ci_move.sh: Gate U, make test-move, Gate M, the Move pytest suites); Gate R 123/123 and
    Gate M 78/78 with the build isolation.
  • Host: the presets by critical-band loudness and peaks against 0.9.9 (tools/quick.py level gate, tools/preset_lists.py);
    tests/py/test_bars_knock_mallet.py (VIBES and MARIMBA at BARK 0 / 64 / 96 / 127 and four velocities, a 16-note
    chord) and the never-louder-after-key-up checks on every sound and engine; make quick; Gate R, Gate H and Gate M
    renewed for the intended changes; local CI on arm64 and amd64.
  • A 30-minute stress run: 3 instances at real time, preset switches, 818 000 automation events, the window
    opened and closed, no event dropped and no memory growth.
  • Windows: the build under wine (the coroutine, the controller, the window, the CLAP host and a Gate D subset).
    Linux: x86_64 and aarch64 in Ubuntu 20.04 under Xvfb (the window and the tests); the dependency check (only the
    system's own libraries, no symbol newer than glibc 2.31).
  • Host: every script with and without the new note-on cache, and on both images: identical output (984 WAVs);
    tests/py/test_bar_cc.py (a RING, DAMPER or TYPE change between a note's arrival and its strike); Gate R.
  • Host: tests/py/test_c1_subblock.py; the one-core build byte-identical on every script; the two-core build moves
    only toward the one-core 14-voice build (the worst script, 16470 LSB apart, now 3).
  • Host: tests/py/test_c1_ram_text.py (the build check passes the flash driver and the second core's idle loop, fails
    the old RAM set); the host output is unchanged (only the code's place moves).
  • Host: tools/dry_dist.py's chords at COMP 4:1 ATK 40 REL 48 (no failure against 0.9.9 played the same);
    tests/py/test_comp_clean.py; the compressor's level, fatness and peaks by critical band (C2..C6 x v40/80/127,
    chords); test_every_control, test_display_sound, test_switch_clicks updated.
  • Host: tests/py/test_dry_width.py (width, the mono sum by band, binaural loudness, peaks, steady side); test_spread,
    test_every_control (CHORUS off, FX-BYPASS, SPREAD 0, TREM-WAH) and test_display_sound (LEVEL, THRESH) read the mono
    sum where they assumed L == R; the pristine fast grid (MARIMBA's key-up windows listed in tests/expected_changes.yaml).
  • Host: tests/py/test_recovery_drain.py; the one-core and two-core firmware build with every check ok. Not yet
    tested on the FM-1.
  • Host: tests/py/test_wd_poll.py runs the feeding code against a model: with everything alive it feeds for 60 s;
    a stopped audio interrupt stops it after 3 s, a stopped clock after its pass limit, the second core's check at once.
  • FM-1 (release builds): the worst-load soaks and the crackle runs with no reset (the watchdog never fired while the
    sound ran). A frozen audio interrupt was not provoked on the device.

Full manual: https://github.com/leonardoMirabal/frodhes/blob/main/docs/MANUAL.md · Built on Dinghy. GPL-3.0.

Don't miss a new frodhes release

NewReleases is sending notifications on new releases.