Firmware

CS-1

Hype: warming · 68

Eight-voice dual-layer polysynth in the spirit of a famous 70s flagship, meant to be played over MIDI.

forM-VAVE FM-1·by@twochannels

Unclaimed. Is this yours? Sign in with GitHub as @twochannels to claim it.

Download v0.3.2

cs1-0.3.2.fwsc· 596 KB

GPL-3.0· twochannels/CS-1·downloads come from the creator’s GitHub releases

53 commits and 3 releases in the last year

CS-1

A CS-80-style synthesizer firmware for the M-VAVE FM-1: a sound module for a dawless rig, played over MIDI (TRS or USB) from a sequencer such as the Novation Circuit Tracks.

CS-1 is a Yamaha CS-80 in spirit: eight voices of two channels each (I and II), every channel a VCO (sawtooth and / or pulse with PWM, noise), a resonant high-pass and low-pass filter in series, a sine added after the filters, a filter envelope (IL, AL, A, D, R), a VCA envelope (A, D, S, R) and the touch response (velocity and pressure to brilliance and level); a sub oscillator to pitch, filter and level; the ring modulator; the chorus / tremolo (stereo here); portamento and glissando, channel II detune, the initial pitch bend, keyboard control, sustain modes I and II, brilliance and resonance levers, and the SELECT encoder as the ribbon. For a sequencer with no hands: an auto after touch curve each note plays by itself, MIDI learn, a CC map for the Circuit Tracks' macros, and clock sync. Effects beyond the instrument: drive and two shelves, a flanger, a stereo delay with a tape character, a phaser, and a Dattorro plate reverb with a shimmer at any interval. The 22 preset tones come from the owner's manual's charts (tools/gen_presets.py says how they were read and mapped), and the voice was calibrated against a CS-80 emulation, one dry note at a time (tools/compare_wav.py). 52 sounds, 32 user presets, a documentation site with the firmware running in the browser, and an installer in the browser.

What it stands on

  • Dinghy (zvenson): the minimal FM-1 firmware template, which is the Felucca / SLOOP platform (Leo Kuroshita, Hügelton Instruments; isod89).
  • FM-106 (PatttF): the second core as an audio worker (firmware/hal/fm1_multicore.h, firmware/src/audio_worker.h) and MIDI IN on the TRS jack (midi_uart.c), ported onto the Dinghy tree here.

Everything is GPL-3.0-only; see LICENSING.md.

MIDI clock from the sequencer drives the delay's SYNC divisions (DELAY page) and the sub oscillator's (SUB OSC 2); VINTAGE on PERFORM lets each voice drift a few cents on its own, as the voice cards did.

The sounds

PRESETS (and program change) runs through these, then the 32 user slots; HOME + a key picks a tone for a channel, ALGO picks a category on HOME (PAD, STRINGS, BRASS, KEYS, BELLS, BASS, LEAD, FX, USER) for PRESETS to browse, and turns a button's pages elsewhere. The classic ones are recipes after what is documented about the records (which presets, the technique), not transcriptions; they pair a row I tone with a row II tone as the instrument does, and most carry the chorus, a touch of detune, an auto after touch curve and the plate. The last group is converted from CS-80 V factory presets on a computer with the plugin installed: tools/converted.txt lists them with our names, tools/arturia_convert.py reads each preset's panel and maps it through the same calibration as the manual's tones (tools/converted.json keeps the values, so the build does not need the plugin), and tools/level_converted.py evens out their loudness by measurement.

VangelisBLADE BRASS, BR BLUES, BR FLUTE, BR STRINGS, CHARIOTS, UNKNOWN MAN, BR BRASS 2 (Syntorial's recipe), BRASS SWELL (MusicTech's), BR BLUES 2, END TITLES, CHIMES
Toto, ThrillerAFRICA, AFRICA 2 (Syntorial's), ROSANNA, HUMAN NATURE (the chromatic glide), BILLIE JEAN, BILLIE KEYS (Syntorial's)
The eightiesBORN USA, XMAS BASS (the sub oscillator's inverted saw into the filter), WHO BASS, BABOOSHKA, DUCHESS, TURN IT ON, TIME STRINGS, VIENNA, OXYGENE, ENO WASH, WALKING, 4001 PLUCK, 4001 STRINGS, LONG BRASS, SHRIEK LEAD, SQUELCH BASS
The manual's own examplesTRUMPET, CLARINET, OBOE, TIMPANI
The plain pairsSTRINGS 1+2, BRASS 1+2, FLUTE+BASS, ORGANS, CLAVS, HARPSI, E.PIANO, FUNKY 1+2
With the effectsTAPE PAD, SHIMMER CHOIR, PHASE STRINGS, ECHO KEYS, TAPE BRASS, DEEP DRIFT
After CS-80 V presets, our namesTYRELL TOWER, RAIN ON NEON, BRASS SECTION, RISING BRASS, SOFT BRASS, STRING MACHINE, STRINGS 81, CHAMBER, WARM SKY, FIELD FLUTE, ICE BELLS, BELL TOWER, GLASS ORGAN, MUSIC BOX, CLAV FUNK, SWIM BASS, FAR SHORE, RAINDROPS

Layout

firmware/src/cs1.cthe app: the panel's pages, the screen, keys, MIDI, settings
firmware/src/cs1_voice.h, cs1_dsp.hthe voice (patch, envelopes, filters, the block render on both cores) and the fixed-point primitives
firmware/gen/cs1_tables.hthe voice's tables, from tools/gen_tables.py (committed; no FPU on the chip)
firmware/gen/cs1_presets.hthe CS-80's 22 preset tones, from tools/gen_presets.py (the manual's charts, with the mapping's assumptions)
tools/wav_check.pypitch, level and harmonics of a host render: a change to the voice checked without ears
firmware/src/platform.cthe platform wiring (boot, USB, updater, audio ISR, settings, CPU1, TRS MIDI)
firmware/hal/every hardware register access; nothing outside it touches a register (the build checks)
tests/host.c, tests/run_host.shthe app on a computer: a scripted run that writes a WAV and screen PNGs
web/emu/the browser emulator (Emscripten + AudioWorklet): play it, with Web MIDI in
web/site/, web/site.css, tools/gen_docs.pythe documentation site: overview and install, manual, sound design guide, a reference generated from the firmware's page table, with the emulator under emu/
tools/build.pythe device build (JieLi toolchain, in Docker on macOS) and the .fwsc package
docs/API.md (what the platform offers), RULES.md (the chip's rules: no float, no 64-bit division)

Build and run on a computer

pip3 install Pillow
tests/run_host.sh          # -> build/host/cs1.wav, build/host/cs1-*.png

On macOS without the Xcode licence accepted, point the compiler at the Command Line Tools: DEVELOPER_DIR=/Library/Developer/CommandLineTools tests/run_host.sh.

Play it in the browser, and the site

The firmware runs in an AudioWorklet against a fake FM-1, with the panel on the page and Web MIDI in and out (Chrome or Edge). The documentation site wraps it: the pages in web/site/, a reference that tools/gen_docs.py generates from the firmware's own page and sound tables, and the emulator under emu/. Needs Emscripten (tools/get_emsdk.sh installs it into ~/.emsdk, no Xcode or Homebrew) and Node for the test:

web/site/build.sh                # -> build/site/ (index, manual, sound, reference, img/, emu/)
node web/emu/emu_test.mjs        # the wasm in Node: boots, sounds, LEDs, MIDI, settings, determinism, cost
python3 tools/serve_web.py       # http://localhost:8000/  (the emulator at /emu/; Web MIDI needs localhost or https)

Click Switch on, then play the keys (mouse, touch, or the Q and A rows), turn the knobs (drag or wheel), and pick your MIDI interface under MIDI in to play it from a sequencer. CC 80 to 87 and MIDI learn (REC) map a controller's knobs, as on the FM-1. emu/?sound=N opens a sound, which the site's "Try" links use. The settings sector and the user bank are kept in the browser's localStorage; Export presets writes the bank to a .cs1bank file. What the emulator cannot tell you: CPU cost on the real chip, the dual-core split, USB audio and the updater.

tests/run_tests.sh runs the host build, the site build and the emulator test together. build/site/ is the whole site, ready for any static host (GitHub Pages included).

Build for the FM-1

Needs the JieLi toolchain (tools/get_toolchain.sh), the AC79 SDK checkout, and Docker on macOS:

./build.sh                 # -> build/cs1.fwsc  (DINGHY_DUAL_CORE=0 ./build.sh for single-core)
python3 tools/fm1_install.py build/cs1.fwsc

The package identity is FM-1_95N (N = minor version). Installing any custom firmware is at your own risk: hold OCT- at power-on for the USB rescue; M-VAVE's updater or the Firmware Hub's "Back to official V15" takes you back to stock, and any firmware with Felucca's or M-VAVE's update loader installs over CS-1 (from 0.3.2; before, the official package was refused on a unit with an older flash head). tests/ota_test.c runs the update entry on a computer against a package. tools/arminator_read.py and tools/arturia_convert.py --all read whole preset libraries (Arminator 2's banks via tests/vstdump.c under Wine, the CS-80 V's) into a corpus; tools/gen_random.py reduces the 910 sounds to the RANDOM page's model (a mean a category and twelve directions, firmware/gen/cs1_random.h); nothing of the libraries themselves is shipped.