Skip to content

Instantly share code, notes, and snippets.

@Visuelle-Musik
Created September 17, 2024 18:48
Show Gist options
  • Save Visuelle-Musik/8d70f4fd2505099fcbc94dbeb9a26107 to your computer and use it in GitHub Desktop.
Save Visuelle-Musik/8d70f4fd2505099fcbc94dbeb9a26107 to your computer and use it in GitHub Desktop.
// === AMY-Example: Setting up a patch for addtive synthesis, storing it, assigning it two two different voices and playing one note per voice ===
#include "AMY-Arduino.h"
AMY amy;
// --- I2S Driver ---
#include <ESP_I2S.h>
I2SClass I2S;
// --- Setup 4 voices with 24 partials each and default base-frequency and breakpoints... ---
void attach_partials_to_voices()
{
// --- Setup variables to generate an additive voice ---
char amy_command[MAX_MESSAGE_LEN];
char amy_partial_command[MAX_MESSAGE_LEN]; // Make sure that patchstring does not exceed bufferlength MAX_MESSAGE_LEN (currently 25
int num_partials = 24; // max. num of osc ( AMY_OSCS in amy_config.h) is 120! For four voices we use up 96 with this config!
float base_freq = 261.63;
int base_osc = 0;
struct event e = amy.default_event();
// --- Generate a patch to be stored for our additive voice[s] ---
strcpy(amy_command, "1024,"); // Patch-number as a kind of header to our patch-string, numbers 1024-1055 can be used for user-patches
for(int i=1; i< num_partials+1; i++)
{
// Set up each partial as the corresponding harmonic of the base_freq, with an amplitude of 1/N, 50ms attack, and a decay of 1 sec / N
// sprintf(amy_partial_command, "v%dw%df%.2fA0,%.2f,%d,0,0,0",base_osc+i,PARTIAL,base_freq*i,1.f/i, 1000/i);
sprintf(amy_partial_command, "v%dw%d",base_osc+i,PARTIAL);
strcat(amy_command, amy_partial_command); // Concatinate all partials to one wire-string to set up the patch
// Use this command if you want to store only one voice in memory instead: amy_play_message(amy_partial_command);
}
// --- Actually store the patch-data ---
patches_store_patch(amy_command);
Serial.printf("Patch to assign partials to voices: %s\n", amy_command); // Print patch, noteted as wire-string to serial for reference
// --- Reload the patch to be able to attach it to several voices ---
e = amy.default_event();
e.load_patch = 1024;
strcpy(e.voices, "0,1,2,3");
amy.add_event(e);
// --- Add base-frequency default breakpoints to oscillators of all voices ---
for(int i=1; i< num_partials+1; i++) // We do this on purpose, to keep the string for the patch as short as possible, standard-lenght is 255
{
e = amy.default_event();
strcpy(e.voices, "0,1,2,3");
e.osc=base_osc+i;
e.freq_coefs[COEF_CONST]=base_freq*i;
sprintf(e.bp0,"0,%.2f,%d,0,0,0", 1.f/i, 1000/i);
amy.add_event(e);
}
}
// --- Initialize everything ---
void setup()
{
// --- Start up AMY ---
amy.begin(1, 0, 0, 0); // Cores==1, Reverb==0, Chorus==0, Echo==0
// --- Setup 4 voices with 24 partials each and default base-frequency and breakpoints... ---
attach_partials_to_voices();
// --- Serial stuff (Serial Monitor output) ---
Serial.begin(115200);
// --- Set and start I2S ---
I2S.setPins(13, 11, 12, -1, -1); // MB 20240807
I2S.begin(I2S_MODE_STD, AMY_SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO); // I2S.begin(I2S_PHILIPS_MODE, AMY_SAMPLE_RATE, BYTES_PER_SAMPLE8);
}
// --- "Play" a chord with 4 notes consisting of 24 partials each, using 4 seperate voices ---
void play_chord()
{
struct event e = amy.default_event();
// --- Note-on events for two notes assigned to one voice each ---
e = amy.default_event();
e.time=100;
strcpy(e.voices, "0");
e.midi_note=60;
e.velocity=0.5f;
amy.add_event(e);
e = amy.default_event();
e.time=200;
strcpy(e.voices, "1");
e.midi_note=64;
e.velocity=0.5f;
amy.add_event(e);
e = amy.default_event();
e.time=300;
strcpy(e.voices, "2");
e.midi_note=67;
e.velocity=0.5f;
amy.add_event(e);
e = amy.default_event();
e.time=400;
strcpy(e.voices, "3");
e.midi_note=72;
e.velocity=0.5f;
amy.add_event(e);
// --- Note-off events for two notes assigned to one voice each ---
e = amy.default_event();
e.time=2400;
strcpy(e.voices, "0");
e.midi_note=60;
e.velocity=0.f;
amy.add_event(e);
e = amy.default_event();
e.time=2400;
strcpy(e.voices, "1");
e.midi_note=64;
e.velocity=0.f;
amy.add_event(e);
e = amy.default_event();
e.time=2400;
strcpy(e.voices, "2");
e.midi_note=67;
e.velocity=0.f;
amy.add_event(e);
e = amy.default_event();
e.time=2400;
strcpy(e.voices, "3");
e.midi_note=72;
e.velocity=0.f;
amy.add_event(e);
}
// --- Main loop function ---
void loop()
{
// --- "Play" a chord with 4 notes consisting of 24 partials each, using 4 seperate voices ---
play_chord();
// --- Render the amy-events from above as audio ---
while(true)
{
short* samples = amy.render_to_buffer(); // You should hear two notes played one after the other and then released at the same time...
I2S.write((uint8_t*)samples, AMY_BLOCK_SIZE*AMY_NCHANS*BYTES_PER_SAMPLE);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment