Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions examples/AMY_Spresense_Test/AMY_Spresense_Test.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#include <AMY-Arduino.h>

// AMY_Spresense_Analog
//
// Minimal AMY example for Sony Spresense analog output.
// Spresense backend in src/spresense_support.cpp handles DAC output.

void setup() {
#ifdef LED_BUILTIN
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
#endif

Serial.begin(115200);
delay(1000);
Serial.println("AMY Spresense analog output");

amy_config_t amy_config = amy_default_config();
amy_config.features.startup_bleep = 1;
amy_config.features.default_synths = 1;

// Default synth set may require around 90+ oscillators; keep headroom.
amy_config.max_oscs = 128;

// Use Spresense platform audio path (analog DAC output backend).
// To use I2S output instead, uncomment the next line.
// amy_config.spresense_output_device = SPRESENSE_OUTPUT_I2S;
amy_config.audio = AMY_AUDIO_IS_SPRESENSE;
amy_config.midi = AMY_MIDI_IS_NONE;

amy_start(amy_config);

}

void loop() {
amy_update();

static uint32_t last_ms = 0;
uint32_t now = millis();
if (now - last_ms > 600) {
last_ms = now;
static int root = 60;
static bool play_chord = false;
uint32_t t = amy_sysclock();

if (!play_chord) {
Serial.print("single note ");
Serial.print(root);
Serial.print(" at ");
Serial.println(t);

amy_event on = amy_default_event();
on.time = t;
on.synth = 1;
on.midi_note = root;
on.velocity = 0.8f;
amy_add_event(&on);

amy_event off = amy_default_event();
off.time = t + 220;
off.synth = 1;
off.midi_note = root;
off.velocity = 0.0f;
amy_add_event(&off);
} else {
const int chord[3] = {root, root + 4, root + 7};
Serial.print("chord ");
Serial.print(chord[0]);
Serial.print(",");
Serial.print(chord[1]);
Serial.print(",");
Serial.print(chord[2]);
Serial.print(" at ");
Serial.println(t);

for (int i = 0; i < 3; ++i) {
amy_event on = amy_default_event();
on.time = t;
on.synth = 1;
on.midi_note = chord[i];
on.velocity = 0.7f;
amy_add_event(&on);

amy_event off = amy_default_event();
off.time = t + 220;
off.synth = 1;
off.midi_note = chord[i];
off.velocity = 0.0f;
amy_add_event(&off);
}
}

play_chord = !play_chord;
root += 2;
if (root > 72) {
root = 60;
}
}
}
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ sentence=AMY, the Music Synthesizer Library
paragraph=AMY supports many types of oscillators, filters, envelopes, analog, FM, PCM, Karplus-strong, reverb, chorus, echo
category=Signal Input/Output
url=http://github.com/shorepine/amy
architectures=esp32,stm32,rp2040,mbed_rp2040,rp2350,mbed_rp2350,teensy,STM32F1,STM32F4,STM32H7,nrf52,samd,avr
architectures=esp32,stm32,rp2040,mbed_rp2040,rp2350,mbed_rp2350,teensy,STM32F1,STM32F4,STM32H7,nrf52,samd,avr,spresense
includes=AMY-Arduino.h
depends=
3 changes: 3 additions & 0 deletions src/amy.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ uint64_t profile_start_us = 0;
int64_t amy_get_us() { return esp_timer_get_time(); }
#elif defined PICO_ON_DEVICE
int64_t amy_get_us() { return to_us_since_boot(get_absolute_time()); }
#elif defined(ARDUINO_ARCH_SPRESENSE)
extern unsigned long micros(void);
int64_t amy_get_us() { return (int64_t)micros(); }
#elif defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
Expand Down
18 changes: 17 additions & 1 deletion src/amy.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ extern const uint32_t pcm_wavetable_len;

#ifdef AMY_DAISY
#define AMY_SAMPLE_RATE 48000
#elif defined(ARDUINO_ARCH_SPRESENSE)
#define AMY_SAMPLE_RATE 48000
#elif defined __EMSCRIPTEN__
#define AMY_SAMPLE_RATE 48000
#else
Expand Down Expand Up @@ -121,6 +123,8 @@ extern const uint32_t pcm_wavetable_len;
#define AMY_HAS_REVERB (amy_global.config.features.reverb)
#define AMY_HAS_AUDIO_IN (amy_global.config.features.audio_in)
#define AMY_HAS_I2S (amy_global.config.audio == AMY_AUDIO_IS_I2S)
#define AMY_HAS_SPRESENSE_AUDIO (amy_global.config.audio == AMY_AUDIO_IS_SPRESENSE)
#define AMY_HAS_PLATFORM_AUDIO_OUT (AMY_HAS_I2S || AMY_HAS_SPRESENSE_AUDIO)
#define AMY_HAS_DEFAULT_SYNTHS (amy_global.config.features.default_synths)
#define AMY_HAS_CHORUS (amy_global.config.features.chorus)
#define AMY_HAS_ECHO (amy_global.config.features.echo)
Expand Down Expand Up @@ -313,7 +317,7 @@ typedef int amy_err_t;

#include "amy_fixedpoint.h"

#if defined ARDUINO && !defined TLONG && !defined ESP_PLATFORM
#if defined ARDUINO && !defined TLONG && !defined ESP_PLATFORM && !defined(ARDUINO_ARCH_SPRESENSE)
#include "avr/pgmspace.h" // for PROGMEM, DMAMEM, FASTRUN
#else
#define PROGMEM
Expand Down Expand Up @@ -634,6 +638,13 @@ typedef struct delay_line {
#define AMY_AUDIO_IS_I2S 0x01
#define AMY_AUDIO_IS_USB_GADGET 0x02
#define AMY_AUDIO_IS_MINIAUDIO 0x04
#define AMY_AUDIO_IS_SPRESENSE 0x08

#if defined(ARDUINO_ARCH_SPRESENSE)
// Spresense audio output device selection
#define SPRESENSE_OUTPUT_ANALOG 0
#define SPRESENSE_OUTPUT_I2S 1
#endif

#define AMY_MIDI_IS_NONE 0x0
#define AMY_MIDI_IS_UART 0x01
Expand Down Expand Up @@ -721,6 +732,11 @@ typedef struct {
int8_t capture_device_id;
int8_t playback_device_id;

#if defined(ARDUINO_ARCH_SPRESENSE)
// Spresense audio output device (SPRESENSE_OUTPUT_ANALOG or SPRESENSE_OUTPUT_I2S)
uint8_t spresense_output_device;
#endif

} amy_config_t;

typedef struct reverb_state {
Expand Down
8 changes: 8 additions & 0 deletions src/amy_midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,14 @@ void stop_midi() {
}
#endif

#if defined(ARDUINO_ARCH_SPRESENSE)
void run_midi() {
}

void stop_midi() {
}
#endif


#ifdef __linux__
void stop_midi() {
Expand Down
7 changes: 6 additions & 1 deletion src/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ amy_config_t amy_default_config() {
c.midi_uart = 1; // This is MIDI UART _number_, like index
#endif

#if defined(ARDUINO_ARCH_SPRESENSE)
c.audio = AMY_AUDIO_IS_SPRESENSE;
c.spresense_output_device = SPRESENSE_OUTPUT_ANALOG; // Default to analog DAC output
#endif

return c;
}

Expand Down Expand Up @@ -407,7 +412,7 @@ int16_t *amy_update() {
// Single function to update buffers.
amy_update_tasks();
int16_t *block = amy_render_audio();
if (AMY_HAS_I2S && !amy_global.i2s_is_in_background) {
if (AMY_HAS_PLATFORM_AUDIO_OUT && !amy_global.i2s_is_in_background) {
amy_i2s_write(
(uint8_t *)block, AMY_BLOCK_SIZE * AMY_NCHANS * sizeof(int16_t)
);
Expand Down
37 changes: 35 additions & 2 deletions src/i2s.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
// rp2350, rp2040
// teensy 3.6, 4.0, 4.1

// Only run this code on MCUs
#if defined(ESP_PLATFORM) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO) || defined(ARDUINO_ARCH_RP2350)
// Only run this code on MCU targets with platform backends in this file.
#if defined(ESP_PLATFORM) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RP2350) || defined(ARDUINO_ARCH_SPRESENSE)

#include "amy.h"

Expand Down Expand Up @@ -574,6 +574,39 @@ void amy_platform_deinit() {
}


#elif defined(ARDUINO_ARCH_SPRESENSE)

// Spresense analog output backend is implemented in C++.
extern void spresense_setup_audio(amy_config_t *config);
extern void spresense_teardown_audio(amy_config_t *config);
extern size_t spresense_audio_write(const uint8_t *buffer, size_t nbytes);

void amy_platform_init() {
if (AMY_HAS_SPRESENSE_AUDIO) {
spresense_setup_audio(&amy_global.config);
}
}

void amy_platform_deinit() {
if (AMY_HAS_SPRESENSE_AUDIO) {
spresense_teardown_audio(&amy_global.config);
}
}

void amy_update_tasks() {
amy_execute_deltas();
}

int16_t *amy_render_audio() {
amy_render(0, AMY_OSCS, 0);
return amy_fill_buffer();
}

size_t amy_i2s_write(const uint8_t *buffer, size_t nbytes) {
return spresense_audio_write(buffer, nbytes);
}


#elif defined __IMXRT1062__


Expand Down
Loading