Created
September 17, 2024 18:48
-
-
Save Visuelle-Musik/8d70f4fd2505099fcbc94dbeb9a26107 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// === 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