Skip to content

Repository files navigation

PicoFaceYC

A Yamaha reface YC combo/home organ clone for the RP2350. PicoFaceYC is the sibling project of PicoFaceDX, sharing the same hardware base (SparkFun Pro Micro RP2350 board, I2S DAC output, SH1106 128x64 OLED, 3 rotary encoders). The organ engine features a wavetable-based additive footage synthesis architecture ported from setBfree concepts.

Features

Category Details
Engine Organ Flutes tone generator (Wavetable-based additive footage synthesis). 5 Wave types: H (Tonewheel warm), V (Vox square), F (Farfisa sawtooth), A (Japanese transistor bright), Y (Yamaha transistor). Derived/ported from setBfree (BeatrixCPP).
Polyphony 16 voices (YC_MAX_VOICES). Yamaha spec states 128; 32 still overloaded the RP2350 at 9-footage-per-voice + full FX (§36), so the cap was lowered to 16 for guaranteed stability. Tunable constexpr in yc_core.h; a CPU-load watchdog (§38) forces all-notes-off on sustained overload. Raise only after on-hardware CPU-load measurement.
Sample rate 44100 Hz
DMA buffer 64 Samples (kChunkLen in YC_Synth_Bridge)
DSP style Header-only (include/yc_engine/), no dynamic allocation, fixed buffers, single-precision float throughout.
MIDI USB-MIDI (TinyUSB, no DIN-Port). Note On/Off with Octave Transpose, Sustain (CC64) always active, RX channel filter (Omni default), gated Panel CCs, outgoing Panel Mirroring, SysEx Parameter Change/Request, Identity Reply. NO Program Change.
Effects Fixed chain: Percussion -> Vibrato/Chorus -> Overdrive -> Rotary Speaker -> Reverb -> Soft-Clip Limiter.
Persistence Virtual EEPROM (wear-leveled Flash append log, reused from PicoFaceDX). Autosave 2s after last change.
Presets None. Panel state is fully SysEx-addressable.
Display SH1106 128x64 OLED
Controls 3 rotary encoders (Selector/ParamA/ParamB) across 11 pages.

Signal flow / architecture

USB-MIDI (Core 1)
    |
    v
RefaceMidi (Core 1) --IPC--> YC_Synth_Bridge (Core 0) --> yc_engine (Tonegen/Percussion/Vibrato/Rotary/FX/Reverb) --> I2S DAC (DMA-IRQ)
    ^
    |
YC_Controller (Core 1) --IPC--> [same Bridge]
    |
    v
YC_GUI --> SH1106 OLED

Hardware pinout

Pinout is unchanged from PicoFaceDX (same board).

Function Pin
I2S DATA 26
I2S BCLK 27
I2S LRCLK 28
OLED SDA 2
OLED SCL 3
Selector encoder CLK 6
Selector encoder DT 7
Selector encoder SW 8
Param A encoder CLK 10
Param A encoder DT 11
Param A encoder SW 14 (optional)
Param B encoder CLK 12
Param B encoder DT 13
Param B encoder SW 15 (optional)
Status LED 25
DIN-MIDI RX 5 (Header present, unused)

Repository layout

effects/
  ram_hot.h
include/
  yc_engine/
    yc_core.h
    yc_tonegen.h
    yc_wavetable.h
    yc_percussion.h
    yc_vibrato.h
    yc_rotary.h
    yc_fx.h
    yc_reverb.h
    yc_engine.h
  YC_Controller.h
  YC_GUI.h
  YC_Synth_Bridge.h
  ipc.h
  midi_reface.h
  midi_input_usb.h
  pico_frontpanel.h
  pico_userinterface.h
  pico_hw.h
  settings.h
  veeprom.h
  project_config.h
  tusb_config.h
  get_serial.h
src/
  Corresponding .cpp files
  main.cpp
  usb_descriptors.c
  get_serial.c
test/
  yc_engine_host_test.cpp
doc/
  MIDI_IMPLEMENTATION.md
  PERSISTENCE.md
  UI_PAGE_MAP.md
  IPC_PROTOCOL.md
  CHANGELOG_YC_ENGINE.md
  reface manual PDFs
tools/OpenB3/BeatrixCPP/
  setBfree reference (read-only, not compiled)

Building the firmware

Toolchain: arm-none-eabi-gcc, CMake >= 3.22, Ninja.

Clone the repository using --recurse-submodules to fetch the required pico-sdk and pico-extras.

Build:

git clone --recurse-submodules https://github.com/<owner>/PicoFaceYC.git
cd PicoFaceYC
mkdir build && cd build
cmake -G Ninja ..
ninja

Firmware Footprint (after the §21-§30 optimization pass):

  • Flash: ~117 KB of 16 MB (~0.71%) — LUT set moved from RAM to XIP flash (.rodata)
  • RAM: ~55 KB of 512 KB (~10.8%) — LUTs in flash, but the active wave table is mirrored to an 8 KB RAM buffer (§33) so the voice-render hot path never touches XIP flash

Controls

The interface uses 3 rotary encoders (Selector, ParamA, ParamB) across 11 pages. Selector long-press (>=500ms) opens the system menu (About/CPU Load).

Page Param A Param B
1. VOLUME Volume (0-127) - (reserved)
2. WAVE/OCTAVE Wave Type Octave
3. FOOTAGE 16'/5 1/3' 16' Drawbar 5 1/3' Drawbar
4. FOOTAGE 8'/4' 8' Drawbar 4' Drawbar
5. FOOTAGE 2 2/3'/2' 2 2/3' Drawbar 2' Drawbar
6. FOOTAGE 1 3/5'/1 1/3' 1 3/5' Drawbar 1 1/3' Drawbar
7. FOOTAGE 1' 1' Drawbar - (reserved)
8. PERCUSSION Type Length
9. VIBRATO/CHORUS Select Depth
10. ROTARY Speed -
11. EFFECT Distortion Reverb

Note: On the PERCUSSION page, ParamA short-press toggles Percussion On/Off.

MIDI

PicoFaceYC uses USB-MIDI via TinyUSB (no DIN-Port).

  • Note Handling: Note On/Off with Octave Transpose. Sustain (CC64) is always active. RX channel filter uses Omni as default.
  • Panel CCs: Gated panel CCs (Wave/Footage x9/Percussion x3/Vibrato-Chorus x2/Rotary/Distortion/Reverb) are only processed when MIDI Control is active.
  • Panel Mirroring: Encoder changes on the panel are transmitted as outgoing MIDI-CC.
  • SysEx: Supports Parameter Change (Set) and Parameter Request (Reply) for all Tone Generator addresses, as well as Identity Reply.
  • Program Change: NOT supported (YC does not support it according to the official MIDI Implementation Chart).
  • Limitations: The Model-ID byte for SysEx is an unverified placeholder (see doc/MIDI_IMPLEMENTATION.md). The full Bulk-Dump block (with checksum) is not yet implemented (TODO).

Persistence

PicoFaceYC uses a Virtual EEPROM mechanism (wear-leveled Flash append log, reused from PicoFaceDX) to store yc_panel_state_t. This includes Wave, Octave, 9 Footages, Percussion, Vibrato/Chorus, Rotary Speed, Distortion, Reverb, Volume, and MIDI-Control-Mode. Autosave triggers 2s after the last change, with a 250ms polling interval.

Presets

None. The reface YC has no Program Change or a preset bank according to the official MIDI Implementation Chart. The complete panel state is directly SysEx-addressable.

Effects

PicoFaceYC uses a fixed effect chain (no slot system like PicoFaceDX):

  1. Percussion: Monophonic, single-trigger, 2nd/3rd harmonic. Attack/Decay controlled via Length.
  2. Vibrato/Chorus: Modulated delay-line.
  3. Overdrive: 1024-point LUT with tanh curve.
  4. Rotary Speaker: Algorithmic Horn/Drum model with crossover filter and physical speed ramps between OFF/STOP/SLOW/FAST.
  5. Reverb: Schroeder type (4 Comb + 2 Allpass).
  6. Soft-Clip Limiter: Final safety stage.

Design notes

  • DSP Style: Header-only DSP implementation in include/yc_engine/ with no dynamic allocation.
  • RAM_HOT(): The RAM_HOT() macro (effects/ram_hot.h, unchanged from DX) places audio hot-path data in RAM.
  • Soft-Clip Limiter: A single yc_soft_clip() stage applied as the final DSP step inside yc_engine_render_block (the redundant firmware-side softClipSample in main.cpp was removed in §29); the I2S path does a direct *32767 cast plus hard clamp.
  • Lookup Tables in Flash (active wave mirrored to RAM): The wavetable/sine/overdrive/footage-gain LUTs are inline const float[] in include/yc_engine/yc_lut_data.h (.rodata/XIP flash). The active wave table is copied into an 8 KB RAM buffer yc_wavetable_ram (yc_wavetable_select, §33) so the voice-render inner loop reads RAM, not flash — the RP2350 XIP cache is only 16 KB. Regenerate the flash tables with tools/gen_luts.cpp (host g++).
  • Testing: test/yc_engine_host_test.cpp provides a host test driver that can be compiled with a standard g++ without the Pico-SDK.
  • Hardware Watchdog: A 4 s hardware watchdog (kicked from the audio IRQ, §40) reboots the chip if Core 0 stalls (HardFault/deadlock). A watchdog-reboot counter WDR: N is shown on the System → CPU Load screen (§41) to diagnose freezes: rising WDR = Core 0 stall (self-recovered); frozen with WDR = 0 = Core 1/USB stall.

Acknowledgements

The tone generation concepts (Tonewheel/Drawbar model, Percussion, Vibrato/Chorus scanner, Rotary Speaker principle) were derived from the DSP concepts of setBfree/BeatrixCPP (tools/OpenB3/) and reimplemented for the RP2350 header-only architecture. Code for the YC port was developed with an LLM-assisted workflow: architecture and review by the maintainer, code generation via glm-5.2, matching existing project conventions (exactly like the DX port).

License

GPLv3 - see LICENSE.

About

Yamaha Reface YC Emulation on RP2350

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages