github leonardoMirabal/frodhes v0.9.6
Frodhes 0.9.6

3 hours ago

Frodhes 0.9.6: a physically modelled electric piano, vibraphone and marimba for the M-VAVE FM-1. Every note is computed live from the mechanics of the instrument; there are no samples.

Download: frodhes.fwsc below (the same file as frodhes-0.9.6.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

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

If anything goes wrong, switch the FM-1 off, hold OCT− and switch it on to get the USB rescue, then install again.

Changes

  • The manual: the SCALE page's MODE and TRANSP act on the FM-1's own keys; notes from USB-MIDI and the TRS jack play
    as sent (a DIATONIC / DIA 7TH chord still takes its root onto the scale, from any source).
  • TREM/WAH: on WAH the SHAPE card shows "-" (it does nothing there and keeps its value for TREM and PAN).
  • The manual: the compressor woken from OFF keeps the volume of what you play about the same (a quiet, dying tail
    comes up, as under any compressor).
  • The browser emulator is published with every release, at the same moment, and shows the version it runs (in the
    title, the heading, the footer and on the emulated screen).
  • The emulator's knobs turn more evenly: a trackpad swipe or a mouse wheel notch moves them a step or two (a gentle
    swipe used to jump about 30 steps), and a drag moves one step every 10 pixels.
  • The manual: DELAY MIX also lowers the dry sound a little (−1 dB at the middle, −6 dB at the top), as it always
    did; REVERB MIX moves in small steps (DECAY and TONE glide); the drive types match the drive off on played
    phrases, and how a held chord's tail and single notes compare.
  • OCT− and OCT+ together go back to octave 0: hold one and press the other (GitHub issue #15). The first button
    still steps the octave as before; letting go steps nothing. The same on the SMK-37.
  • Where Frodhes keeps its data: only in flash that no region of the stock firmware's own table uses. The FM-1: the
    settings and the 16 user presets are one record in two copies (0xFC000, 0xFD000), the pattern at 0xFE000. The
    SMK-37: 0xEB000-0xF3FFF (the record, the pattern and the update staging), nothing of the stock settings area
    0x9D000-0xBFFFF any more (no owner-tag clear). Going back to stock now finds the stock settings as they were.
  • The first start after the update copies 0.9.5's settings, user presets (every slot, every older preset format) and
    pattern once to the new places, the pattern first and the record last; a power cut before the end repeats the copy
    at the next start. 0.9.5's sectors are read, never written.
  • A user preset SAVE writes the record (settings and presets) to the copy not in use, then reads it back: a power cut
    during a SAVE keeps every preset as it was before it.
  • Going back to 0.9.5: it reads its presets and pattern from its old places, as they were when this version was
    installed (presets saved since are not there). Its settings: as they were, or its defaults once this version has
    saved twice (0.9.5 does not read the new record). The new record stays, unless 0.9.5 writes over both copies.
  • COMPRESSOR: turning THRESH up from OFF starts it at −16 dB (the presets' setting) with the +2.8 dB make-up, so it
    comes on at about the same volume (it started at −0.3 dB with the make-up: 2.8 dB louder); CC 106 does the same
    when THRESHOLD is 0 (it came on without the make-up), and keeps a THRESHOLD already sent with CC 107.

Fixed

  • With the arpeggiator holding 16 notes (for example the sequencer's pattern feeding it), a new note replaces the
    oldest one instead of being lost (0.9.5 did the same).

  • A note played while every voice is busy is never lost: a stolen voice that died away during its steal fade, or
    more new notes in one audio block than voices, dropped the new note (every engine).

  • Moving these under ringing notes, echoes or a reverb tail no longer clicks, steps or bends:

    • the Rhodes TYPE (a short crossfade);
    • REVERB MIX turned down (the tail rang up to 6 dB louder at MIX 0);
    • REVERB MOD (HALL, INFINITE);
    • REVERB SIZE on PLATE and INFINITE (the old size fades into the new one in 0.13 s on PLATE, 0.19 s on INFINITE; it stepped and bent);
    • DRIVE AMOUNT on FDRV and KHLON;
    • TREM <-> WAH;
    • DELAY EFFECT DIG <-> ANA (a crossfade);
    • DELAY TIME on DIG (the old and the new time crossfade) and on ANA (it bends gently, as tape does);
    • a synced delay following a new tempo;
    • the WAH's RATE (the resonance);
    • TAPE's TONE;
    • FX (all effects off) with SPREAD on;
    • LEVEL with FX off;
    • the MASTER knob (it stepped once per audio block).
  • PERFORM: turning the DELAY or TREM/WAH knob up from OFF switches on the type you last used, not the first one.

  • PLATE: a very hot input (the compressor's full make-up into the plate) no longer overflows its input filter.

  • Touch WAH: a very hot input (the compressor's full make-up, the pedal) no longer overflows its filter.

  • A SAVE, and the settings' save, with the drive's KHLON and the tremolo on (as F06 with TREM) waited for ever: the
    output was silent, but a tiny idle residue under the silence gate never counted as quiet. Saves go through now.

  • SMK-37: the mod wheel adds TREM/WAH depth (VIBES: motor depth) on top of the DEPTH you set, and gives it back at
    rest. It used to set DEPTH itself, so at rest the effect was on at depth 0 and the preset's DEPTH was lost. What
    it switched on, it switches off again at rest.

  • SMK-37: the pitch wheel takes its centre once the reading holds still, and widens its range only to what it holds.
    A spike on the analog inputs (a jack going in, power-on) could leave a bend on or make a full travel bend only a
    little, until the next power-on.

  • A power-on whose last preset slot is empty now plays the saved sound with its synced LFO and delay rates running.
    They stayed at zero until the next tempo or rate change, while the panel showed them set.

  • REVERB INFINITE and PLATE: turning MIX no longer bends the pitch of the tail. With SIZE on AUTO, MIX also set the
    size of the space, and a size change stretches a ringing tail (a held tone went 50 to 250 cents flat while MIX
    moved). On INFINITE, AUTO is now a fixed 5.0 and MIX sets only the level. On PLATE the AUTO size waits while a tail
    rings and follows MIX again once the plate is silent, so the presets sound as before. HALL is unchanged.

  • Turning the volume no longer clicks on the jack (SMK-37 K1 in particular; USB was never affected).

  • PHASER: it keeps the level at every DEPTH. At a low DEPTH (0, the default, and up to about 48) the sweep sat
    still in the middle of the sound as a fixed notch: a chord came out about 4 dB quieter and a single A4 almost 8 dB.
    Below the middle of DEPTH the sweep now moves up as it narrows (to the top of its range at 0), and the phaser's
    level follows DEPTH so a chord's loudness matches the phaser switched off everywhere (within 0.1 LU on the host).
    Turning DEPTH glides, without a zipper.

  • CHORUS: the bass stays full. The chorus' short delay cancelled part of the lowest notes (C2 about 10 dB quieter
    at DEPTH 64); the chorus now leaves everything below about 200 Hz as it is, and its level is a little steadier
    across DEPTH (a chord within about 1 dB of the chorus off).

  • CHORUS: turning DEPTH no longer zippers (the delay tap jumped and the mix stepped with each step of the knob).

  • DELAY: turning MIX no longer steps the echoes' level (DIG, ANA and TAPE): it now glides sample by sample.

  • Loading a preset while a chord or a tail rings no longer clicks: the effects it switches fade over instead of
    switching in one sample, and the Rhodes TYPE crossfades.

  • FILTER: RESO glides; a jump of the cutoff (a MIDI CC 74 jump, a preset) moves at most 1/8 octave a step, so a
    band-pass no longer clicks and rings over; one TYPE to another crossfades on the running filter instead of
    passing through the dry sound (HP12 -> HP18 jumped about 21 dB).

  • PHASER: DEPTH and FEEDBK glide; its sweep keeps time while the phaser is off, so it comes back in step.

  • SMK-37 (GitHub #14): MASTER (K1) is kept across power cycles. It goes into the settings record (an append-only
    field, the record's version unchanged), saved with the other settings 2 s after the last turn and only in silence,
    never once a detent; at power-on it is back before the first sound. A record from before, or one without the
    value, starts at the old level (724 of 1023). The FM-1 is unchanged.

  • SMK-37 (GitHub #13): the SUSTAIN pad and REC share one latch. A tap on either switches the sustain you hear on or
    off, holding either one works as a pedal and letting go releases the latch, and a MIDI pedal let up (CC 64)
    releases it too. Before, each kept its own latch: REC could not let go of a sustain the pad had latched, nor the
    other way round.

  • An update from 0.9.5 takes in what 0.9.5 saved (settings, user presets, the pattern), also after going back to
    0.9.5 and up again: whatever 0.9.5 saved since the last time is taken in again, and only that.

  • Switching effects under a held chord no longer clicks: PHASER and CHORUS on / off, the WAH on / off, the
    COMPRESSOR on / off, every FILTER TYPE change and OFF, DRIVE AMOUNT to 0 and back: each fades over about 46 ms
    with the effect still running (as the drive's and the delay's switches always did).

  • LEVEL glides instead of stepping at each detent.

Tools

  • CI builds the emulator on every pull request and runs its selftest in Chromium and WebKit; the release workflow
    builds it from the tag, tests it, and publishes the release only once GitHub Pages serves it.
  • tools/control_sweep.py: every control (115 of them) swept and moved under a ringing chord, judged for clicks
    (against the same render without the move), zipper, level jumps, pitch and stuck states;
    tests/py/test_manual_claims.py checks the manual's promises of glides and steady levels the same way.
  • tools/monkey.py: seeded random play on the host (notes, the pedal, knobs, buttons, presets, MIDI), with checks
    for lost notes, clicks, overflows (sanitizer builds), silence after all notes off, never louder after the key-up,
    and settings that survive a power cycle; failures are shrunk to a few events. --focus-xfade aims at the
    controls with a crossfade, --shed N adds the overload's voice shedding. tools/hil_monkey.py plays the same
    streams on the FM-1 and judges the USB recording with the glitch detector.
  • tools/coverage.sh (with coverage_sum.py): line and condition coverage of the host tests.
  • tools/hil_usb_bench.py: a bench build (APP_DEFS=-DFELUCCA_UAC_TONE=1 or 2, never in a normal build) that
    sends a known wave through the USB audio path, to tell a lost or repeated USB frame from the music.
  • tools/hil_crackle.py: a repeated-frame event is counted only where the wave around it is predictable and well
    over the music's own quiet plateaus (fewer false alarms on noisy music; real copies are still found).

Tested

  • Host: tests/scripts/arp_full.txt (the arpeggiator fed past 16 notes: the newest note plays, the oldest leaves),
    Gate R (the new script's render added; every other render unchanged).
  • Host: tests/py/test_steal_race.py, tests/py/test_switch_clicks.py (the cases above; each fails on 0.9.5),
    tests/py/test_control_sweep.py (REVERB SIZE on PLATE and INFINITE: no bend, no click),
    tests/py/test_delay_time_change.py, tests/py/test_overflows.py (under ASan + UBSan), tests/py/test_monkey.py,
    tests/py/test_persistence.py (a save with KHLON + TREM, then a power cycle; a record naming an empty slot), tests/scripts/perform_wake.txt,
    scale_midi.txt, wah_shape.txt, quiet_gated.txt, tests/smk/wheels.txt and wheel_pedal.txt (make test-smk; the pedal
    plugged in at power-on, a spike as it goes in), tests/smk_wheel_test.c, the control sweep (tools/control_sweep.py) and the manual's claims with their
    expected failures removed, make test, make pytest, Gate R.
  • Host: a held 440 Hz tone in INFINITE FREEZE with MIX swept from 64 to 120: the tail stays within 0.2 cents of the
    same take with MIX held (it was up to 180 cents flat); the same on a ringing PLATE tail (it was up to 188 cents
    flat). INFINITE on AUTO renders the same as SIZE 5.0, sample for sample; PLATE on AUTO with MIX changed while
    silent renders as the fixed size, and every HALL and PLATE render is unchanged (Gate R).
  • Host: tests/py/test_master_click.py (the platform's MASTER pass on the app's output, single detents and fast spins
    at low, mid and full volume: the largest second difference within 1.5x of the same audio at a steady gain; 0.9.5's
    pass 5-28x).
  • Host: tests/py/test_mix_levels.py (the chorus DEPTH, phaser DEPTH and delay MIX zipper, the chorus' bass and level,
    the phaser's level at every DEPTH, the chorus' pitch while DEPTH moves; it fails on the code before), make test,
    make pytest, Gate R (re-saved: the chorus and phaser renders move on purpose), ./build.sh.
  • Host: tests/scripts/oct_reset.txt (both orders, from either end, single presses still step; fails on 0.9.5) on the
    FM-1 and the SMK-37 builds, make test, make test-smk.
  • Host: preset loads under a held, pedalled chord (F01 to F02, F06, F07, F09, F11 and F12, F07 / F09 to F01, F11 to
    F19): the largest second difference around the load 0.8-6.5x the same chord without it (the click limit is 10x);
    the control sweep's FILTER and PHASER cases.
  • Host: tests/py/test_smk_host.py (turned, saved, switched off and on: the same level; an old record: 724; K1
    turned every 500 ms for 5 s: no flash write while it turns, one settings save 2 s after the last detent),
    tests/smk/encoders.txt (K1's detents reach MASTER), make test-smk, make test; the FM-1 firmware is byte for byte
    the same (sha256 of the fwsc before and after).
  • Host: tests/smk/sus_shared.txt (both orders, holds, CC 64, a note ringing and released), tests/smk/pedal.txt,
    make test-smk, make test; the FM-1 firmware is byte for byte the same (sha256 of the fwsc before and after).
  • Host: tests/set_ab_test.c (FM-1 and SMK-37: a power cut at every call of a save and of the migration's commit,
    three ways, from every start; the copies alternating; a save plus a power cycle; the flash model fails the test on
    any write outside the store), tests/smk_flash_test.c, tests/py/test_store_migration.py (a full 0.9.5 bank in v3,
    v2 and v1 format, every field compared; no old data; a corrupt bank; a migration cut two ways; the SMK-37 only
    under its owner tag), tests/py/test_persistence.py, tests/py/test_smk_host.py, make test, make test-smk.
  • Not tested on hardware:
    • The FM-1 from V15: the update staging stays at 0xE0000 (the end of V15's settings area, which its factory settings
      leave erased; 0.9.5 and Felucca staged there too). Whether V15's own updater stages exactly there is not proven.
      From V16 (no V15 settings marker at 0x93000) it stages at 0xA9000-0xADFFF, a gap in V16's table.
    • The SMK-37: the staging moved to 0xEF000-0xF3FFF. Where the chip's boot code looks for the update record after a
      power cut during an install is not known for the SMK-37 (docs/SMK37.md).
    • MKE-P37: every install erases 0x9C000, the first sector of its stock settings area (docs/SMK37.md).
  • Host: tests/py/test_store_migration.py (up from 0.9.5, back to 0.9.5 with a save there, up again: the setup and
    the pattern 0.9.5 saved come back; what 0.9.5 did not change stays), tests/py/test_hil_store_migration.py.
  • Host: tests/py/test_switch_clicks.py, a differential click check (the largest second difference around the change
    against the same render without it, under 10x; the old ones were 14-307x), and the compressor's wake level.

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.