SoC Projects

All Projects

polysyn

8-voice touch/MIDI polysynth with scope.

Pitch / Touch         Audio / CV
             ┌────┐
C2    touch0 │in0 │◄─ phase modulation
G2    touch1 │in1 │◄─ filter envelope
C3    touch2 │in2 │◄─ drive
Eb3   touch3 │in3 │◄─ -
             └────┘
             ┌────┐
G3    touch4 │out0│─► -
C4    touch5 │out1│─► MIDI CLK
-     touch6 │out2│─► audio out (L)
-     touch7 │out3│─► audio out (R)
             └────┘

Voices are controlled through touching jacks 0-5 or using a MIDI keyboard (TRS MIDI or USB host is supported). The control source must be selected in the menu system (MISC page).

  • Voice mix is sent to output channels 2 and 3 (last 2 jacks).

  • For touch, the touch magnitude controls the filter envelopes of each voice. For MIDI, the velocity of each note and mod wheel affects the filter envelopes.

  • When a jack is patched into input 0, 1 or 2, CV can be used to modulate all voices simultaneously up to audio rate (phase mod, filter cutoff and drive). Inputs 1 and 2 act as bipolar offsets on top of the existing envelope / knob value. Patch an LFO into phase CV for retro ‘tape-wow’ like detuning. Patch an oscillator into phase CV for FM effects, or into drive for AM effect.

Each voice is hard panned left or right in the stereo field, with 2 end-of-chain effects: distortion and diffusion (delay), both of which can be mixed in with the UI.

      USB MIDI   TRS MIDI
         ─────┐ ┌─────  (`usb-host` setting)
        ┌─────▼─▼─────┐
touch──►│Voice Tracker├──►┌─────────┐
        └─────────────┘   │ Voices  │
                          │  (x8)   │
                          │         │
                          │ Wavetbl │
                          │    ▼    │
                          │  ADSR   │ (ADSR sets filter cutoff)
                          │    ▼    │
                          │ Filter  │ (resonance =
                          └─────────┘  `reso` setting)
                          ┌────▼────┐
                          │Mix L/R  │
                          │(stereo) │
                          └────┬────┘
                          ┌────▼────┐ (wet/dry mix =
                          │Diffuser │  `diffuse` setting)
                          └────┬────┘
                          ┌────▼────┐
                          │  Drive  │ (`drive` setting)
                          └────┬────┘
                          ┌────┴───┐
                          │Audio   │
                          │OUT (4x)├──────► out2 (L)
                          └────────┴──────► out3 (R)

The VOICE page allows selection between many wavetables. The ‘proc’ option allows applying effects (e.g. saturation, wavefolding, rectify) to the wavetable before it hits the voice filter. When no CV is patched into input 0, a built-in sine LFO modulates the phase of all voices (rate and depth are adjustable on the VOICE page).

If a MIDI clock is present on TRS or USB MIDI, it is divided by 24 (1PPQN) and sent out on output jack 1. STOP/START/CONTINUE is respected. The LED will pulse with the clock ONLY if that jack is connected.

The following options are tweakable in the menu. Note that the USB/TRS MIDI can also be used to control most of these through CCs as follows:

Page    Parameter     CC  Description
────    ─────────     ──  ───────────
HELP    scroll         -  scroll help text up/down

VOICE   waveform      20  wavetable selection
VOICE   proc          21  wavetable processing mode
VOICE   proc-amt      22  wavetable processing amount
VOICE   reso          23  filter resonance
VOICE   lfo-rate      24  phase modulation LFO rate
VOICE   lfo-depth     25  phase modulation LFO depth

ADSR    attack        30  filter envelope attack
ADSR    decay         31  filter envelope decay
ADSR    sustain       32  filter envelope sustain
ADSR    release       33  filter envelope release

EFFECT  drive         40  distortion amount
EFFECT  diffuse       41  diffusion wet/dry mix

BEAM    scale         50  vectorscope volts/div
BEAM    persist       51  phosphor persistence (high = slow)
                       -  (CC 52 deprecated)
BEAM    intensity     53  trace intensity
BEAM    hue           54  trace and menu hue
BEAM    palette       55  color palette

MISC    touch-ctrl     -  enable/disable jacktouch input
MISC    cc-highlight   -  highlight changed on CC input
MISC    usb-host       -  enable USB host MIDI (disables TRS)
MISC    serial-debug   -  dump MIDI data out serial port
MISC    save-opts      -  save all options to flash
MISC    wipe-opts      -  reset all options to defaults

MIDI CC 1 (mod wheel) controls filter cutoff. CC 64 (sustain pedal) holds voices. Pitch bend is also supported.

xbeam

Vectorscope/oscilloscope with menu system, USB audio and tunable delay lines.

  • In vectorscope mode, rasterize X/Y, intensity and color to a simulated CRT, with adjustable beam settings, scale and offset for each channel.

  • In oscilloscope mode, all 4 input channels are plotted simultaneosly with adjustable timebase, trigger settings and so on.

The channels are assigned as follows:

         Vectorscope │ Oscilloscope
┌────┐               │
│in0 │◄─ x           │ channel 0 + trig
│in1 │◄─ y           │ channel 1
│in2 │◄─ intensity   │ channel 2
│in3 │◄─ color       │ channel 3
└────┘

A USB audio interface, tunable delay lines, and series of switches is included in the signal path to open up more applications. The overall signal flow looks like this:

in0/x ───────►┌───────┐
in1/y ───────►│Audio  │
in2/i ───────►│IN (4x)│
in3/c ───────►└───┬───┘
                  ▼
         ┌───◄─[SPLIT]─►────┐
         │        │         ▼
         │        ▼  ┌──────────────┐     ┌────────┐
         │        │  │4in/4out USB  ├────►│Computer│
         │        │  │Audio I/F     │◄────│(USB2)  │
         │        │  └──────┬───────┘     └────────┘
         │        └───┐ ┌───┘
         │ usb=bypass ▼ ▼ usb=enabled
         │           [MUX]
         │      ┌──────────────┐
         │      │4x Delay Lines│ (tunable)
         │      └──────┬───────┘
         │             ▼
         └────┐ ┌─◄─[SPLIT]─►────┐
              │ │                │
   src=inputs ▼ ▼ src=outputs    │
             [MUX]               │
               │                 ▼
         ┌─────▼──────┐     ┌────────┬──────► out0
         │Vectorscope/│     │Audio   ├──────► out1
         │Oscilloscope│     │OUT (4x)├──────► out2
         └────────────┘     └────────┴──────► out3

The [MUX] elements pictured above can be switched by the menu system, for viewing different parts of the signal path (i.e inputs or outputs to delay lines, USB streams). Some usage ideas:

  • With plot_src=inputs and usb_mode=bypass, we can visualize our analog audio inputs.

  • With plot_src=outputs and usb_mode=bypass, we can visualize our analog audio inputs after being affected by the delay lines (this is fun to get patterns out of duplicated mono signals)

  • With plot_src=outputs and usb_mode=enable, we can visualize a USB audio stream as it is sent to the analog outputs. This is perfect for visualizing oscilloscope music being streamed from a computer.

  • With plot_src=inputs and usb_mode=enable, we can visualize what we are sending back to the computer on our analog inputs.

Note

The USB audio interface will always enumerate if it is connected to a computer, however it is only part of the signal flow if usb_mode=enabled in the menu system.

The following options are tweakable in the menu. Note that the MIDI TRS input can also be used to control most of these through CCs as follows:

Page    Parameter     CC  Description
────    ─────────     ──  ───────────
HELP    scroll         -  scroll help text up/down

                          (Hint: to hide HELP page --
                           use 'MISC: help' below)

VECTOR  x-offset      20  in0 (horizontal deflection) offset
VECTOR  x-scale       21  in0 (horizontal deflection) volts/div
VECTOR  y-offset      22  in1 (vertical deflection) offset
VECTOR  y-scale       23  in1 (vertical deflection) volts/div
VECTOR  i-offset      24  in2 (beam intensity) offset
VECTOR  i-scale       25  in2 (beam intensity CV) scale
VECTOR  c-offset      26  in3 (beam color) offset
VECTOR  c-scale       27  in4 (beam color CV) scale

DELAY   delay-x       30  in0/X channel delayline length
DELAY   delay-y       31  in1/Y channel delayline length
DELAY   delay-i       32  in2/intensity delayline length
DELAY   delay-c       33  in3/color delayline length

BEAM    persist       40  phosphor persistence (high = slow)
                       -  (CC 41 deprecated)
BEAM    ui-hue        42  menu and grid overlay hue
BEAM    palette       43  color palette
BEAM    grid          44  grid overlay style
BEAM    grid-i        45  grid overlay intensity

MISC    plot-type     50  vectorscope or oscilloscope
MISC    plot-src      51  plot inputs or outputs
MISC    usb-mode       -  enable/bypass USB audio
MISC    rotation      52  screen rotation
MISC    help           -  show/hide leftmost help page
MISC    cc-highlight   -  highlight changed on CC input
MISC    save-opts      -  save all options to flash
MISC    wipe-opts      -  reset all options to defaults

SCOPE1  ypos0         60  channel 0 vertical position
SCOPE1  ypos1         61  channel 1 vertical position
SCOPE1  ypos2         62  channel 2 vertical position
SCOPE1  ypos3         63  channel 3 vertical position
SCOPE1  n-channels    64  number of active channels

SCOPE2  yscale        70  vertical volts/div
SCOPE2  timebase      71  horizontal time/div
SCOPE2  xzoom         72  horizontal zoom
SCOPE2  trig-mode     73  trigger mode
SCOPE2  trig-lvl      74  trigger level
SCOPE2  intensity     75  trace intensity
SCOPE2  hue           76  trace color

Note

By default, this core builds for 48kHz/16bit sampling. However, Tiliqua is shipped with --fs-192khz enabled, which provides much higher fidelity plots. If you’re feeling adventurous, you can also synthesize with the environment variable TILIQUA_ASQ_WIDTH=24 to use a completely 24-bit audio path. This mostly works, but might break the scope triggering and use a bit more FPGA resources.

macro_osc

‘Macro-Oscillator’ runs a downsampled version of the DSP code from a famous Eurorack module (credits below), on a softcore, to demonstrate the compute capabilities available if you do everything in software, using a really large CPU that has big caches and an FPU.

┌────┐
│in0 │◄─ frequency modulation
│in1 │◄─ trigger
│in2 │◄─ timbre modulation
│in3 │◄─ morph modulation
└────┘
┌────┐
│out0│─► -
│out1│─► -
│out2│─► 'out' output (mono)
│out3│─► 'aux' output (mono)
└────┘

Most engines are available for tweaking and patching via the UI. A couple of engines use a bit more compute and may cause the UI to slow down or audio to glitch, so these ones are disabled. A scope and vectorscope is included and hooked up to the oscillator outputs so you can visualize exactly what the softcore is spitting out.

                  (write samples to)
                 ┌─────────────────┐
                 │                 ▼
 poll       ┌────┴─────┐┌───────────────────┐
audio/ ────►│VexiiRiscv││AudioFifoPeripheral│
  CV        └──────────┘└──────────┬────────┘
             (plaits               ▼
               engines)      ┌──[SPLIT]────────►
                             │             (audio out)
                             ▼
                    ┌────────────┐
                    │Vectorscope/│
                    │Oscilloscope│
                    └────────────┘

The original module was designed to run at 48kHz. Here, we instantiate a powerful (rv32imafc) softcore (this one includes an FPU), which is enough to run most engines at ~24kHz-48kHz, however with the video and menu system running simultaneously, it’s necessary to clock this down to 24kHz. Surprisingly, most engines still sound reasonable. The resampling from 24kHz <-> 48kHz is performed in hardware below.

There is quite some heavy compute here and RAM usage, as a result, the audio buffers are too big to fit in BRAM. In this demo, both the firmware and the DSP buffers are allocated from external PSRAM.

Credits to Emilie Gillet for the original Plaits module and firmware.

Credits to Oliver Rockstedt for the Rust port of said firmware:

https://github.com/sourcebox/mi-plaits-dsp-rs

The Rust port is what is running on this softcore.

sid

This example instantiates a SID chip, which can be modulated via CV.

┌────┐
│in0 │◄─ modulation source 0
│in1 │◄─ modulation source 1
│in2 │◄─ modulation source 2
│in3 │◄─ modulation source 3
└────┘
┌────┐
│out0│─► voice 0 (solo)
│out1│─► voice 1 (solo)
│out2│─► voice 2 (solo)
│out3│─► voices 0-2 (sum)
└────┘

Using the menu system, each input channel can be assigned to a modulation target (i.e pitch / gate of specific voices or multiple voices).

The soft CPU then uses this mapping to redirect CV to perform specific register writes on the SID chip. To add new modulation types or for more complex modulation, only the rust firmware needs to be changed.

The audio routing out the SID chip to the audio outputs however is pure gateware. The softcore is only used for register writes.

                ┌──────────┐  ┌───┐
(poll CV) ─────►│VexiiRiscv│  │SID│ ─────► (audio out)
                └────┬─────┘  └───┘
                     │          ▲
                     └──────────┘
                   (register writes)

There is a lot of design space left to explore here. For example, adding MIDI input, more modulation sources, adding end of chain effects and so on…

sampler

3-channel sampler with CV+touch control.

Record audio into a single shared sample buffer (~5 sec). Three independent grain channels read from different positions in the same buffer. Toggle recording from the DELAYLINE page.

┌────┐
│in0 │◄─ audio in (record source)
│in1 │◄─ gate ch0 (CV or touch)
│in2 │◄─ gate ch1 (CV or touch)
│in3 │◄─ gate ch2 (CV or touch)
└────┘
┌────┐
│out0│──► channel 0
│out1│──► channel 1
│out2│──► channel 2
│out3│──► mix (ch0+ch1+ch2)
└────┘

Each ‘Grain Channel’ is independent, with a start and stop position and playback mode. The behaviour of touch/CV is different in each mode:

  • Gate: Play while gate is high. Stop and reset on release.

  • Oneshot: Trigger full grain on rising edge.

  • Loop: Continuously loop from start to end (gated by touch/CV).

  • LoopOn: Loop with gate stuck on. Touch/CV controls playback speed.

  • Bounce: Ping-pong between start and end (gated by touch/CV).

  • BounceOn: Bounce with gate stuck on. Touch/CV controls playback speed.

  • ScrubFast: CV scrubs position within grain.

  • ScrubSlow: CV scrubs position (with one-pole filter)

When no cable is plugged into a gate input, the corresponding jack captouch (1/2/3) acts as a gate. If a jack is plugged in, gate trigger is 2V with 1V hysteresis. Jack CV may also be used to control pitch or scrub grain position, depending on the playback mode.

Record may be toggled ON and OFF at any time, to bring in new material and freeze the sample buffer. Alternatively, record may be left permanently ON and gates triggered while new material is arriving. This can be used for slewable delayline and Karplus-strong effects (especially in SCRUB mode).

Note

WARN: saving / loading settings and playback buffers happens to a fixed region in SPI flash at the moment, which is a bit slow!

Note

WARN: pop prevention is not implemented yet, you might need to fiddle with the grain start/end positions to get clean gates.

selftest

Collect some information about Tiliqua health, display it on the video output and log it over serial. This is mostly used to check for hardware issues and for calibration.

bootloader