Add Effects to MidiSynthKeyboard Audio example

halogravity

Well-known member
Hello everyone. Recently I started building a basic synth for my young niece, so obviously bright blinky lights were a big factor. :) I started creating my own pcb and used Cherry MX keyboard keys. Then multiplexing came into play, and it began to get a little complicated(being my first PCB design). I then stumbled upon the Keybow 2040 (https://shop.pimoroni.com/products/keybow-2040?variant=32399559589971) which is quite literally exactly what I was going for in my design(16 hot-swappable MX keys, addressable LED's, etc). I decided to try using the Teensy as a host and plug the Keybow into the Teensy. I loaded up the MidiSynthKeyboard sketch and SUCCESS! Almost! The lights light up and the notes play, but I dont think its reading the notes from the Teensy sketch, The Keybow uses the Raspberry Pi 2040 chip, and is the code is written in circuit python. Here is the sketch for the keybow:

Code:
# SPDX-FileCopyrightText: 2021 Sandy Macdonald
#
# SPDX-License-Identifier: MIT

# Demonstrates how to send MIDI notes by attaching handler functions to key
# presses with decorators.

# You'll need to connect Keybow 2040 to a computer running a DAW like Ableton,
# or other software synth, or to a hardware synth that accepts USB MIDI.

# Drop the `keybow2040.py` file and `keybow_hardware` folder
# into your `lib` folder on your `CIRCUITPY` drive.

# NOTE! Requires the adafruit_midi CircuitPython library also!

import time
from keybow2040 import Keybow2040
from keybow_hardware.pim56x import PIM56X as Hardware # for Keybow 2040
#from keybow_hardware.pim551 import PIM551 as Hardware # for Pico RGB Keypad Base

import usb_midi
import adafruit_midi
from adafruit_midi.note_off import NoteOff
from adafruit_midi.note_on import NoteOn

# Set up Keybow
keybow = Keybow2040(Hardware())
keys = keybow.keys

# Set USB MIDI up on channel 0.
midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0)

# The colour to set the keys when pressed.
rgb = (0, 255, 50)

# Initial values for MIDI note and velocity.
start_note = 36
velocity = 127

# Loop through keys and attach decorators.
for key in keys:
    # If pressed, send a MIDI note on command and light key.
    @keybow.on_press(key)
    def press_handler(key):
        note = start_note + key.number
        key.set_led(*rgb)
        midi.send(NoteOn(note, velocity))

    # If released, send a MIDI note off command and turn off LED.
    @keybow.on_release(key)
    def release_handler(key):
        note = start_note + key.number
        key.set_led(0, 0, 0)
        midi.send(NoteOff(note, 0))

while True:
    # Always remember to call keybow.update()!
    keybow.update()

It came with the Keybow 2040 code as an example and works great as a midi controller. There is even an arpeggiator and a 4 track sequencer (Thanks Sandy!) Here's my issue. The way the MidiSynthKeyboard sketch is written the mixer number is a variable, "TOTAL_MIXERS", so with my limited knowledge of the audio system I am having trouble loading it into the Audio Design tool.


Basically, how do I add effects onto the audio chain? When I try and paste the code to the Audio design tool I get a few boxes and no connections, and I'm a bit confused. I feel like maybe starting from scratch would be better, because honestly I'd rather use oscillators like in a virtual analog setup rather than wavetables anyway but then I don't know how to get the Teensy to read the notes the Keybow sends polyphonically and this setup seems so close to what I need.

And lastly, is there a way to setup a button or pot to scroll through the different wavetables? The keybow has the ability to hold a key and press another (like a shift/function key) but I cant figure out what determines the wavetable used by the synth. Is it the channel the Keyboard is transmitting Midi on? And I have SUPER limited CircuitPython knowledge.

And just to make it slightly more complex Id like to add an encoder that would change the key and scale the keyboard is playing. The click of the encoder would change the key and the turn would change through scales (Major, Minor, Mixolydian, Dorian, etc.)

I'm sorry to throw so much out there I am just feel like I'm so close and I'm hoping someone out there can point me in the right direction. Can I make the MidiSynthKeyboard sketch work or should I start from scratch?

Thanks in advance for any help you guys can provide! I appreciate you taking the time reading this. Here is the MidiSynthKeyboard sketch for reference. The patch section is whats throwing me and seems to throw the audio tool as well. I just would like to add some reverb, maybe chorus and delay, the usual stuff.

Code:
/* Play notes with a regular USB MIDI Instrument.

   To use this example, connect a USB instrument to Teensy 3.6's
   USB host port.  This cable is recommended:
     https://www.pjrc.com/store/cable_usb_host_t36.html

   Requires Teensy 3.6 for USB host capability.
   Requires Audio Shield: https://www.pjrc.com/store/teensy3_audio.html
*/


#include "Pizzicato_samples.h"
#include "FrenchHorns_samples.h"
#include "Viola_samples.h"
#include "BasicFlute1_samples.h"
#include "Ocarina_samples.h"

#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <USBHost_t36.h>

//#define DEBUG_ALLOC

const int TOTAL_VOICES = 64;
const int TOTAL_MIXERS = 21;
const int SECONDARY_MIXERS = 4;

USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub3(myusb);
KeyboardController keyboard1(myusb);
KeyboardController keyboard2(myusb);
MIDIDevice midi1(myusb);

AudioControlSGTL5000 sgtl5000_1;
AudioSynthWavetable wavetable[TOTAL_VOICES];
AudioMixer4 mixer[TOTAL_MIXERS];
AudioOutputI2S i2s1;
AudioConnection patchCord[] = {
	{wavetable[0], 0, mixer[0], 0}, {wavetable[1], 0, mixer[0], 1}, {wavetable[2], 0, mixer[0],  2}, {wavetable[3], 0, mixer[0],  3}, {mixer[0], 0, mixer[TOTAL_MIXERS - 2], 0},
	{wavetable[4], 0, mixer[1], 0}, {wavetable[5], 0, mixer[1], 1}, {wavetable[6], 0, mixer[1],  2}, {wavetable[7], 0, mixer[1],  3}, {mixer[1], 0, mixer[TOTAL_MIXERS - 2], 1},
	{wavetable[8], 0, mixer[2], 0}, {wavetable[9], 0, mixer[2], 1}, {wavetable[10], 0, mixer[2],  2}, {wavetable[11], 0, mixer[2],  3}, {mixer[2], 0, mixer[TOTAL_MIXERS - 2], 2},
	{wavetable[12], 0, mixer[3], 0}, {wavetable[13], 0, mixer[3], 1}, {wavetable[14], 0, mixer[3],  2}, {wavetable[15], 0, mixer[3],  3}, {mixer[3], 0, mixer[TOTAL_MIXERS - 2], 3},
	{wavetable[16], 0, mixer[4], 0}, {wavetable[17], 0, mixer[4], 1}, {wavetable[18], 0, mixer[4],  2}, {wavetable[19], 0, mixer[4],  3}, {mixer[4], 0, mixer[TOTAL_MIXERS - 3], 0},
	{wavetable[20], 0, mixer[5], 0}, {wavetable[21], 0, mixer[5], 1}, {wavetable[22], 0, mixer[5],  2}, {wavetable[23], 0, mixer[5],  3}, {mixer[5], 0, mixer[TOTAL_MIXERS - 3], 1},
	{wavetable[24], 0, mixer[6], 0}, {wavetable[25], 0, mixer[6], 1}, {wavetable[26], 0, mixer[6],  2}, {wavetable[27], 0, mixer[6],  3}, {mixer[6], 0, mixer[TOTAL_MIXERS - 3], 2},
	{wavetable[28], 0, mixer[7], 0}, {wavetable[29], 0, mixer[7], 1}, {wavetable[30], 0, mixer[7],  2}, {wavetable[31], 0, mixer[7],  3}, {mixer[7], 0, mixer[TOTAL_MIXERS - 3], 3},
	{wavetable[32], 0, mixer[8], 0}, {wavetable[33], 0, mixer[8], 1}, {wavetable[34], 0, mixer[8],  2}, {wavetable[35], 0, mixer[8],  3}, {mixer[8], 0, mixer[TOTAL_MIXERS - 4], 0},
	{wavetable[36], 0, mixer[9], 0}, {wavetable[37], 0, mixer[9], 1}, {wavetable[38], 0, mixer[9],  2}, {wavetable[39], 0, mixer[9],  3}, {mixer[9], 0, mixer[TOTAL_MIXERS - 4], 1},
	{wavetable[40], 0, mixer[10], 0}, {wavetable[41], 0, mixer[10], 1}, {wavetable[42], 0, mixer[10], 2}, {wavetable[43], 0, mixer[10], 3}, {mixer[10], 0, mixer[TOTAL_MIXERS - 4], 2},
	{wavetable[44], 0, mixer[11], 0}, {wavetable[45], 0, mixer[11], 1}, {wavetable[46], 0, mixer[11], 2}, {wavetable[47], 0, mixer[11], 3}, {mixer[11], 0, mixer[TOTAL_MIXERS - 4], 3},
	{wavetable[48], 0, mixer[12], 0}, {wavetable[49], 0, mixer[12], 1}, {wavetable[50], 0, mixer[12], 2}, {wavetable[51], 0, mixer[12], 3}, {mixer[12], 0, mixer[TOTAL_MIXERS - 5], 0},
	{wavetable[52], 0, mixer[13], 0}, {wavetable[53], 0, mixer[13], 1}, {wavetable[54], 0, mixer[13], 2}, {wavetable[55], 0, mixer[13], 3}, {mixer[13], 0, mixer[TOTAL_MIXERS - 5], 1},
	{wavetable[56], 0, mixer[14], 0}, {wavetable[57], 0, mixer[14], 1}, {wavetable[58], 0, mixer[14], 2}, {wavetable[59], 0, mixer[14], 3}, {mixer[14], 0, mixer[TOTAL_MIXERS - 5], 2},
	{wavetable[60], 0, mixer[15], 0}, {wavetable[61], 0, mixer[15], 1}, {wavetable[62], 0, mixer[15], 2}, {wavetable[63], 0, mixer[15], 3}, {mixer[15], 0, mixer[TOTAL_MIXERS - 5], 3},
	{mixer[TOTAL_MIXERS - 2], 0, mixer[TOTAL_MIXERS - 1], 0},
	{mixer[TOTAL_MIXERS - 3], 0, mixer[TOTAL_MIXERS - 1], 1},
	{mixer[TOTAL_MIXERS - 4], 0, mixer[TOTAL_MIXERS - 1], 2},
	{mixer[TOTAL_MIXERS - 5], 0, mixer[TOTAL_MIXERS - 1], 3},
	{mixer[TOTAL_MIXERS - 1], 0, i2s1, 0},
	{mixer[TOTAL_MIXERS - 1], 0, i2s1, 1},
};
Bounce buttons[] = { {0, 15}, {1, 15}, {2, 15}, };
const int TOTAL_BUTTONS = sizeof(buttons) / sizeof(Bounce);

void guitarHeroMode();
void printVoices();
void setVolume() {
	sgtl5000_1.volume(0.8*(analogRead(PIN_A2) - 1) / 1022.0);
}

struct voice_t {
	int wavetable_id;
	byte channel;
	byte note;
};
voice_t voices[TOTAL_VOICES];

IntervalTimer midiMapTimer;
IntervalTimer guitarHeroTimer;
IntervalTimer volumeTimer;

void setup() {
	Serial.begin(115200);

	pinMode(0, INPUT_PULLUP);
	pinMode(1, INPUT_PULLUP);
	pinMode(2, INPUT_PULLUP);

	AudioMemory(120);

	sgtl5000_1.enable();
	sgtl5000_1.volume(0.8);

	for (int i = 0; i < TOTAL_VOICES; ++i) {
		wavetable[i].setInstrument(Pizzicato);
		wavetable[i].amplitude(1);
		voices[i].wavetable_id = i;
		voices[i].channel = voices[i].note = 0xFF;
	}

	for (int i = 0; i < TOTAL_MIXERS - 1; ++i)
		for (int j = 0; j < 4; ++j)
			mixer[i].gain(j, 0.50);
	for (int i = 0; i < 4; ++i)
		mixer[TOTAL_MIXERS - 1].gain(i, i < SECONDARY_MIXERS ? 1.0 / SECONDARY_MIXERS : 0.0);

	Serial.println("USB Host Testing");
	myusb.begin();
	keyboard1.attachPress(OnPress);
	keyboard2.attachPress(OnPress);
	midi1.setHandleNoteOff(OnNoteOff);
	midi1.setHandleNoteOn(OnNoteOn);
	midi1.setHandleControlChange(OnControlChange);
	//volumeTimer.begin(setVolume, 100000);
	guitarHeroTimer.begin(guitarHeroMode, 1000000 / 120);
	//midiMapTimer.begin(printVoices, 5000);

	delay(2000);
}

void loop() {
	myusb.Task();
	midi1.read();
	//for (int i = 0; i < TOTAL_BUTTONS; ++i) buttons[i].update();
	//if (buttons[0].fallingEdge()) AudioSynthWavetable::print_performance();
	//if (buttons[1].risingEdge()) {
	//	midiMapTimer.end();
	//	Serial.print('\n');
	//}
	//if (buttons[1].fallingEdge()) midiMapTimer.begin(printVoices, 5000);
	//if (buttons[2].risingEdge()) guitarHeroTimer.end();
	//if (buttons[2].fallingEdge())
	//	guitarHeroTimer.begin(guitarHeroMode, 1000000/60);
}

int allocateVoice(byte channel, byte note);
int findVoice(byte channel, byte note);
void freeVoices();

int used_voices = 0;
int stopped_voices = 0;
int evict_voice = 0;
int notes_played = 0;

void OnPress(int key)
{
	Serial.print("key '");
	Serial.print((char)key);
	Serial.print("'  ");
	Serial.println(key);
	//Serial.print("key ");
	//Serial.print((char)keyboard1.getKey());
	//Serial.print("  ");
	//Serial.print((char)keyboard2.getKey());
	//Serial.println();
}

void OnControlChange(byte channel, byte control, byte value)
{
	Serial.print("Control Change, ch=");
	Serial.print(channel);
	Serial.print(", control=");
	Serial.print(control);
	Serial.print(", value=");
	Serial.print(value);
	Serial.println();
}

void OnNoteOn(byte channel, byte note, byte velocity) {
	notes_played++;
#ifdef DEBUG_ALLOC
	//Serial.printf("**** NoteOn: channel==%hhu,note==%hhu ****\n", channel, note);
	printVoices();
#endif //DEBUG_ALLOC
	freeVoices();
	int wavetable_id = allocateVoice(channel, note);
	switch (channel) {
	case 1:
		wavetable[wavetable_id].setInstrument(BasicFlute1);
		break;
	case 2:
		wavetable[wavetable_id].setInstrument(FrenchHorns);
		break;
	case 3:
		wavetable[wavetable_id].setInstrument(Ocarina);
		break;
	case 4:
		wavetable[wavetable_id].setInstrument(Ocarina);
		break;
	case 5:
		wavetable[wavetable_id].setInstrument(Pizzicato);
		break;
	default:
		wavetable[wavetable_id].setInstrument(Pizzicato);
		break;
	}
	wavetable[wavetable_id].playNote(note, velocity);
#ifdef DEBUG_ALLOC
	printVoices();
#endif //DEBUG_ALLOC
}

void OnNoteOff(byte channel, byte note, byte velocity) {
#ifdef DEBUG_ALLOC
	//Serial.printf("\n**** NoteOff: channel==%hhu,note==%hhu ****", channel, note);
	printVoices();
#endif //DEBUG_ALLOC
	int wavetable_id = findVoice(channel, note);
	if (wavetable_id != TOTAL_VOICES)
		wavetable[wavetable_id].stop();
#ifdef DEBUG_ALLOC
	printVoices();
#endif //DEBUG_ALLOC
}

int allocateVoice(byte channel, byte note) {
	int i;
	int nonfree_voices = stopped_voices + used_voices;
	if (nonfree_voices < TOTAL_VOICES) {
		for (i = nonfree_voices; i < TOTAL_VOICES && voices[i].channel != channel; ++i);
		if (i < TOTAL_VOICES) {
			voice_t temp = voices[i];
			voices[i] = voices[nonfree_voices];
			voices[nonfree_voices] = temp;
		}
		i = nonfree_voices;
		used_voices++;
	}
	else {
		if (stopped_voices) {
			i = evict_voice % stopped_voices;
			voice_t temp = voices[i];
			stopped_voices--;
			voices[i] = voices[stopped_voices];
			voices[stopped_voices] = temp;
			used_voices++;
			i = stopped_voices;
		}
		else
			i = evict_voice;
	}

	voices[i].channel = channel;
	voices[i].note = note;

	evict_voice++;
	evict_voice %= TOTAL_VOICES;

	return voices[i].wavetable_id;
}

int findVoice(byte channel, byte note) {
	int i;
	//find match
	int nonfree_voices = stopped_voices + used_voices;
	for (i = stopped_voices; i < nonfree_voices && !(voices[i].channel == channel && voices[i].note == note); ++i);
	//return TOTAL_VOICES if no match
	if (i == (nonfree_voices)) return TOTAL_VOICES;

	voice_t temp = voices[i];
	voices[i] = voices[stopped_voices];
	voices[stopped_voices] = temp;
	--used_voices;

	return voices[stopped_voices++].wavetable_id;
}

void freeVoices() {
	for (int i = 0; i < stopped_voices; i++)
		if (wavetable[voices[i].wavetable_id].isPlaying() == false) {
			voice_t temp = voices[i];
			--stopped_voices;
			voices[i] = voices[stopped_voices];
			int nonfree_voices = stopped_voices + used_voices;
			voices[stopped_voices] = voices[nonfree_voices];
			voices[nonfree_voices] = temp;
		}
}

void guitarHeroMode() { // now unicorn friendly
	const int RESET = 4;
	const int MIDI_NOTES = 128;
	static char line[MIDI_NOTES + 1] = { 0 };
	static int accumulated = 0;
	if (!accumulated) {
		for (int i = 0; i < MIDI_NOTES; ++i) line[i] = '-';
		++accumulated;
	}
	for (int i = stopped_voices; i < used_voices + stopped_voices; ++i) line[voices[i].note] = '*';
	if (accumulated++ == RESET) {
		Serial.println(line);
		accumulated = 0;
	}
}

const char* note_map[] = {
	"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"
};

void printVoices() {
	static int last_notes_played = notes_played;
	if (last_notes_played == notes_played)
		return;
	last_notes_played = notes_played;
	int usage = AudioProcessorUsage();
	Serial.printf("\nCPU:%03i voices:%02i CPU/Voice:%02i evict:%02i", usage, used_voices, usage / used_voices, evict_voice);
	for (int i = 0; i < used_voices; ++i)
		Serial.printf(" %02hhu %-2s", voices[i].channel, note_map[voices[i].note % 12]);

}
 
Last edited:
I would be glad to start from scratch if someone could give me a head start on how to setup a 16 note polyphonic waveform synth with the teensy a usb host and a 16 key midi controller(the Keybow 2040). Do I need 16 waveform instances and 16 mixer inputs? Any help would be greatly appreciated.
 
You need as many waveforms (or whatever sound generators) as you would like to be able to play back in parallel, i.e. polyphonic voices at the same time.

If you should have "only" 16 input keys than it could be easy to use 16 voices to have one waveform for each key. In this way you would save the work to manage the voice allocation and have a fixed connection.

Each mixer has 4 inputs. For 16 waveform you need 4x4 mixers plus one mixer for these 4 mixers. This could be done all in the GUI.

In the code you are showing for the mixers and waveforms indices (using the [] brackets) are used which makes it handy for such huge numbers of elements. This organisation of elements is not shown in the GUI.

It could make sense to start with a simple example: One waveform, one voice... and than add more voices and fx step by step. If you understand the principles there could come the point where you change from designing in the GUI to use larger numbers of elements with indices. It would be also possible to combine blocks. See here: https://forum.pjrc.com/threads/7229...tions-conflict?p=321678&viewfull=1#post321678
 
Thanks TomChiron! That was very helpful and the post you showed cleared it up a lot. I'm going ton search around myself and simply start from scratch. I need to find information on using the Teensy as a USB Host and then I'm guessing I set each note to trigger an onPress and onRelease function that will turn the mixer on or off for each note? Is that the general idea? Sorry to hound you my friend but I'm not finding a to of info for this particular setup. I've found monosynth tutorials and MIDI tutorials but not much in the way of USB Host info.
 
I guess my main question is how do I read each midi note for my controller press and then turn on/off the mixer channel based on that? Do I begin all the waveforms at the very start? I know I also need an array to keep track of the playing voices.... this is where I start to get confused, I'm not a super strong coder, I'm coming from the hardware world so I can build you a VCF in couple hours... and I thought this would be easier...lol. At least I said that this will be my nieces Christmas gift. I have some time. If there is some comprehensive guide somewhere I'm missing feel free to send me on my way but Im not a person who runs to a forum without searching first. Even github didnt have a good example using this setup. Sigh. This is the setup I'm starting with, am I on th right track?

Code:
#include <Arduino.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// TeensyAudioDesign: begin automatically generated code
// the following JSON string contains the whole project, 
// it's included in all generated files.
// JSON string:[{"type":"settings","data":{"main":{},"arduino":{"Board":{"Platform":"","Board":"teensy41","Options":""}},"BiDirDataWebSocketBridge":{"bddwssPort":80},"workspaces":{},"sidebar":{},"palette":{},"editor":{},"devTest":{},"IndexedDBfiles":{"testFileNames":"testFile.txt"},"NodeDefGenerator":{},"NodeDefManager":{},"NodeHelpManager":{},"OSC":{}}},{"type":"tab","id":"Main","label":"Main","nodes":[],"links":[],"export":true,"isMain":false,"mainNameType":"tabName","mainNameExt":".ino","isAudioMain":false,"generateCppDestructor":false,"extraClassDeclarations":"","settings":{"scaleFactor":0.4}},{"id":"sgtl5000_1","type":"AudioControlSGTL5000","name":"sgtl5000_1","x":0,"y":0,"z":"Main","bgColor":"#E6E0F8","wires":[]},{"id":"wavetable[TOTAL_VOICES]","type":"AudioSynthWavetable","name":"wavetable[TOTAL_VOICES]","arraySize":0,"x":0,"y":0,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"mixer[TOTAL_MIXERS]","type":"AudioMixer4","name":"mixer[TOTAL_MIXERS]","arraySize":0,"x":0,"y":0,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"i2s1","type":"AudioOutputI2S","name":"i2s1","x":0,"y":0,"z":"Main","bgColor":"#E6E0F8","wires":[]},{"id":"20230930T152420_430Z_367f","type":"AudioSynthWaveform","name":"waveform1","comment":"","arraySize":1,"x":1010,"y":535,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213047_341Z_60a4:0"]]},{"id":"20230930T152548_699Z_27ab","type":"AudioSynthWaveform","name":"waveform2","comment":"","arraySize":1,"x":1010,"y":580,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213047_341Z_60a4:1"]]},{"id":"20230930T152631_053Z_785c","type":"AudioSynthWaveform","name":"waveform3","comment":"","arraySize":1,"x":1010,"y":625,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213047_341Z_60a4:2"]]},{"id":"20230930T152643_171Z_8aed","type":"AudioSynthWaveform","name":"waveform4","comment":"","arraySize":1,"x":1010,"y":670,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213047_341Z_60a4:3"]]},{"id":"20230930T152741_255Z_3cd6","type":"AudioSynthWaveform","name":"waveform5","comment":"","arraySize":1,"x":1005,"y":740,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213110_916Z_4bc6:0"]]},{"id":"20230930T152741_255Z_ca98","type":"AudioSynthWaveform","name":"waveform6","comment":"","arraySize":1,"x":1005,"y":785,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213110_916Z_4bc6:1"]]},{"id":"20230930T152741_256Z_3a50","type":"AudioSynthWaveform","name":"waveform7","comment":"","arraySize":1,"x":1000,"y":825,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213110_916Z_4bc6:2"]]},{"id":"20230930T152741_256Z_6b99","type":"AudioSynthWaveform","name":"waveform8","comment":"","arraySize":1,"x":1000,"y":865,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213110_916Z_4bc6:3"]]},{"id":"20230930T152835_452Z_756e","type":"AudioSynthWaveform","name":"waveform9","comment":"","arraySize":1,"x":1005,"y":945,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213115_322Z_a98d:0"]]},{"id":"20230930T152835_452Z_45ea","type":"AudioSynthWaveform","name":"waveform10","comment":"","arraySize":1,"x":1010,"y":990,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213115_322Z_a98d:1"]]},{"id":"20230930T152835_452Z_88f4","type":"AudioSynthWaveform","name":"waveform11","comment":"","arraySize":1,"x":1010,"y":1035,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213115_322Z_a98d:2"]]},{"id":"20230930T152835_452Z_9557","type":"AudioSynthWaveform","name":"waveform12","comment":"","arraySize":1,"x":1010,"y":1080,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213115_322Z_a98d:3"]]},{"id":"20230930T152944_291Z_fc06","type":"AudioSynthWaveform","name":"waveform13","comment":"","arraySize":1,"x":1100,"y":1170,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213122_635Z_5407:0"]]},{"id":"20230930T152944_291Z_dec6","type":"AudioSynthWaveform","name":"waveform14","comment":"","arraySize":1,"x":1100,"y":1215,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213122_635Z_5407:1"]]},{"id":"20230930T152944_291Z_6f1b","type":"AudioSynthWaveform","name":"waveform15","comment":"","arraySize":1,"x":1100,"y":1260,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213122_635Z_5407:2"]]},{"id":"20230930T152944_291Z_2642","type":"AudioSynthWaveform","name":"waveform16","comment":"","arraySize":1,"x":1100,"y":1305,"z":"Main","bgColor":"#E6E0F8","wires":[["20230929T213122_635Z_5407:3"]]},{"id":"20230929T213047_341Z_60a4","type":"AudioMixer4","name":"mixer1","comment":"","arraySize":1,"x":1260,"y":595,"z":"Main","bgColor":"#E6E0F8","wires":[["20230930T151203_985Z_f429:0"]]},{"id":"20230929T213110_916Z_4bc6","type":"AudioMixer4","name":"mixer2","comment":"","arraySize":1,"x":1255,"y":800,"z":"Main","bgColor":"#E6E0F8","wires":[["20230930T151203_985Z_f429:1"]]},{"id":"20230929T213115_322Z_a98d","type":"AudioMixer4","name":"mixer3","comment":"","arraySize":1,"x":1265,"y":1010,"z":"Main","bgColor":"#E6E0F8","wires":[["20230930T151203_985Z_f429:2"]]},{"id":"20230929T213122_635Z_5407","type":"AudioMixer4","name":"mixer4","comment":"","arraySize":1,"x":1335,"y":1245,"z":"Main","bgColor":"#E6E0F8","wires":[["20230930T151203_985Z_f429:3"]]},{"id":"20230930T151203_985Z_f429","type":"AudioMixer4","name":"mixer5","comment":"","arraySize":1,"x":1550,"y":1050,"z":"Main","bgColor":"#E6E0F8","wires":[["20230930T151742_472Z_517e:0"]]},{"id":"20230930T151532_942Z_16cb","type":"AudioInputI2S","name":"i2s2","comment":"","x":1540,"y":1135,"z":"Main","bgColor":"#E6E0F8","wires":[["20230930T151742_472Z_517e:1"],["20230930T151742_472Z_517e:2"]]},{"id":"20230930T151338_558Z_91f3","type":"AudioControlSGTL5000","name":"sgtl5000","comment":"","x":1556.25,"y":1203.75,"z":"Main","bgColor":"#E6E0F8","wires":[]},{"id":"20230930T151742_472Z_517e","type":"AudioMixer4","name":"mixer6","comment":"","arraySize":1,"x":1735,"y":1095,"z":"Main","bgColor":"#E6E0F8","wires":[["20230930T151254_820Z_1fd2:0","20230930T151254_820Z_1fd2:1"]]},{"id":"20230930T151254_820Z_1fd2","type":"AudioOutputI2S","name":"i2s","comment":"","x":1855,"y":1065,"z":"Main","bgColor":"#E6E0F8","wires":[]}]




// Audio Processing Nodes
AudioSynthWavetable             wavetable[TOTAL_VOICES]; //xy=0,0
AudioMixer4                     mixer[TOTAL_MIXERS]; //xy=0,0
AudioOutputI2S                  i2s1;           //xy=0,0
AudioSynthWaveform              waveform1; //xy=1010,535
AudioSynthWaveform              waveform2; //xy=1010,580
AudioSynthWaveform              waveform3; //xy=1010,625
AudioSynthWaveform              waveform4; //xy=1010,670
AudioSynthWaveform              waveform5; //xy=1005,740
AudioSynthWaveform              waveform6; //xy=1005,785
AudioSynthWaveform              waveform7; //xy=1000,825
AudioSynthWaveform              waveform8; //xy=1000,865
AudioSynthWaveform              waveform9; //xy=1005,945
AudioSynthWaveform              waveform10; //xy=1010,990
AudioSynthWaveform              waveform11; //xy=1010,1035
AudioSynthWaveform              waveform12; //xy=1010,1080
AudioSynthWaveform              waveform13; //xy=1100,1170
AudioSynthWaveform              waveform14; //xy=1100,1215
AudioSynthWaveform              waveform15; //xy=1100,1260
AudioSynthWaveform              waveform16; //xy=1100,1305
AudioMixer4                     mixer1; //xy=1260,595
AudioMixer4                     mixer2; //xy=1255,800
AudioMixer4                     mixer3; //xy=1265,1010
AudioMixer4                     mixer4; //xy=1335,1245
AudioMixer4                     mixer5; //xy=1550,1050
AudioInputI2S                   i2s2; //xy=1540,1135
AudioMixer4                     mixer6; //xy=1735,1095
AudioOutputI2S                  i2s; //xy=1855,1065

// Audio Connections (all connections (aka wires or links))
AudioConnection        patchCord1(waveform1, 0, mixer1, 0);
AudioConnection        patchCord2(waveform2, 0, mixer1, 1);
AudioConnection        patchCord3(waveform3, 0, mixer1, 2);
AudioConnection        patchCord4(waveform4, 0, mixer1, 3);
AudioConnection        patchCord5(waveform5, 0, mixer2, 0);
AudioConnection        patchCord6(waveform6, 0, mixer2, 1);
AudioConnection        patchCord7(waveform7, 0, mixer2, 2);
AudioConnection        patchCord8(waveform8, 0, mixer2, 3);
AudioConnection        patchCord9(waveform9, 0, mixer3, 0);
AudioConnection        patchCord10(waveform10, 0, mixer3, 1);
AudioConnection        patchCord11(waveform11, 0, mixer3, 2);
AudioConnection        patchCord12(waveform12, 0, mixer3, 3);
AudioConnection        patchCord13(waveform13, 0, mixer4, 0);
AudioConnection        patchCord14(waveform14, 0, mixer4, 1);
AudioConnection        patchCord15(waveform15, 0, mixer4, 2);
AudioConnection        patchCord16(waveform16, 0, mixer4, 3);
AudioConnection        patchCord17(mixer1, 0, mixer5, 0);
AudioConnection        patchCord18(mixer2, 0, mixer5, 1);
AudioConnection        patchCord19(mixer3, 0, mixer5, 2);
AudioConnection        patchCord20(mixer4, 0, mixer5, 3);
AudioConnection        patchCord21(mixer5, 0, mixer6, 0);
AudioConnection        patchCord22(i2s2, 0, mixer6, 1);
AudioConnection        patchCord23(i2s2, 1, mixer6, 2);
AudioConnection        patchCord24(mixer6, 0, i2s, 0);
AudioConnection        patchCord25(mixer6, 0, i2s, 1);

// Control Nodes (all control nodes (no inputs or outputs))
AudioControlSGTL5000     sgtl5000_1;     //xy=0,0
AudioControlSGTL5000     sgtl5000;       //xy=1556.25,1203.75



// TeensyAudioDesign: end automatically generated code
 
In the examples included in the Teensyduino installation you should be able to find some inspiration and get into different aspects. E.g. "PlaySynthMusic". Also for reading input from USB host you should find examples.

Possibly the audio tutorial can also be of help for you:
https://www.pjrc.com/store/audio_tutorial_kit.html

You can use envelopes to trigger a note. Keep in mind that these are only available in linear behaviour. One workaround to get it "more exponential" is to combine/add a few envelopes.
 
Thank you gentlemen! I started the tutorial and I can see he starts with a single voice so I'm just going to follow along step by step, though Im on a 4.1 with a Rev. D audio board... shouldn't be an issue I'd wager. Thank you so much!
 
In response to your original post (sorry this is so late to the conversation), here's a visual representation of the audio interconnects from the legacy sketch (this layout does not necessarily respect the specific interconnections from the original design, but should give you the jist of how their arrays of objects were connected to each other). This layout simply splits out the arrays of objects into individual objects (e.g. wavetable[0] becomes wavetable_00, etc.). You should be able to cut/paste this into the "Audio System Design Tool for Teensy Audio Library" to get the visual layout.

Hope this helps to understand what was done in the legacy sketch . . .


Code:
// GUItool: begin automatically generated code
AudioSynthWavetable      wavetable_00;   //xy=153,100
AudioSynthWavetable      wavetable_01;   //xy=153,160
AudioSynthWavetable      wavetable_02;   //xy=153,220
AudioSynthWavetable      wavetable_03;   //xy=153,280
AudioSynthWavetable      wavetable_04;   //xy=153,400
AudioSynthWavetable      wavetable_05;   //xy=153,460
AudioSynthWavetable      wavetable_06;   //xy=153,520
AudioSynthWavetable      wavetable_07;   //xy=153,580
AudioSynthWavetable      wavetable_08;   //xy=153,700
AudioSynthWavetable      wavetable_09;   //xy=153,760
AudioSynthWavetable      wavetable_10;   //xy=153,820
AudioSynthWavetable      wavetable_11;   //xy=153,880
AudioSynthWavetable      wavetable_12;   //xy=153,1000
AudioSynthWavetable      wavetable_13;   //xy=153,1060
AudioSynthWavetable      wavetable_14;   //xy=153,1120
AudioSynthWavetable      wavetable_15;   //xy=153,1180
AudioSynthWavetable      wavetable_16;   //xy=153,1300
AudioSynthWavetable      wavetable_17;   //xy=153,1360
AudioSynthWavetable      wavetable_18;   //xy=153,1420
AudioSynthWavetable      wavetable_19;   //xy=153,1480
AudioSynthWavetable      wavetable_20;   //xy=153,1600
AudioSynthWavetable      wavetable_21;   //xy=153,1660
AudioSynthWavetable      wavetable_22;   //xy=153,1720
AudioSynthWavetable      wavetable_23;   //xy=153,1780
AudioSynthWavetable      wavetable_24;   //xy=153,1900
AudioSynthWavetable      wavetable_25;   //xy=153,1960
AudioSynthWavetable      wavetable_26;   //xy=153,2020
AudioSynthWavetable      wavetable_27;   //xy=153,2080
AudioSynthWavetable      wavetable_28;   //xy=153,2200
AudioSynthWavetable      wavetable_29;   //xy=153,2260
AudioSynthWavetable      wavetable_30;   //xy=153,2320
AudioSynthWavetable      wavetable_31;   //xy=153,2380
AudioSynthWavetable      wavetable_32;   //xy=153,2500
AudioSynthWavetable      wavetable_33;   //xy=153,2560
AudioSynthWavetable      wavetable_34;   //xy=153,2620
AudioSynthWavetable      wavetable_35;   //xy=153,2680
AudioSynthWavetable      wavetable_36;   //xy=153,2800
AudioSynthWavetable      wavetable_37;   //xy=153,2860
AudioSynthWavetable      wavetable_38;   //xy=153,2920
AudioSynthWavetable      wavetable_39;   //xy=153,2980
AudioSynthWavetable      wavetable_40;   //xy=153,3100
AudioSynthWavetable      wavetable_41;   //xy=153,3160
AudioSynthWavetable      wavetable_42;   //xy=153,3220
AudioSynthWavetable      wavetable_43;   //xy=153,3280
AudioSynthWavetable      wavetable_44;   //xy=153,3400
AudioSynthWavetable      wavetable_45;   //xy=153,3460
AudioSynthWavetable      wavetable_46;   //xy=153,3520
AudioSynthWavetable      wavetable_47;   //xy=153,3580
AudioSynthWavetable      wavetable_48;   //xy=153,3700
AudioSynthWavetable      wavetable_49;   //xy=153,3760
AudioSynthWavetable      wavetable_50;   //xy=153,3820
AudioSynthWavetable      wavetable_51;   //xy=153,3880
AudioSynthWavetable      wavetable_52;   //xy=153,4000
AudioSynthWavetable      wavetable_53;   //xy=153,4060
AudioSynthWavetable      wavetable_54;   //xy=153,4120
AudioSynthWavetable      wavetable_55;   //xy=153,4180
AudioSynthWavetable      wavetable_56;   //xy=153,4300
AudioSynthWavetable      wavetable_57;   //xy=153,4360
AudioSynthWavetable      wavetable_58;   //xy=153,4420
AudioSynthWavetable      wavetable_59;   //xy=153,4480
AudioSynthWavetable      wavetable_60;   //xy=153,4600
AudioSynthWavetable      wavetable_61;   //xy=153,4660
AudioSynthWavetable      wavetable_62;   //xy=153,4720
AudioSynthWavetable      wavetable_63;   //xy=153,4780
AudioMixer4              mixer_00;       //xy=653,190
AudioMixer4              mixer_01;       //xy=653,490
AudioMixer4              mixer_02;       //xy=653,790
AudioMixer4              mixer_03;       //xy=653,1090
AudioMixer4              mixer_04;       //xy=653,1390
AudioMixer4              mixer_05;       //xy=653,1690
AudioMixer4              mixer_06;       //xy=653,1990
AudioMixer4              mixer_07;       //xy=653,2290
AudioMixer4              mixer_08;       //xy=653,2590
AudioMixer4              mixer_09;       //xy=653,2890
AudioMixer4              mixer_10;       //xy=653,3190
AudioMixer4              mixer_11;       //xy=653,3490
AudioMixer4              mixer_12;       //xy=653,3790
AudioMixer4              mixer_13;       //xy=653,4090
AudioMixer4              mixer_14;       //xy=653,4390
AudioMixer4              mixer_15;       //xy=653,4690
AudioMixer4              mixer_16;       //xy=1153,640
AudioMixer4              mixer_17;       //xy=1153,1840
AudioMixer4              mixer_18;       //xy=1153,3040
AudioMixer4              mixer_19;       //xy=1153,4240
AudioMixer4              mixer_20;       //xy=1653,2440
AudioOutputI2S           i2s1;           //xy=1853,2440

AudioConnection          patchCord1(wavetable_00, 0, mixer_00, 0);
AudioConnection          patchCord2(wavetable_01, 0, mixer_00, 1);
AudioConnection          patchCord3(wavetable_02, 0, mixer_00, 2);
AudioConnection          patchCord4(wavetable_03, 0, mixer_00, 3);
AudioConnection          patchCord5(wavetable_04, 0, mixer_01, 0);
AudioConnection          patchCord6(wavetable_05, 0, mixer_01, 1);
AudioConnection          patchCord7(wavetable_06, 0, mixer_01, 2);
AudioConnection          patchCord8(wavetable_07, 0, mixer_01, 3);
AudioConnection          patchCord9(wavetable_08, 0, mixer_02, 0);
AudioConnection          patchCord10(wavetable_09, 0, mixer_02, 1);
AudioConnection          patchCord11(wavetable_10, 0, mixer_02, 2);
AudioConnection          patchCord12(wavetable_11, 0, mixer_02, 3);
AudioConnection          patchCord13(wavetable_12, 0, mixer_03, 0);
AudioConnection          patchCord14(wavetable_13, 0, mixer_03, 1);
AudioConnection          patchCord15(wavetable_14, 0, mixer_03, 2);
AudioConnection          patchCord16(wavetable_15, 0, mixer_03, 3);
AudioConnection          patchCord17(wavetable_16, 0, mixer_04, 0);
AudioConnection          patchCord18(wavetable_17, 0, mixer_04, 1);
AudioConnection          patchCord19(wavetable_18, 0, mixer_04, 2);
AudioConnection          patchCord20(wavetable_19, 0, mixer_04, 3);
AudioConnection          patchCord21(wavetable_20, 0, mixer_05, 0);
AudioConnection          patchCord22(wavetable_21, 0, mixer_05, 1);
AudioConnection          patchCord23(wavetable_22, 0, mixer_05, 2);
AudioConnection          patchCord24(wavetable_23, 0, mixer_05, 3);
AudioConnection          patchCord25(wavetable_24, 0, mixer_06, 0);
AudioConnection          patchCord26(wavetable_25, 0, mixer_06, 1);
AudioConnection          patchCord27(wavetable_26, 0, mixer_06, 2);
AudioConnection          patchCord28(wavetable_27, 0, mixer_06, 3);
AudioConnection          patchCord29(wavetable_28, 0, mixer_07, 0);
AudioConnection          patchCord30(wavetable_29, 0, mixer_07, 1);
AudioConnection          patchCord31(wavetable_30, 0, mixer_07, 2);
AudioConnection          patchCord32(wavetable_31, 0, mixer_07, 3);
AudioConnection          patchCord33(wavetable_32, 0, mixer_08, 0);
AudioConnection          patchCord34(wavetable_33, 0, mixer_08, 1);
AudioConnection          patchCord35(wavetable_34, 0, mixer_08, 2);
AudioConnection          patchCord36(wavetable_35, 0, mixer_08, 3);
AudioConnection          patchCord37(wavetable_36, 0, mixer_09, 0);
AudioConnection          patchCord38(wavetable_37, 0, mixer_09, 1);
AudioConnection          patchCord39(wavetable_38, 0, mixer_09, 2);
AudioConnection          patchCord40(wavetable_39, 0, mixer_09, 3);
AudioConnection          patchCord41(wavetable_40, 0, mixer_10, 0);
AudioConnection          patchCord42(wavetable_41, 0, mixer_10, 1);
AudioConnection          patchCord43(wavetable_42, 0, mixer_10, 2);
AudioConnection          patchCord44(wavetable_43, 0, mixer_10, 3);
AudioConnection          patchCord45(wavetable_44, 0, mixer_11, 0);
AudioConnection          patchCord46(wavetable_45, 0, mixer_11, 1);
AudioConnection          patchCord47(wavetable_46, 0, mixer_11, 2);
AudioConnection          patchCord48(wavetable_47, 0, mixer_11, 3);
AudioConnection          patchCord49(wavetable_48, 0, mixer_12, 0);
AudioConnection          patchCord50(wavetable_49, 0, mixer_12, 1);
AudioConnection          patchCord51(wavetable_50, 0, mixer_12, 2);
AudioConnection          patchCord52(wavetable_51, 0, mixer_12, 3);
AudioConnection          patchCord53(wavetable_52, 0, mixer_13, 0);
AudioConnection          patchCord54(wavetable_53, 0, mixer_13, 1);
AudioConnection          patchCord55(wavetable_54, 0, mixer_13, 2);
AudioConnection          patchCord56(wavetable_55, 0, mixer_13, 3);
AudioConnection          patchCord57(wavetable_56, 0, mixer_14, 0);
AudioConnection          patchCord58(wavetable_57, 0, mixer_14, 1);
AudioConnection          patchCord59(wavetable_58, 0, mixer_14, 2);
AudioConnection          patchCord60(wavetable_59, 0, mixer_14, 3);
AudioConnection          patchCord61(wavetable_60, 0, mixer_15, 0);
AudioConnection          patchCord62(wavetable_61, 0, mixer_15, 1);
AudioConnection          patchCord63(wavetable_62, 0, mixer_15, 2);
AudioConnection          patchCord64(wavetable_63, 0, mixer_15, 3);
AudioConnection          patchCord65(mixer_00, 0, mixer_16, 0);
AudioConnection          patchCord66(mixer_01, 0, mixer_16, 1);
AudioConnection          patchCord67(mixer_02, 0, mixer_16, 2);
AudioConnection          patchCord68(mixer_03, 0, mixer_16, 3);
AudioConnection          patchCord69(mixer_04, 0, mixer_17, 0);
AudioConnection          patchCord70(mixer_05, 0, mixer_17, 1);
AudioConnection          patchCord71(mixer_06, 0, mixer_17, 2);
AudioConnection          patchCord72(mixer_07, 0, mixer_17, 3);
AudioConnection          patchCord73(mixer_08, 0, mixer_18, 0);
AudioConnection          patchCord74(mixer_09, 0, mixer_18, 1);
AudioConnection          patchCord75(mixer_10, 0, mixer_18, 2);
AudioConnection          patchCord76(mixer_11, 0, mixer_18, 3);
AudioConnection          patchCord77(mixer_12, 0, mixer_19, 0);
AudioConnection          patchCord78(mixer_13, 0, mixer_19, 1);
AudioConnection          patchCord79(mixer_14, 0, mixer_19, 2);
AudioConnection          patchCord80(mixer_15, 0, mixer_19, 3);
AudioConnection          patchCord81(mixer_16, 0, mixer_20, 0);
AudioConnection          patchCord82(mixer_17, 0, mixer_20, 1);
AudioConnection          patchCord83(mixer_18, 0, mixer_20, 2);
AudioConnection          patchCord84(mixer_19, 0, mixer_20, 3);
AudioConnection          patchCord85(mixer_20, 0, i2s1, 0);
AudioConnection          patchCord86(mixer_20, 0, i2s1, 1);

AudioControlSGTL5000     sgtl5000_1;     //xy=1293,120
// GUItool: end automatically generated code

Mark J Culross
KD5RXT
 
Back
Top