overdub

bizar

klaine/bizar · ★ 0

Bizarre dual engine synth module for Ableton Move (Schwung)

README from GitHub, MIT

Bizar

Bizar is a two-engine hybrid synthesizer for Ableton Move, running as a sound-generator module in Schwung. Two digital oscillators with more than two dozen engines each, a resonant filter, two LFOs, a Cycling Envelope, a 12-column modulation matrix, four macros, three effect slots, a sequencer and an arpeggiator, and 128 original presets, all playable from Move's knobs and pads.

Bizar takes its workflow from two-engine performance synths such as Arturia's MiniFreak. It is not an Arturia product and is not affiliated with Arturia, and it contains no Arturia code, firmware, presets or samples. Several engines are adapted from Emilie Gillet's Plaits (MIT); see THIRD_PARTY_NOTICES.md.

Installing on Move

Bizar needs a Move with Schwung installed.

  1. Download bizar-module.tar.gz from the latest release.
  2. Install it with Schwung Manager, or by hand: extract the archive so that it lands at /data/UserData/schwung/modules/sound_generators/bizar/ on the Move.
  3. Rescan modules in Schwung Manager, or restart Schwung.

Bizar then appears under Sound Generators as BIZR.

Developers with SSH access can install a local build with sh scripts/deploy.sh (macOS and Linux) or scripts/install-windows.ps1 (Windows, see Building from source). Both stage the files on the Move's data partition and rename them into place, so a running Schwung is not disturbed.

How it works

The signal path is one voice of a classic hybrid synth, six times over:

flowchart LR
    subgraph voice [Each voice]
        O1[Osc 1] --> MIX[Mix]
        O1 -.->|processor modes| O2[Osc 2]
        O2 --> MIX
        O1 -.-> FFM{{Filter FM}}
        O2 -.-> FFM
        MIX --> F["Filter (LP / BP / HP)"] --> VCA[VCA]
        FFM -.-> F
    end
    VCA --> SUM((All voices))
    SUM --> E1[Effect 1] --> E2[Effect 2] --> E3[Effect 3] --> OUT([Out])

Everything below is reachable from Move's parameter pages, and most of it from the Remote UI too.

Oscillators

Each oscillator has Type, Wave, Timbre, Shape, Tune and Volume. The three timbre knobs mean something specific to each engine, and the page relabels them when the type changes (a wavetable engine's Wave knob becomes Position, for example).

Oscillator 1 chooses from BasicWaves, Two Op FM, Wavefolder, Noise, Wavetable, SuperWave, Harmo, Formant, V.Analog, Waveshaper, Chords, KarplusStr, SawX, Harm, Bass, Modal and Speech.

Oscillator 2 has the same generators plus processor modes that work on Oscillator 1's signal: Ring, Wavefolder, MultiFilter, Crusher, Comb Filter, Surgeon Filter, Phaser Filter, Destroy and FM / RM. That is where the "hybrid" comes from: Osc 2 can be a second voice or a treatment of the first.

The Wavetable engine picks one of 32 banks of 64 frames each (from the CC0 WaveEdit Online collection, listed in assets/wavetables/README.md), with anti-aliased mip levels. Each oscillator also has a Mod Quantize setting that snaps its pitch modulation to a scale, for sequenced and sample-and-hold pitch lines that stay in key.

Filter and envelopes

A per-voice resonant filter with low-pass, band-pass and high-pass modes, envelope amount and audio-rate Filter FM from Osc 1, Osc 2 or their mix. The ADSR envelope has Default/Quick attack and Default/Percussive decay and release curves, and a retrigger switch. A Velocity Targets page sets how velocity reaches the VCA, the filter, envelope depth and envelope time.

Modulation

  • Two LFOs with nine shapes (Triangle, Saw, Square, an editable eight-point Shaper curve, Sine, S&H, Slew S&H, ExpSaw, ExpRamp), tempo sync over 27 divisions, and Free, Poly, Mono, Legato and One-shot retrigger modes. Synced LFOs follow Move's transport.
  • Cycling Envelope, a looping Rise/Hold/Fall generator with Env, Run and Loop modes.
  • Modulation matrix of twelve destination columns fed by seven sources: Cycling Envelope, Envelope, LFO 1, LFO 2, Velocity + Aftertouch, Wheel and Key Track. A matrix cell can itself be a destination, so one source can scale another's depth.
  • Four macros, each driving up to four destinations with its own amounts.

Effects

Three stereo slots in series. Each slot picks a type and then a preset for that type:

TypePresets
DelayDigital, Stereo, Ping-Pong, Mono, Filtered, Filtered Ping-Pong, Tape, each also as a tempo-synced version
ReverbDefault, Long, Hall, Echoes, Room, Dark Room
ChorusDefault, Lush, Dark, Shaded, Single
PhaserDefault, Space, SnH, each free or synced
FlangerDefault, Silly, each free or synced
Super UnisonClassic, Ravey, Soli, Slow, Slow Trig, Wide Trig, Mono Trig, Wavy
DriveClassic, Soft Clip, Germanium, Dual Fold, Climb, Tape
Crusher, 3-Band EQ, Peak EQ, Multi CompBit crushing, a three-band EQ, a parametric peak and a three-band compressor

Voices and playing

Six-voice polyphony, plus Mono and Unison modes (mono or poly stacks with spread) and a keyboard Chord mode that plays up to five intervals from one key. Bizar responds to velocity, pitch bend, channel pressure, polyphonic aftertouch, the mod wheel and the sustain pedal.

Sequencer and arpeggiator

Both are clocked from Move's tempo and start when you hold keys:

  • Seq plays a pattern of up to 64 steps with up to six notes per step, transposed by the last key held.
  • Arp plays the held keys Up, Down, Up/Down, Random, in played order, as a chord or Poly, over one to four octaves.

Rate is a 15-entry division list with gate and swing. Up to four automation lanes each aim at a modulation destination and hold one value per step, stepped or smoothed. The sequence is edited in the Remote UI and saved with the patch.

Presets

128 original presets, sixteen in each of eight categories. Each name starts with a two-letter tag so the list is easy to browse on Move's display:

TagCategoryTagCategory
BABassPDPads
LDLeadsPLPlucks and mallets
KYKeysARArpeggios and sequences
PYPolysynths and brassFXEffects, drones and percussion

Every preset shares the same two macros, so the whole bank plays the same way: Macro 1, Timbre opens the filter and moves the engines' signature controls with it, and Macro 2, Space raises the delay, reverb and release. Presets built on an LFO add Macro 3, Motion, the LFO's depth. The macros start at zero, where the preset sounds as designed. PY Init is a plain saw to start from.

On Move

Bizar's parameter pages, in order: Main (macros, output, cutoff, resonance, attack and release), Factory Patches (it steps through the category that the next page, Patch Category, picks), Patch Category, Oscillator 1, Oscillator 2, Filter, Envelope, Velocity Targets, Cycling Envelope, LFO 1 and LFO 2 (each with a Curve page for the Shaper), Mod Matrix, Matrix Editor, Macros and the four Macro Slots pages, Effect 1 to 3, Voice, Chord and Settings. Each page shows up to eight knobs; controls that only apply to the current engine or effect are hidden until it is selected. PARAMETER_REFERENCE.md lists every page with its ranges and defaults.

Patches are saved and automated through Schwung like any other module. The Remote UI, served by Schwung in a browser, adds what a small screen cannot: knobs for everything, draggable envelope and Shaper curves, a filter response view, waveform previews, the full modulation matrix with hardware-style mod assign, the sequencer editor, undo and redo, a patch browser with categories, favourites and your own patches, A/B compare, patch export and import, and share links that carry the patch in the URL.

Playing in the browser

https://klaine.github.io/bizar/ is the whole synth as a single page: the Remote UI plus the same DSP compiled to WebAssembly. Click Start Bizar, then play from a WebMIDI device (Chrome or Edge; Firefox needs a MIDI add-on), from the computer keyboard in Live's layout (A to K are the white keys, W E T Y U O P the black ones, Z and X shift octaves, C and V velocity), or from the on-screen keyboard. A BPM box drives the synced LFOs and the sequencer, the MIDI menu picks the input and channel and can follow MIDI clock, and Alt-click (or L) on a knob learns a MIDI controller. Your sound is kept in the browser and restored on the next visit.

Building from source

Requirements: a POSIX shell, Python 3, and for the device build either an AArch64 cross compiler (aarch64-linux-gnu-gcc, or set CC) or zig, which the build falls back to as zig cc. The web build needs zig.

sh scripts/build.sh

This writes dist/bizar/ (the module directory), dist/bizar-module.tar.gz, the same bytes as dist/bizar-module-<version>.tar.gz, and dist/bizar-web.html when zig is available.

Other targets:

CC=cc sh scripts/build.sh --test        # desktop DSP and integration tests
sh scripts/build.sh --reference         # regenerate PARAMETER_REFERENCE.md and docs/PRESETS.md
sh scripts/build.sh --web               # browser build only
sh scripts/deploy.sh                    # install the build on a Move over SSH

Without a local toolchain, scripts/Dockerfile builds a container with everything needed, and scripts/build-windows.ps1 runs the same build from PowerShell with Docker Desktop. scripts/install-windows.ps1 installs the result on a Move from Windows.

The parameter reference and preset list are generated from the module's own contract, and CI fails if the committed copies are stale, so they cannot drift from the code. See CONTRIBUTING.md before opening a pull request.

Using your own MiniFreak presets

If you own a MiniFreak, you can compile an exported .mnfx bank into a personal build:

MINIFREAK_BANK=private/MyBank.mnfx sh scripts/build.sh

Such a build is written as dist/bizar-module-personal.tar.gz and must not be shared or published. docs/MINIFREAK_IMPORT.md has the export steps and what the importer covers.

Status

Bizar is a beta. Known gaps:

  • The Sample, Particles, Cloud Grains, Hit Grains, Frozen, Skan, Lick, Raster and Audio In engine types load and respond to their knobs but play a placeholder tone. They need an asset-loading and audio-input model that keeps file I/O off the audio thread.
  • No vocoder effect and no user wavetable import.
  • Modal is struck only; a sustained, dust-excited mode is not wired up.
  • The three effect slots always run in series. There is no per-slot send routing.

Bug reports and ideas are welcome as issues.

Project layout

PathContents
src/bizar.cPlugin adapter: parameters, pages, state, presets, voice allocation and rendering
src/engines.c, effects.c, filter.c, modulation.c, voice.c, sequencer.cAllocation-free DSP
scripts/generate_factory_bank.pyThe 128 factory presets, compiled into the module at build time
scripts/generate_wavetables.pyConverts the CC0 wavetables into mip levels
web_ui.html, web_ui_extras.jsRemote UI
web/Browser build: WebAssembly glue, host shim and bundler
tests/test_plugin.cDesktop DSP and integration tests
tools/Contract dump, factory level meter and preset renderer
include/Schwung ABI declarations, so the module builds without a Schwung checkout

The module does no file I/O and no heap allocation in its audio callbacks. Engine and effect indices are part of the patch format, so new ones are appended and older patches are migrated on load.

License

MIT, see LICENSE. Parts of the engines are adapted from Plaits (MIT) and the built-in wavetables are CC0 1.0; see THIRD_PARTY_NOTICES.md and assets/wavetables/README.md. Schwung and Ableton Move are separate projects under their own licenses.