amy icon indicating copy to clipboard operation
amy copied to clipboard

Combine `amy_live_start()` into `amy_start()`; add `hardware` bitfield to `amy_config`

Open dpwe opened this issue 3 weeks ago • 0 comments

(This is a spin-off of #489)

Currently, AMY Arduino initialization goes like:

void setup() {
  amy_config_t config;
  // Setup config flags
  ...
  // Initialize the AMY engine.
  amy_start(&config);
  // Initialize the I2S hardware
  amy_live_start();
}

void loop() {
  // Process the next block of samples in the AMY engine and pass to I2S
  amy_update();
  ...
}

I'm pointing specifically to the amy_start(&config); amy_live_start() sequence to start things up. (Note, there's a different amy_live_start() defined in libminiaudio-audio.c that starts the miniaudio background thread.)

amy_live_start() is separate from amy_start() I think for compatibility with the AMY Python library: That library is initialized (via amy_start()) at load-time, before we can indicate which audio interface to use. So we load the library, then call amy.live(playback_device, capture_device) from our Python code to select which output and input devices to use (for the Python library, this is indicating libminiaudio system devices).

Instead, we could have amy_start() do everything at load time (including treating the unselected devices as "no input/output"), then allow reinitialization of AMY (via another call to amy_start(), or via an amy_restart() function) that now provides the devices. (This was a motivation behind #364, which got in the way of re-initializing.)

There are actually multiple hardware-specific functions that should be handled in a neatly-abstracted way:

  • I2S input/output
  • MIDI UART input/output
  • Using a 2nd core
  • Using multithreading (e.g., RTOS)

Currently these are handled "smartly", e.g. rendering on the RP2040 always uses processes running on both cores. But I'd like to give the user the opportunity to control these (e.g. if for some reason the 2nd core is already committed elsewhere). So I'd like some new flags in amy_config_t, e.g. a set of hardware bits, simply to indicate whether I2S and UART I/O are requested, whether to try to use all the available cores, and whether to use multithreading when available.

Currently, we have the config.audio, which, somewhat redundantly, is set to AMY_AUDIO_IS_I2S on MCUs and AMY_AUDIO_IS_MINIAUDIO on linux/web. I don't think it's ever inspected, although it could be set to AMY_AUDIO_IS_NONE to prevent audio IO in all cases. Then, we have additional flags like config.features.audio_in to indicate that you want audio input alongside your audio output, and config.i2s_dout(etc.) to indicate the actual pins used for the various I2S functions.

I think we should permit c.audio = AMY_AUDIO_IS_NONE to defeat built-in audio output (via I2S or libminiaudio, depending on the platform. We also need it to select USB output on MCUs (AMY_IS_USB_GADGET).

So I propose:

typedef structure amy_config {
  struct {
    uint8_t i2s : 1;
    uint8_t uart : 1;
    uint8_t multicore: 1;
    uint8_t multithread: 1;
  } hardware;
  ...
}

Each feature is initialized only if the corresponding hardware bit is set. Then, I2S input is configured only if config.i2s_din is set, etc.

dpwe avatar Dec 28 '25 21:12 dpwe