Created
May 7, 2017 19:24
-
-
Save LeoAdamek/8ed24b8e3322037b9a7adb7546b705f1 to your computer and use it in GitHub Desktop.
polysynth
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
#include <Audio.h> | |
#include <MIDI.h> | |
// Each concurrent note is assigned to a voice. | |
// The voice tracks which note is being played so | |
// when it is relased the correct voice can be stopped. | |
typedef struct { | |
// A pointer to the oscillator so it can be controlled. | |
AudioSynthWaveformSine* osc; | |
// MIDI Note | |
byte note; | |
// Note Frequency | |
float freq; | |
// Note amplitude. | |
float amp; | |
} Voice; | |
// The actual oscillators for the voices | |
AudioSynthWaveformSine voice0, voice1, voice2, voice3, voice4, voice5; | |
// A non-USB output is required for the audio engine to run. | |
AudioOutputAnalog uselessOutput; | |
// Return audio over USB | |
AudioOutputUSB audioRet; | |
// 3 Mixes are used so downmix the 6 voices to a dual-mono output. | |
AudioMixer4 mixA, mixB, mixC; | |
Voice* voices; | |
// activeVoices is a bitmask of the currently playing voices. | |
unsigned char activeVoices, i; | |
// Connect the first 3 voices to mixA | |
AudioConnection v0mA(voice0, 0, mixA, 0); | |
AudioConnection v1mA(voice1, 0, mixA, 1); | |
AudioConnection v2mA(voice2, 0, mixA, 2); | |
// Connect the last 3 voices to mixB | |
AudioConnection v3mB(voice3, 0, mixB, 0); | |
AudioConnection v4mB(voice4, 0, mixB, 1); | |
AudioConnection v5mB(voice5, 0, mixB, 2); | |
// Connect mix A and B to mix C | |
AudioConnection mAmC(mixA, 0, mixC, 0); | |
AudioConnection mBmC(mixB, 0, mixC, 1); | |
// Connect mix C to Output L and R | |
AudioConnection mCoL(mixC, 0, audioRet, 0); | |
AudioConnection mCoR(mixC, 0, audioRet, 1); | |
void setup() { | |
AudioMemory(32); | |
activeVoices = 0x00; | |
voices = (Voice*)malloc(6 * sizeof(Voice)); | |
// Serial will be used for debugging messages. | |
Serial.begin(9600); | |
// Callbacks for note handling. | |
usbMIDI.setHandleNoteOff(OnNoteOff); | |
usbMIDI.setHandleNoteOn(OnNoteOn); | |
Serial.println("Teensynth (teensy-unth) v0 @ " __FILE__); | |
//AudioSynthWaveformSine* v0 = &voice0; | |
//Serial.printf("v0 = %0x\n", voices[0].osc); | |
// Doesn't like this for some reason... not sure why :( | |
// voices[0].osc = &voice0; | |
// voices[1].osc = &voice1; | |
// voices[2].osc = &voice2; | |
// voices[3].osc = &voice3;e | |
// voices[4].osc = &voice4; | |
// voices[5].osc = &voice5; | |
pinMode(13, OUTPUT); | |
} | |
void loop() { | |
// Continuously read and handle MIDI messages. | |
usbMIDI.read(); | |
// Turn the LED on if any notes are playing | |
digitalWrite(13, activeVoices); | |
} | |
void OnNoteOn(byte channel, byte note, byte vel) { | |
// If all 6 voices are playing just return. | |
if (activeVoices == 0x3f) return; | |
for(i = 0; i < 6; i++) { | |
// Serial.printf("i = %d \t v = %01x \t a = %01x\n", i, (1<<i), (activeVoices & (1<<i))); | |
if ( (activeVoices & (1<<i)) == 0) { | |
//Serial.printf("Voice %0d on.\n", i); | |
activeVoices |= (1<<i); | |
voices[i].amp = 1; | |
voices[i].note = note; | |
voices[i].freq = noteToFreq(note); | |
/* | |
AudioSynthWaveformSine* osc = voices[i]->osc; | |
osc->amplitude(1); | |
osc->frequency(voices[i]->freq); | |
*/ | |
break; | |
} | |
} | |
showActiveNotes(); | |
//Serial.printf("Active Voices:\t\t %02x\n", activeVoices); | |
//Serial.printf("Audio Memory:\t\t %02x\n", AudioMemoryUsage()); | |
} | |
void OnNoteOff(byte channel, byte note, byte vel) { | |
for(i = 0; i < 6; i++) { | |
//Serial.printf("i = %0d \t v = %02x \t a = %02x\n", i, (1<<i), (activeVoices & (1<<i))); | |
//Serial.printf("v[i].note = %02x\n", voices[i].note); | |
if(voices[i].note == note && (activeVoices & (1<<i)) != 0 ) { | |
//Serial.printf("Voice %0d Off.", i); | |
voices[i].note = 0xff; | |
voices[i].amp = 0; | |
/* | |
AudioSynthWaveformSine* osc; | |
osc->amplitude(0); | |
*/ | |
activeVoices &= ~(1<<i); | |
break; | |
} | |
} | |
showActiveNotes(); | |
//Serial.printf("Active Voices:\t\t %02x\n", activeVoices); | |
} | |
// Debugging function which shows the currently playing notes. | |
void showActiveNotes() { | |
Serial.printf("[%10lu] Notes:\t\t", millis()); | |
for(i = 0; i < 6; i++) { | |
if ( (activeVoices & (1<<i)) != 0 ) { | |
Serial.printf("%02x ", voices[i].note); | |
} else { | |
Serial.print("-- "); | |
} | |
}; | |
Serial.print("\n"); | |
} | |
// Convert MIDI note to tonal freq. | |
// | |
// TODO: Replace this function with a lookup table of frequencies | |
// mapping the midi notes to frequencies. | |
// | |
// Formula: 440 * 2^( midi_note_val - 69) / 12) | |
float noteToFreq(byte note) { | |
float freq = 440 * pow(2, (float(note - 69) / 12)); | |
// Serial.printf("Note: %x // Freq: %.2fHz\n", note, freq); | |
return freq; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment