nimphea_versio
Nim wrapper for Electro-Smith Daisy Versio (Noise Engineering) development board.
The Daisy Versio is a compact Eurorack DSP module featuring:
- 7 knobs/CV inputs (0-5V)
- 2 three-position switches
- 1 momentary tap switch
- 1 gate input
- 4 RGB LEDs (PWM controlled)
- Audio I/O (stereo, Eurorack level)
- USB for programming/power
Hardware Overview:
- Based on Daisy Seed (STM32H750, 480MHz ARM Cortex-M7)
- Compact Eurorack form factor (10HP)
- Perfect for effects, delays, reverbs, filters
Example - Simple LED control:
import nimphea/boards/daisy_versio var versio: DaisyVersio versio.init() versio.startAdc() while true: versio.processAllControls() # Knobs control LED colors let red = versio.getKnobValue(KNOB_0.cint) let green = versio.getKnobValue(KNOB_1.cint) let blue = versio.getKnobValue(KNOB_2.cint) versio.setLed(LED_0.cint, red, green, blue) versio.updateLeds() versio.delayMs(10)
Example - Audio processing:
proc audioCallback(input: ptr float32, output: ptr float32, size: csize_t) {.cdecl.} = for i in 0..<size: var sample: cfloat {.emit: "`sample` = `input`[`i`];".} # Process audio sample = sample * 0.5 {.emit: "`output`[`i`] = `sample`;".} versio.startAudio(audioCallback)
Types
AnalogControl {.importcpp: "daisy::AnalogControl", header: "hid/ctrl.h".} = object
- Analog control (knob/CV input) wrapper Source Edit
DaisyVersio {.importcpp: "daisy::DaisyVersio".} = object seed*: DaisySeed ## Underlying Seed board leds*: array[4, RgbLed] ## 4 RGB LEDs (PWM controlled) knobs*: array[7, AnalogControl] ## 7 knobs/CV inputs tap*: switch.Switch ## Momentary tap switch gate*: GateIn ## Gate input sw*: array[2, Switch3] ## 2 three-position switches
-
Daisy Versio board handle
Contains all hardware peripherals pre-configured for the Versio platform.
Source Edit Switch3 {.importcpp: "daisy::Switch3", header: "hid/switch3.h".} = object
- Three-position switch Source Edit
VersioKnob {.importcpp: "daisy::DaisyVersio::AV_KNOBS", size: 4.} = enum KNOB_0 = 0, ## Knob 0 (leftmost) KNOB_1 = 1, ## Knob 1 KNOB_2 = 2, ## Knob 2 KNOB_3 = 3, ## Knob 3 KNOB_4 = 4, ## Knob 4 KNOB_5 = 5, ## Knob 5 KNOB_6 = 6 ## Knob 6 (rightmost)
-
Knob/CV input identifiers
7 knobs with CV inputs (0-5V)
Source Edit VersioLed {.importcpp: "daisy::DaisyVersio::AV_LEDS", size: 4.} = enum LED_0 = 0, ## LED 0 (top-left) LED_1 = 1, ## LED 1 (top-right) LED_2 = 2, ## LED 2 (bottom-left) LED_3 = 3 ## LED 3 (bottom-right)
-
RGB LED identifiers
4 RGB LEDs arranged on the panel
Source Edit VersioSwitch {.importcpp: "daisy::DaisyVersio::AV_TOGGLE3", size: 4.} = enum SW_0 = 0, ## Switch 0 (left) SW_1 = 1 ## Switch 1 (right)
-
Three-position switch identifiers
2 three-position switches (up/center/down)
Source Edit
Procs
proc audioBlockSize(this: var DaisyVersio): csize_t {. importcpp: "#.AudioBlockSize()", ...raises: [], tags: [], forbids: [].}
-
Get current audio block size
Returns: Samples per channel per callback
Source Edit proc audioCallbackRate(this: var DaisyVersio): cfloat {. importcpp: "#.AudioCallbackRate()", ...raises: [], tags: [], forbids: [].}
-
Get audio callback rate in Hz
Returns: Callback frequency (sampleRate / blockSize)
Source Edit proc audioSampleRate(this: var DaisyVersio): cfloat {. importcpp: "#.AudioSampleRate()", ...raises: [], tags: [], forbids: [].}
-
Get current audio sample rate in Hz
Returns: Sample rate as floating point (e.g., 48000.0)
Source Edit proc changeAudioCallback(this: var DaisyVersio; callback: AudioCallback) {. ...raises: [], tags: [], forbids: [].}
-
Change audio callback function while audio is running
Parameters:
- callback - New callback function
proc changeAudioCallback(this: var DaisyVersio; callback: InterleavingAudioCallback) {....raises: [], tags: [], forbids: [].}
-
Change audio callback function while audio is running (interleaved version)
Parameters:
- callback - New interleaved callback function
proc delayMs(this: var DaisyVersio; del: csize_t) {.importcpp: "#.DelayMs(#)", ...raises: [], tags: [], forbids: [].}
-
Delay execution for specified milliseconds
Parameters:
- del - Delay time in milliseconds
proc gate(this: var DaisyVersio): bool {.importcpp: "#.Gate()", ...raises: [], tags: [], forbids: [].}
-
Check if gate input is high
Returns: True if gate input is HIGH
Example:
if versio.gate(): # Gate is active discard
Source Edit proc getKnobValue(this: var DaisyVersio; idx: cint): cfloat {. importcpp: "#.GetKnobValue(#)", ...raises: [], tags: [], forbids: [].}
-
Get knob value as normalized float
Parameters:
- idx - Knob index (cast VersioKnob to cint: KNOB_0.cint)
Returns: Normalized value from 0.0 to 1.0
Example:
let freq = versio.getKnobValue(KNOB_0.cint) * 1000.0 # 0-1000 Hz
Note: Call processAnalogControls() regularly for accurate readings.
Source Edit proc init(this: var DaisyVersio; boost: bool = false) {.importcpp: "#.Init(#)", ...raises: [], tags: [], forbids: [].}
-
Initialize the Daisy Versio board
Configures all hardware peripherals:
- Audio codec (PCM3060, 24-bit/48kHz)
- ADC for knobs/CV inputs
- Switches (momentary and 3-position)
- Gate input
- RGB LEDs (PWM)
Parameters:
- boost - Enable CPU boost mode (480MHz, default is 400MHz)
Note: Audio and ADC must be started separately with startAudio() and startAdc().
Source Edit proc processAllControls(this: var DaisyVersio) {. importcpp: "#.ProcessAllControls()", ...raises: [], tags: [], forbids: [].}
-
Process all control inputs (analog controls only for Versio)
Convenience method. Equivalent to:
versio.processAnalogControls()
Note: Digital controls (switches, gate) are updated automatically.
Source Edit proc processAnalogControls(this: var DaisyVersio) {. importcpp: "#.ProcessAnalogControls()", ...raises: [], tags: [], forbids: [].}
-
Process analog control inputs (knobs/CV)
Updates internal state of all knobs. Call regularly in main loop (e.g., every 1ms) for stable readings.
Example:
while true: versio.processAnalogControls() let knob0 = versio.getKnobValue(KNOB_0.cint) versio.delayMs(1)
Source Edit proc read(sw: var Switch3): cint {.importcpp: "#.Read()", header: "hid/switch3.h", ...raises: [], tags: [], forbids: [].}
-
Read three-position switch state
Returns:
- 0 = Down position
- 1 = Center position
- 2 = Up position
Example:
let sw0State = versio.sw[SW_0.int].read() if sw0State == 2: echo "Switch 0 is in UP position"
Source Edit proc setAudioBlockSize(this: var DaisyVersio; size: csize_t) {. importcpp: "#.SetAudioBlockSize(#)", ...raises: [], tags: [], forbids: [].}
-
Set audio block size (samples per channel per callback)
Parameters:
- size - Block size in samples (default: 48)
Note: Audio must be stopped before changing block size.
Source Edit proc setAudioSampleRate(this: var DaisyVersio; samplerate: SampleRate) {. importcpp: "#.SetAudioSampleRate(#)", ...raises: [], tags: [], forbids: [].}
-
Set audio sample rate
Parameters:
- samplerate - Desired sample rate (e.g., SAI_48KHZ, SAI_96KHZ)
Note: Audio must be stopped before changing sample rate.
Source Edit proc setLed(this: var DaisyVersio; idx: csize_t; red: cfloat; green: cfloat; blue: cfloat) {.importcpp: "#.SetLed(#, #, #, #)", ...raises: [], tags: [], forbids: [].}
-
Set RGB LED color
Parameters:
- idx - LED index (cast VersioLed to csize_t: LED_0.csize_t)
- red - Red component (0.0 to 1.0)
- green - Green component (0.0 to 1.0)
- blue - Blue component (0.0 to 1.0)
Note: Must call updateLeds() to apply changes.
Example:
# Set LED 0 to purple versio.setLed(LED_0.csize_t, 1.0, 0.0, 1.0) # Set LED 1 to white at 50% brightness versio.setLed(LED_1.csize_t, 0.5, 0.5, 0.5) versio.updateLeds() # Apply changes
Source Edit proc startAdc(this: var DaisyVersio) {.importcpp: "#.StartAdc()", ...raises: [], tags: [], forbids: [].}
-
Start analog-to-digital conversion for knobs/CV inputs
Note: Must be called before reading knob values.
Source Edit proc startAudio(this: var DaisyVersio; callback: AudioCallback) {....raises: [], tags: [], forbids: [].}
-
Start audio processing with multichannel callback
Parameters:
- callback - Function called at audio rate for processing
Callback signature:
proc(input: ptr ptr float32, output: ptr ptr float32, size: csize_t)
Example:
proc myCallback(input: ptr ptr float32, output: ptr ptr float32, size: csize_t) {.cdecl.} = for i in 0..<size: var inL, inR, outL, outR: cfloat {.emit: "`inL` = `input`[0][`i`];".} {.emit: "`inR` = `input`[1][`i`];".} outL = inL * 0.5 outR = inR * 0.5 {.emit: "`output`[0][`i`] = `outL`;".} {.emit: "`output`[1][`i`] = `outR`;".} versio.startAudio(myCallback)
Source Edit proc startAudio(this: var DaisyVersio; callback: InterleavingAudioCallback) {. ...raises: [], tags: [], forbids: [].}
-
Start audio processing with interleaved callback
Parameters:
- callback - Function called at audio rate for processing
Callback signature:
proc(input: ptr float32, output: ptr float32, size: csize_t)
Note: Size is total samples (stereo = size/2 frames)
Source Edit proc stopAdc(this: var DaisyVersio) {.importcpp: "#.StopAdc()", ...raises: [], tags: [], forbids: [].}
- Stop analog-to-digital conversion Source Edit
proc stopAudio(this: var DaisyVersio) {.importcpp: "#.StopAudio()", ...raises: [], tags: [], forbids: [].}
-
Stop audio processing
Stops the audio callback from being called.
Source Edit proc switchPressed(this: var DaisyVersio): bool {. importcpp: "#.SwitchPressed()", ...raises: [], tags: [], forbids: [].}
-
Check if momentary tap switch is pressed
Returns: True if tap switch is pressed
Example:
if versio.switchPressed(): # Tap switch is pressed discard
Source Edit proc updateLeds(this: var DaisyVersio) {.importcpp: "#.UpdateLeds()", ...raises: [], tags: [], forbids: [].}
-
Update LED hardware to reflect current LED states
Must be called after setLed() to actually change the physical LEDs.
Example:
versio.setLed(LED_0.csize_t, 1.0, 0.0, 0.0) # Set to red versio.updateLeds() # Apply the change
Source Edit
Exports
-
pressed, Init, init, FallingEdge, SwitchType, GpioPull, Debounce, rawState, Switch, RawState, Init, debounce, RisingEdge, risingEdge, Pressed, timeHeldMs, init, TimeHeldMs, SwitchPolarity, fallingEdge, trig, init, state, GateIn