Nimphea - Nim wrapper for the Daisy Audio Platform Hardware Abstraction Library
This module provides Nim bindings to the Daisy Audio Platform (via libDaisy C++ library) by Electro-Smith. It enables easy access to audio, controls, GPIO, MIDI, USB, and more.
Basic Example:
import nimphea useNimpheaNamespace() # Required: sets up C++ interop proc main() = var daisy = initDaisy() daisy.setLed(true) daisy.delay(500) daisy.setLed(false) when isMainModule: main()
Audio Example:
import nimphea useNimpheaNamespace() # Required: sets up C++ interop proc audioCallback(input, output: AudioBuffer, size: int) {.cdecl.} = for i in 0..<size: output[0][i] = input[0][i] # Left channel passthrough output[1][i] = input[1][i] # Right channel passthrough proc main() = var daisy = initDaisy() daisy.startAudio(audioCallback) while true: discard when isMainModule: main()
Note: The useNimpheaNamespace() macro automatically generates all necessary C++ interop code at compile time. You just need to call it once after your imports!
Types
AudioBuffer = ptr UncheckedArray[ptr UncheckedArray[cfloat]]
- Multi-channel audio buffer (non-interleaved) Source Edit
AudioCallback = proc (input, output: AudioBuffer; size: int) {.cdecl, ...raises: [].}
- Nim-friendly multi-channel audio callback Source Edit
AudioCallbackC = proc (input: ConstFloatPtrPtr; output: FloatPtrPtr; size: csize_t) {.cdecl.}
- Source Edit
AudioConfig {.importcpp: "daisy::AudioHandle::Config", bycopy.} = object blocksize* {.importc: "blocksize".}: csize_t samplerate* {.importc: "samplerate".}: SampleRate postgain* {.importc: "postgain".}: cfloat output_compensation* {.importc: "output_compensation".}: cfloat
- Source Edit
AudioHandle {.importcpp: "daisy::AudioHandle".} = object
- Source Edit
AudioResult {.importcpp: "daisy::AudioHandle::Result", size: 4.} = enum AUDIO_OK = 0, AUDIO_ERR
- Source Edit
BoardVersion {.importcpp: "daisy::DaisySeed::BoardVersion", size: 4.} = enum BOARD_DAISY_SEED = 0, BOARD_DAISY_SEED_1_1, BOARD_DAISY_SEED_2_DFM
- Source Edit
ConstFloatPtr = ptr cfloat
- Source Edit
ConstFloatPtrPtr = ptr ptr cfloat
- Source Edit
DaisySeed {.importcpp: "daisy::DaisySeed".} = object qspi* {.importc: "qspi".}: QSPIHandle qspi_config* {.importc: "qspi_config".}: QSPIConfig sdram_handle* {.importc: "sdram_handle".}: SdramHandle audio_handle* {.importc: "audio_handle".}: AudioHandle adc* {.importc: "adc".}: AdcHandle dac* {.importc: "dac".}: DacHandle usb_handle* {.importc: "usb_handle".}: UsbHandle led* {.importc: "led".}: GPIO testpoint* {.importc: "testpoint".}: GPIO system* {.importc: "system".}: System codec* {.importc: "codec".}: Ak4556
- Source Edit
FloatPtrPtr = ptr ptr cfloat
- Source Edit
GPIOMode {.importcpp: "daisy::GPIO::Mode", size: 4.} = enum INPUT = 0, OUTPUT, OPEN_DRAIN, ANALOG
- Source Edit
GPIOPort {.importcpp: "daisy::GPIOPort", size: 4.} = enum PORTA = 0, PORTB, PORTC, PORTD, PORTE, PORTF, PORTG, PORTH, PORTI, PORTJ, PORTK, PORTX
- Source Edit
GPIOPull {.importcpp: "daisy::GPIO::Pull", size: 4.} = enum NOPULL = 0, PULLUP, PULLDOWN
- Source Edit
GPIOSpeed {.importcpp: "daisy::GPIO::Speed", size: 4.} = enum LOW = 0, MEDIUM, HIGH, VERY_HIGH
- Source Edit
InterleavedAudioBuffer = ptr UncheckedArray[cfloat]
- Interleaved audio buffer Source Edit
InterleavingAudioCallback = proc (input, output: InterleavedAudioBuffer; size: int) {.cdecl, ...raises: [].}
- Nim-friendly interleaved audio callback Source Edit
InterleavingAudioCallbackC = proc (input: ConstFloatPtr; output: FloatPtr; size: csize_t) {.cdecl.}
- Source Edit
Pin {.importcpp: "daisy::Pin".} = object port* {.importc: "port".}: GPIOPort pin* {.importc: "pin".}: uint8
- Source Edit
QSPIConfig {.importcpp: "daisy::QSPIHandle::Config", bycopy.} = object device* {.importc: "device".}: QSPIDevice mode* {.importc: "mode".}: QSPIMode
- Source Edit
QSPIDevice {.importcpp: "daisy::QSPIHandle::Config::Device", size: 4.} = enum IS25LP080D = 0, ## 8 Mbit (1 MB) IS25LP064A = 1 ## 64 Mbit (8 MB)
- Source Edit
QSPIHandle {.importcpp: "daisy::QSPIHandle".} = object
- Source Edit
QSPIMode {.importcpp: "daisy::QSPIHandle::Config::Mode", size: 4.} = enum MEMORY_MAPPED = 0, ## Read-only memory-mapped access INDIRECT_POLLING = 1 ## Full read/write/erase access
- Source Edit
SampleRate {.importcpp: "daisy::SaiHandle::Config::SampleRate", size: 4.} = enum SAI_8KHZ = 0, SAI_16KHZ, SAI_32KHZ, SAI_48KHZ, SAI_96KHZ
- Source Edit
SdramHandle {.importcpp: "daisy::SdramHandle".} = object
- Source Edit
Procs
proc audioSaiHandle(daisy: DaisySeed): SaiHandle {....raises: [], tags: [], forbids: [].}
-
Get the SAI handle for the Daisy Seed audio interface.
This can be useful when adding a secondary codec - the result of this function can be passed to AudioHandle.init() with an SAI2 configuration.
Source Edit proc boardVersion(daisy: var DaisySeed): BoardVersion {....raises: [], tags: [], forbids: [].}
- Check which version of Daisy Seed board is connected Source Edit
proc callbackRate(daisy: DaisySeed): float {....raises: [], tags: [], forbids: [].}
- Source Edit
proc changeAudioCallback(daisy: var DaisySeed; callback: AudioCallback) {. ...raises: [], tags: [], forbids: [].}
- Change the audio callback while audio is running Source Edit
proc changeAudioCallback(daisy: var DaisySeed; callback: InterleavingAudioCallback) {....raises: [], tags: [], forbids: [].}
- Change the interleaved audio callback while audio is running Source Edit
proc deinit(audio: var AudioHandle): AudioResult {....raises: [], tags: [], forbids: [].}
- Stop and deinitialize audio. Source Edit
proc floatToS16(x: float32): int16 {.inline, ...raises: [], tags: [], forbids: [].}
- Converts float to signed 16-bit Source Edit
proc floatToS24(x: float32): int32 {.inline, ...raises: [], tags: [], forbids: [].}
- Converts float to signed 24-bit Source Edit
proc getChannels(audio: AudioHandle): int {....raises: [], tags: [], forbids: [].}
-
Get the number of audio channels.
Returns 2 when using a single SAI, 4 when using two SAI, 0 if not initialized.
Source Edit proc getConfig(audio: AudioHandle): AudioConfig {....raises: [], tags: [], forbids: [].}
- Get the current AudioHandle configuration. Source Edit
proc getSampleRate(audio: var AudioHandle): float {....raises: [], tags: [], forbids: [].}
- Source Edit
proc init(audio: var AudioHandle; config: AudioConfig; sai1, sai2: SaiHandle): AudioResult {. ...raises: [], tags: [], forbids: [].}
-
Initialize AudioHandle with two SAI, each configured in stereo I2S mode.
This is an advanced API - most users should use DaisySeed's built-in audio methods.
Source Edit proc init(audio: var AudioHandle; config: AudioConfig; sai: SaiHandle): AudioResult {. ...raises: [], tags: [], forbids: [].}
-
Initialize AudioHandle with a single SAI configured in stereo I2S mode.
This is an advanced API - most users should use DaisySeed's built-in audio methods.
Source Edit proc initGpio(pin: Pin; mode: GPIOMode = OUTPUT; pull: GPIOPull = NOPULL; speed: GPIOSpeed = LOW): GPIO {....raises: [], tags: [], forbids: [].}
-
Initialize a GPIO pin
Parameters: pin: The pin to configure (use D0(), D1(), A0(), etc.) mode: INPUT, OUTPUT, OPEN_DRAIN, or ANALOG pull: NOPULL, PULLUP, or PULLDOWN speed: LOW, MEDIUM, HIGH, or VERY_HIGH
Example:
var led = initGpio(D7(), OUTPUT) led.write(true)
Source Edit proc printLine(f: float) {.inline, ...raises: [], tags: [], forbids: [].}
- Print a float with newline. Source Edit
proc s16ToFloat(x: int16): float32 {.inline, ...raises: [], tags: [], forbids: [].}
- Converts signed 16-bit to float Source Edit
proc s24ToFloat(x: int32): float32 {.inline, ...raises: [], tags: [], forbids: [].}
- Converts signed 24-bit to float Source Edit
proc sampleRate(daisy: var DaisySeed): float {....raises: [], tags: [], forbids: [].}
- Source Edit
proc setBlockSize(audio: var AudioHandle; size: int): AudioResult {....raises: [], tags: [], forbids: [].}
- Set the block size after initialization. Source Edit
proc setBlockSize(daisy: var DaisySeed; size: int) {....raises: [], tags: [], forbids: [].}
- Set the audio block size (number of samples per callback) Source Edit
proc setOutputCompensation(audio: var AudioHandle; compensation: float): AudioResult {. ...raises: [], tags: [], forbids: [].}
-
Set an additional amount of gain compensation at the end of the callback.
Useful if the hardware input/output levels are not equal.
To calculate the value:
- Measure the input signal level (vin)
- Measure the output signal level with compensation set to 1.0 (vout)
- Calculate: compensation = 1.0 / (vout / vin)
Parameters: compensation: Output compensation factor
Source Edit proc setOutputCompensation(daisy: var DaisySeed; compensation: float): AudioResult {. ...raises: [], tags: [], forbids: [].}
- Convenience wrapper to set output compensation on the DaisySeed's audio handle. Source Edit
proc setPostGain(audio: var AudioHandle; gain: float): AudioResult {....raises: [], tags: [], forbids: [].}
-
Set the amount of gain adjustment to perform before and after callback.
Useful if the hardware has additional headroom and the nominal value shouldn't be 1.0. The hardware will clip at the reciprocal of this value.
Parameters: gain: Gain adjustment amount
Example:
daisy.audio_handle.setPostGain(0.5) # Allow signals up to 2.0 without clipping
Source Edit proc setPostGain(daisy: var DaisySeed; gain: float): AudioResult {....raises: [], tags: [], forbids: [].}
- Convenience wrapper to set post-gain on the DaisySeed's audio handle. Source Edit
proc setSampleRate(audio: var AudioHandle; samplerate: SampleRate): AudioResult {. ...raises: [], tags: [], forbids: [].}
- Set the sample rate and reinitialize the SAI as needed. Source Edit
proc setSampleRate(daisy: var DaisySeed; rate: SampleRate) {....raises: [], tags: [], forbids: [].}
-
Set the audio sample rate
Available rates: SAI_8KHZ, SAI_16KHZ, SAI_32KHZ, SAI_48KHZ, SAI_96KHZ
Source Edit proc setTestPoint(daisy: var DaisySeed; state: bool) {....raises: [], tags: [], forbids: [].}
- Set the test point pin state (for oscilloscope debugging) Source Edit
proc startAudio(daisy: var DaisySeed; callback: AudioCallback) {....raises: [], tags: [], forbids: [].}
-
Start audio processing with a multi-channel (non-interleaved) callback
The callback receives separate channels as arrays of float samples.
Example:
proc audioCallback(input, output: AudioBuffer, size: int) {.cdecl.} = for i in 0..<size: output[0][i] = input[0][i] * 0.5 # Left channel, reduce volume output[1][i] = input[1][i] * 0.5 # Right channel daisy.startAudio(audioCallback)
Source Edit proc startAudio(daisy: var DaisySeed; callback: InterleavingAudioCallback) {. ...raises: [], tags: [], forbids: [].}
-
Start audio processing with an interleaved callback
The callback receives interleaved samples (L, R, L, R, ...)
Source Edit