nimphea/boards/daisy_versio

Search:
Group by:
Source   Edit  

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
Source   Edit  
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
Source   Edit  
proc delayMs(this: var DaisyVersio; del: csize_t) {.importcpp: "#.DelayMs(#)",
    ...raises: [], tags: [], forbids: [].}

Delay execution for specified milliseconds

Parameters:

  • del - Delay time in milliseconds
Source   Edit  
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