#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include "theMixer.h"
// GUItool: begin automatically generated code
// the following JSON string contains the whole project,
// it's included in all generated files.
// JSON string:[{"type":"settings","data":[{"arduino":{"useExportDialog":true,"IOcheckAtExport":true,"WriteJSONtoExportedFile":true,"WebServerPort":8080}},{"view":{"showWorkspaceToolbar":true,"showNodeToolTip":true,"space_width":5000,"space_height":5000,"scaleFactor":1,"showGridHminor":true,"showGridHmajor":true,"showGridVminor":true,"showGridVmajor":true,"gridHminorSize":10,"gridHmajorSize":100,"gridVminorSize":10,"gridVmajorSize":100,"snapToGrid":true,"snapToGridHsize":5,"snapToGridVsize":5,"lineCurveScale":0.75,"lineConnectionsScale":1.5,"partialRenderLinks":false}},{"palette":{"categoryHeaderTextSize":12,"onlyShowOne":true}}]},{"type":"tab","id":"4c6f22c7.190434","label":"Voice","inputs":1,"outputs":1,"export":true,"nodes":[]},{"type":"tab","id":"Main","label":"SynthMain","inputs":0,"outputs":0,"export":true,"nodes":[]},{"type":"tab","id":"5e244a75.659154","label":"SynthController","inputs":0,"outputs":0,"export":true,"nodes":[]},{"id":"SynthController_includeDef3","type":"IncludeDef","name":"<Arduino.h>","comment":"","x":160,"y":70,"z":"5e244a75.659154","bgColor":"#DDFFBB","wires":[]},{"id":"SynthMain_ClassComment1","type":"ClassComment","name":"This is the root class of any sound objects","x":250,"y":40,"z":"Main","bgColor":"#CCFFCC","wires":[]},{"id":"Voice_In1","type":"TabInput","name":"modIn","comment":"","x":60,"y":140,"z":"4c6f22c7.190434","bgColor":"#CCE6FF","wires":[["Voice_waveformMod1:0","Voice_waveformMod2:0"]]},{"id":"Voice_ClassComment1","type":"ClassComment","name":"This is a single voice with two \"generators\" and one envelope","x":280,"y":40,"z":"4c6f22c7.190434","bgColor":"#CCFFCC","wires":[]},{"id":"Main_dc1","type":"AudioSynthWaveformDc","name":"dcMod","comment":"","x":60,"y":150,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_Voice1:0"]]},{"id":"SynthController_ClassComment1","type":"ClassComment","name":"This class is the main controller of the whole project, and should not contain any Audio Nodes","x":335,"y":25,"z":"5e244a75.659154","bgColor":"#CCFFCC","wires":[]},{"id":"SynthController_includeDef1","type":"IncludeDef","name":"\"SynthMain.h\"","comment":"","x":165,"y":140,"z":"5e244a75.659154","bgColor":"#DDFFBB","wires":[]},{"id":"Main_constValue1","type":"ConstValue","name":"VOICE_COUNT","value":"32","valueType":"int","x":235,"y":105,"z":"Main","bgColor":"#EB9834","wires":[]},{"id":"Voice_waveformMod1","type":"AudioSynthWaveformModulated","name":"waveformMod1","comment":"","x":255,"y":110,"z":"4c6f22c7.190434","bgColor":"#E6E0F8","wires":[["Voice_mixer:0"]]},{"id":"Main_Voice1","type":"Voice","name":"voices[VOICE_COUNT]","x":235,"y":150,"z":"Main","bgColor":"#CCFFCC","wires":[["Main_mixer1:0"]]},{"id":"SynthController_vars1","type":"Variables","name":"SynthMain instance","comment":"SynthMain synth;","x":180,"y":180,"z":"5e244a75.659154","bgColor":"#DDFFBB","wires":[]},{"id":"Voice_waveformMod2","type":"AudioSynthWaveformModulated","name":"waveformMod2","comment":"","x":255,"y":165,"z":"4c6f22c7.190434","bgColor":"#E6E0F8","wires":[["Voice_mixer:1"]]},{"id":"Main_codeFile1","type":"CodeFile","name":"theMixer.h","comment":"/* Audio Library for Teensy 3.X\n * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com\n *\n * Development of this audio library was funded by PJRC.COM, LLC by sales of\n * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop\n * open source software by purchasing Teensy or other PJRC products.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice, development funding notice, and this permission\n * notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifndef theMixer_h_\n#define theMixer_h_\n\n#include \"Arduino.h\"\n#include \"AudioStream.h\"\n\n//#define AudioMixer4 AudioMixer<4>\n\n// the following Forward declarations \n// must be defined when we use template \n// the compiler throws some warnings that should be errors otherwise\nstatic inline int32_t signed_multiply_32x16b(int32_t a, uint32_t b); \nstatic inline int32_t signed_multiply_32x16t(int32_t a, uint32_t b);\nstatic inline int32_t signed_saturate_rshift(int32_t val, int bits, int rshift);\nstatic inline uint32_t pack_16b_16b(int32_t a, int32_t b);\nstatic inline uint32_t signed_add_16_and_16(uint32_t a, uint32_t b);\n\n// because of the template use applyGain and applyGainThenAdd functions\n// must be in this file and NOT in cpp file\n#if defined(__ARM_ARCH_7EM__)\n#define MIXER_MULTI_UNITYGAIN 65536\n#define MIXER_MULTI_UNITYGAIN_F 65536.0f\n#define MIXER_MAX_GAIN 32767.0f\n#define MIXER_MIN_GAIN -32767.0f\n#define MIXER_MULT_DATA_TYPE int32_t\n\n\tstatic void applyGain(int16_t *data, int32_t mult)\n\t{\n\t\tuint32_t *p = (uint32_t *)data;\n\t\tconst uint32_t *end = (uint32_t *)(data + AUDIO_BLOCK_SAMPLES);\n\n\t\tdo {\n\t\t\tuint32_t tmp32 = *p; // read 2 samples from *data\n\t\t\tint32_t val1 = signed_multiply_32x16b(mult, tmp32);\n\t\t\tint32_t val2 = signed_multiply_32x16t(mult, tmp32);\n\t\t\tval1 = signed_saturate_rshift(val1, 16, 0);\n\t\t\tval2 = signed_saturate_rshift(val2, 16, 0);\n\t\t\t*p++ = pack_16b_16b(val2, val1);\n\t\t} while (p < end);\n\t}\n\n\tstatic void applyGainThenAdd(int16_t *data, const int16_t *in, int32_t mult)\n\t{\n\t\tuint32_t *dst = (uint32_t *)data;\n\t\tconst uint32_t *src = (uint32_t *)in;\n\t\tconst uint32_t *end = (uint32_t *)(data + AUDIO_BLOCK_SAMPLES);\n\n\t\tif (mult == MIXER_MULTI_UNITYGAIN) {\n\t\t\tdo {\n\t\t\t\tuint32_t tmp32 = *dst;\n\t\t\t\t*dst++ = signed_add_16_and_16(tmp32, *src++);\n\t\t\t\ttmp32 = *dst;\n\t\t\t\t*dst++ = signed_add_16_and_16(tmp32, *src++);\n\t\t\t} while (dst < end);\n\t\t} else {\n\t\t\tdo {\n\t\t\t\tuint32_t tmp32 = *src++; // read 2 samples from *data\n\t\t\t\tint32_t val1 = signed_multiply_32x16b(mult, tmp32);\n\t\t\t\tint32_t val2 = signed_multiply_32x16t(mult, tmp32);\n\t\t\t\tval1 = signed_saturate_rshift(val1, 16, 0);\n\t\t\t\tval2 = signed_saturate_rshift(val2, 16, 0);\n\t\t\t\ttmp32 = pack_16b_16b(val2, val1);\n\t\t\t\tuint32_t tmp32b = *dst;\n\t\t\t\t*dst++ = signed_add_16_and_16(tmp32, tmp32b);\n\t\t\t} while (dst < end);\n\t\t}\n\t}\n\n#elif defined(KINETISL)\n#define MIXER_MULTI_UNITYGAIN 256\n#define MIXER_MULTI_UNITYGAIN_F 256.0f\n#define MIXER_MAX_GAIN 127.0f\n#define MIXER_MIN_GAIN -127.0f\n#define MIXER_MULT_DATA_TYPE int16_t\n\n\tstatic void applyGain(int16_t *data, int32_t mult)\n\t{\n\t\tconst int16_t *end = data + AUDIO_BLOCK_SAMPLES;\n\n\t\tdo {\n\t\t\tint32_t val = *data * mult;\n\t\t\t*data++ = signed_saturate_rshift(val, 16, 0);\n\t\t} while (data < end);\n\t}\n\n\tstatic void applyGainThenAdd(int16_t *dst, const int16_t *src, int32_t mult)\n\t{\n\t\tconst int16_t *end = dst + AUDIO_BLOCK_SAMPLES;\n\n\t\tif (mult == MIXER_MULTI_UNITYGAIN) {\n\t\t\tdo {\n\t\t\t\tint32_t val = *dst + *src++;\n\t\t\t\t*dst++ = signed_saturate_rshift(val, 16, 0);\n\t\t\t} while (dst < end);\n\t\t} else {\n\t\t\tdo {\n\t\t\t\tint32_t val = *dst + ((*src++ * mult) >> 8); // overflow possible??\n\t\t\t\t*dst++ = signed_saturate_rshift(val, 16, 0);\n\t\t\t} while (dst < end);\n\t\t}\n\t}\n#endif\n\ntemplate <int NN>\nclass AudioMixer : public AudioStream\n{\npublic:\n\tAudioMixer(void) : AudioStream(NN, inputQueueArray) {\n\t\tfor (int i=0; i<NN; i++) multiplier[i] = MIXER_MULTI_UNITYGAIN;\n\t}\n\t\n\tvoid update() {\n\t\taudio_block_t *in, *out=NULL;\n\t\tunsigned int channel;\n\n\t\tfor (channel=0; channel < NN; channel++) {\n\t\t\tif (!out) {\n\t\t\t\tout = receiveWritable(channel);\n\t\t\t\tif (out) {\n\t\t\t\t\tint32_t mult = multiplier[channel];\n\t\t\t\t\tif (mult != MIXER_MULTI_UNITYGAIN) applyGain(out->data, mult);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tin = receiveReadOnly(channel);\n\t\t\t\tif (in) {\n\t\t\t\t\tapplyGainThenAdd(out->data, in->data, multiplier[channel]);\n\t\t\t\t\trelease(in);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (out) {\n\t\t\ttransmit(out);\n\t\t\trelease(out);\n\t\t}\n\t}\n\t/**\n\t * this sets the individual gains\n\t * @param channel\n\t * @param gain\n\t */\n\tvoid gain(unsigned int channel, float gain) {\n\t\tif (channel >= NN) return;\n\t\tif (gain > MIXER_MAX_GAIN) gain = MIXER_MAX_GAIN;\n\t\telse if (gain < MIXER_MIN_GAIN) gain = MIXER_MIN_GAIN;\n\t\tmultiplier[channel] = gain * MIXER_MULTI_UNITYGAIN_F; // TODO: proper roundoff?\n\t}\n\t/**\n\t * set all channels to specified gain\n\t * @param gain\n\t */\n\tvoid gain(float gain) {\n\t\tfor (int i = 0; i < NN; i++)\n\t\t{\n\t\t\tif (gain > MIXER_MAX_GAIN) gain = MIXER_MAX_GAIN;\n\t\t\telse if (gain < MIXER_MIN_GAIN) gain = MIXER_MIN_GAIN;\n\t\t\tmultiplier[i] = gain * MIXER_MULTI_UNITYGAIN_F; // TODO: proper roundoff?\n\t\t} \n\t}\n\nprivate:\n\tMIXER_MULT_DATA_TYPE multiplier[NN];\n\taudio_block_t *inputQueueArray[NN];\n};\n\n#endif","x":420,"y":105,"z":"Main","bgColor":"#DDFFBB","wires":[]},{"id":"SynthController_vars3","type":"Variables","name":"btnInputVars","comment":"#define btnInEnablePin 9\r\n#define btnSustainPin 23\r\n#define btnSostenutoPin 22\r\n#define btnSoftPedalPin 21\r\nuint8_t btnSustain = 0;\r\nuint8_t btnSostenuto = 0;\r\nuint8_t btnSoftPedal = 0;\r\nuint8_t btnSustainWasPressed = 0;\r\nuint8_t btnSostenutoWasPressed = 0;\r\nuint8_t btnSoftPedalWasPressed = 0;\r\n\r\n#define btnNextInstrumentPin 20\r\nuint8_t btnNextInstrument = 0;\r\nuint8_t btnNextInstrumentWasPressed = 0;","x":160,"y":260,"z":"5e244a75.659154","bgColor":"#DDFFBB","wires":[]},{"id":"Voice_codeFile1","type":"CodeFile","name":"theMixer.h","comment":"","x":508,"y":92,"z":"4c6f22c7.190434","bgColor":"#DDFFBB","wires":[]},{"id":"SynthMain_code1","type":"Function","name":"noteOnOff","comment":"void noteOn(byte note, byte velocity)\n{\n //digitalWrite(NOTE_PRESSED_STATE_LED, HIGH); //any note \"pressed\"\n // fist checks if this note is allready playing\n // it that is the case then it \"reuses\" this \"slot\"\n // this makes sure that not all \"slots\" is filled\n // with the same playing note\n // if the MIDI keyboard is for some reason\n // not sending a noteoff (my keyboard is sometimes glitching)\n // and when sending MIDI from my computer for fast playing songs\n for (int i = 0; i < VOICE_COUNT; i++) \n {\n // first check if the note was played recently\n if (voices[i].note == note) \n {\n voices[i].noteOn(note, velocity);\n //digitalWrite(NOTE_OVERFLOWN_LED, LOW);\n return; \n }\n }\n // then if the note has not allready been played\n // // second see if there is any free \"spot\"\n for (int i = 0; i < VOICE_COUNT; i++) \n {\n if (voices[i].isNotPlaying())\n {\n voices[i].noteOn(note, velocity);\n //digitalWrite(NOTE_OVERFLOWN_LED, LOW); // clear overflown notification\n return;\n }\n }\n //digitalWrite(NOTE_OVERFLOWN_LED, HIGH); // this is a notification that there was no free spots\n}\nvoid noteOff(byte note)\n{\n //digitalWrite(NOTE_PRESSED_STATE_LED, LOW); //any note \"released\"\n for (int i = 0; i < VOICE_COUNT; i++)\n {\n if (voices[i].note == note)\n {\n voices[i].noteOff();\n return;\n }\n }\n}\nvoid activateSustain()\n{\n for (int i = 0; i < VOICE_COUNT; i++)\n {\n voices[i].isSustain = 1;\n\n }\n}\nvoid deactivateSustain()\n{\n for (int i = 0; i < VOICE_COUNT; i++)\n {\n voices[i].isSustain = 0;\n if (!voices[i].isNoteOn)\n voices[i].noteOff();\n }\n}","x":255,"y":224,"z":"Main","bgColor":"#DDFFBB","wires":[]},{"id":"Main_mixer1","type":"AudioMixer","name":"mixer","inputs":"1","comment":"","x":410,"y":150,"z":"Main","bgColor":"#E6E0F8","wires":[["i2s1:0","i2s1:1"]]},{"id":"Voice_vars1","type":"Variables","name":"noteFreqs","comment":"const float noteFreqs[128] = {8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602, 21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032, 5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85};\n","x":250,"y":240,"z":"4c6f22c7.190434","bgColor":"#DDFFBB","wires":[]},{"id":"Voice_mixer","type":"AudioMixer","name":"mixer","inputs":"2","comment":"","x":480,"y":145,"z":"4c6f22c7.190434","bgColor":"#E6E0F8","wires":[["Voice_envelope1:0"]]},{"id":"SynthController_code2","type":"Function","name":"begin function","comment":"void begin()\n{\n synth.begin();\n \n pinMode(btnSustainPin, INPUT);\n pinMode(btnSostenutoPin, INPUT);\n pinMode(btnSoftPedalPin, INPUT);\n pinMode(btnNextInstrumentPin, INPUT);\n\n pinMode(btnInEnablePin, OUTPUT);\n digitalWrite(btnInEnablePin, LOW);\n \n btnSustainWasPressed = 0;\n btnSoftPedalWasPressed = 0;\n btnSostenutoWasPressed = 0;\n btnNextInstrumentWasPressed = 0;\n}\n","x":165,"y":305,"z":"5e244a75.659154","bgColor":"#DDFFBB","wires":[]},{"id":"Voice_vars2","type":"Variables","name":"vars1","comment":"byte note = 0;\nbyte isNoteOn = 0;\nbyte isSustain = 0;","x":235,"y":275,"z":"4c6f22c7.190434","bgColor":"#DDFFBB","wires":[]},{"id":"sgtl5000_1","type":"AudioControlSGTL5000","name":"sgtl5000_1","x":595,"y":100,"z":"Main","bgColor":"#E6E0F8","wires":[]},{"id":"SynthMain_code2","type":"Function","name":"set functions","comment":"byte waveform1 = WAVEFORM_SINE;\nbyte waveform2 = WAVEFORM_SINE;\nbyte waveform1amp = 100;\nbyte waveform2amp = 100;\nconst float DIV100 = 0.01;\n \nvoid set_waveform1(byte wf)\n{\n if (wf > 8) wf = 8;\n waveform1 = wf;\n for (int i = 0; i < VOICE_COUNT; i++)\n {\n voices[i].waveformMod1.begin(wf);\n }\n}\nvoid set_waveform2(byte wf)\n{\n if (wf > 8) wf = 8;\n waveform2 = wf;\n for (int i = 0; i < VOICE_COUNT; i++)\n {\n voices[i].waveformMod2.begin(wf);\n }\n}\nvoid set_waveform1_amplitude(byte value)\n{\n if (value > 100) value = 100;\n waveform1amp = value;\n for (int i = 0; i < VOICE_COUNT; i++)\n {\n voices[i].mixer.gain(0,value*DIV100);\n }\n}\nvoid set_waveform2_amplitude(byte value)\n{\n if (value > 100) value = 100;\n waveform2amp = value;\n for (int i = 0; i < VOICE_COUNT; i++)\n {\n voices[i].mixer.gain(1, value*DIV100);\n }\n}","x":270,"y":265,"z":"Main","bgColor":"#DDFFBB","wires":[]},{"id":"SynthController_code1","type":"Function","name":"MIDI functions","comment":"\nvoid loop_task()\n{\n btnInputProcessTask();\n}\n\nvoid uartMidi_NoteOn(byte channel, byte note, byte velocity) {\n //note += KEYBOARD_NOTE_SHIFT_CORRECTION; // this is only used for my homemade keyboard\n velocity = 127 - velocity;\n synth.noteOn(note, velocity);\n \n}\n\nvoid uartMidi_NoteOff(byte channel, byte note, byte velocity) {\n //note += KEYBOARD_NOTE_SHIFT_CORRECTION; // this is only used for my homemade keyboard\n velocity = 127 - velocity;\n synth.noteOff(note);\n \n}\n\nvoid uartMidi_ControlChange(byte channel, byte control, byte value) {\n \n}\n\nvoid uartMidi_PitchBend(byte channel, int value) {\n \n}\n\nvoid usbMidi_NoteOn(byte channel, byte note, byte velocity) {\n synth.noteOn(note, velocity);\n}\n\nvoid usbMidi_NoteOff(byte channel, byte note, byte velocity) {\n synth.noteOff(note); \n}\n\nvoid usbMidi_PitchBend(byte channel, int value) {\n \n}\n\nvoid usbMidi_ControlChange(byte channel, byte control, byte value) {\n switch (control) { // cases 20-31,102-119 is undefined in midi spec\n case 64:\n if (value == 0)\n synth.deactivateSustain();\n else if (value == 127)\n synth.activateSustain();\n break;\n case 0:\n //synth.set_InstrumentByIndex(value);\n break;\n case 20: // OSC A waveform select\n synth.set_waveform1(value);\n break;\n case 21: // OSC B waveform select\n synth.set_waveform2(value);\n break;\n \n\n case 23:\n //synth.set_OSC_A_pulseWidth(value);\n break;\n case 24:\n //synth.set_OSC_B_pulseWidth(value);\n break;\n case 25:\n //synth.set_OSC_C_pulseWidth(value);\n break;\n\n case 26:\n //synth.set_OSC_A_phase(value);\n break;\n case 27:\n //synth.set_OSC_B_phase(value);\n break;\n case 28:\n //synth.set_OSC_C_phase(value);\n break;\n\n case 29:\n synth.set_waveform1_amplitude(value);\n break;\n case 30:\n synth.set_waveform2_amplitude(value);\n break;\n case 31:\n //synth.set_OSC_C_amplitude(value);\n break;\n case 32: //(\"LSB for Control 0 (Bank Select)\" @ midi spec.)\n //synth.set_OSC_D_amplitude(value);\n break;\n\n case 33: \n //synth.set_mixVoices_gains(value);\n break;\n \n case 100:\n //synth.set_envelope_delay(value);\n break;\n case 101:\n //synth.set_envelope_attack(value);\n break;\n case 102:\n //synth.set_envelope_hold(value);\n break;\n case 103:\n //synth.set_envelope_decay(value);\n break;\n case 104:\n //synth.set_envelope_sustain(value);\n break;\n case 105:\n //synth.set_envelope_release(value);\n break;\n \n case 108:\n //synth.set_OSC_A_freqMult(value);\n break;\n case 109:\n //synth.set_OSC_B_freqMult(value);\n break;\n case 110:\n //synth.set_OSC_C_freqMult(value);\n break;\n\n case 115: // set wavetable as primary (Piano mode)\n //synth.SetWaveTable_As_Primary();\n break;\n case 116:\n //synth.SetWaveForm_As_Primary();\n break;\n \n case 117: // EEPROM read settings\n //synth.EEPROM_ReadSettings();\n break;\n case 118: // EEPROM save settings\n //synth.EEPROM_SaveSettings();\n break;\n\n case 119: // get all values\n //synth.sendAllSettings();\n break;\n }\n}\n","x":165,"y":340,"z":"5e244a75.659154","bgColor":"#DDFFBB","wires":[]},{"id":"Voice_code1","type":"Function","name":"begin function","comment":"void begin()\n{\n waveformMod1.begin(WAVEFORM_SINE);\n waveformMod2.begin(WAVEFORM_SQUARE);\n \n mixer.gain(0, 0.5f);\n mixer.gain(1, 0.5f);\n}\n\n","x":260,"y":310,"z":"4c6f22c7.190434","bgColor":"#DDFFBB","wires":[]},{"id":"SynthMain_code3","type":"Function","name":"begin function","comment":"void begin()\n{\n for (int i = 0; i < VOICE_COUNT; i++)\n {\n voices[i].begin();\n }\n mixer.gain(1.0f/(float)VOICE_COUNT);\n dcMod.amplitude(0.0f);\n}\n","x":270,"y":305,"z":"Main","bgColor":"#DDFFBB","wires":[]},{"id":"i2s1","type":"AudioOutputI2S","name":"i2s1","x":600,"y":150,"z":"Main","bgColor":"#E6E0F8","wires":[]},{"id":"SynthController_code3","type":"Function","name":"btnInput function","comment":"\r\nvoid btnInputProcessTask(void)\r\n{\r\n btnSustain = digitalRead(btnSustainPin);\r\n btnSostenuto = digitalRead(btnSostenutoPin);\r\n btnSoftPedal = digitalRead(btnSoftPedalPin);\r\n btnNextInstrument = digitalRead(btnNextInstrumentPin);\r\n\r\n // Sustain pedal\r\n if ((btnSustain == LOW) && (btnSustainWasPressed == 0))\r\n {\r\n btnSustainWasPressed = 1;\r\n usbMIDI.sendControlChange(0x40, 0x7F, 0x00);\r\n synth.activateSustain();\r\n }\r\n else if ((btnSustain == HIGH) && (btnSustainWasPressed == 1))\r\n {\r\n btnSustainWasPressed = 0;\r\n usbMIDI.sendControlChange(0x40, 0x00, 0x00);\r\n synth.deactivateSustain();\r\n }\r\n // Sostenuto Pedal\r\n if ((btnSostenuto == LOW) && (btnSostenutoWasPressed == 0))\r\n {\r\n btnSostenutoWasPressed = 1;\r\n usbMIDI.sendControlChange(0x42, 0x7F, 0x00);\r\n }\r\n else if ((btnSostenuto == HIGH) && (btnSostenutoWasPressed == 1))\r\n {\r\n btnSostenutoWasPressed = 0;\r\n usbMIDI.sendControlChange(0x42, 0x00, 0x00);\r\n }\r\n // Soft Pedal\r\n if ((btnSoftPedal == LOW) && (btnSoftPedalWasPressed == 0))\r\n {\r\n btnSoftPedalWasPressed = 1;\r\n usbMIDI.sendControlChange(0x43, 0x7F, 0x00);\r\n }\r\n else if ((btnSoftPedal == HIGH) && (btnSoftPedalWasPressed == 1))\r\n {\r\n btnSoftPedalWasPressed = 0;\r\n usbMIDI.sendControlChange(0x43, 0x00, 0x00);\r\n }\r\n // Next Instrument button\r\n if ((btnNextInstrument == LOW) && (btnNextInstrumentWasPressed == 0))\r\n {\r\n btnNextInstrumentWasPressed = 1;\r\n // if (synth.currentWTinstrument == (InstrumentCount - 1)) synth.currentWTinstrument = 0;\r\n // else synth.currentWTinstrument++;\r\n // synth.set_InstrumentByIndex(synth.currentWTinstrument);\r\n // usbMIDI.sendControlChange(0, synth.currentWTinstrument, 0x00);\r\n }\r\n else if ((btnNextInstrument == HIGH) && (btnNextInstrumentWasPressed == 1))\r\n {\r\n btnNextInstrumentWasPressed = 0;\r\n }\r\n}","x":170,"y":375,"z":"5e244a75.659154","bgColor":"#DDFFBB","wires":[]},{"id":"Voice_envelope1","type":"AudioEffectEnvelope","name":"envelope","comment":"","x":650,"y":145,"z":"4c6f22c7.190434","bgColor":"#E6E0F8","wires":[["Voice_Out1:0"]]},{"id":"Voice_code2","type":"Function","name":"note on/off","comment":"/*\n * this takes care of all the tasks that\n * needs to be taken care of when doing\n * a note on/off\n */\n \nvoid noteOn(byte Note, byte velocity)\n{\n float newAmp = 0.0f;\n if (Note >= sizeof(noteFreqs)) return;\n \n note = Note;\n isNoteOn = 1;\n \n waveformMod1.frequency(noteFreqs[Note]);\n waveformMod2.frequency(noteFreqs[Note]);\n \n newAmp = (float)velocity*(1.0f / 127.0f);\n waveformMod1.amplitude(newAmp);\n waveformMod2.amplitude(newAmp);\n \n envelope.noteOn();\n}\n\nvoid noteOff()\n{\n isNoteOn = 0;\n if (!isSustain)\n {\n envelope.noteOff();\n }\n}\n\nbool isNotPlaying()\n{\n if (!envelope.isActive())\n return true;\n else\n return false;\n}","x":250,"y":345,"z":"4c6f22c7.190434","bgColor":"#DDFFBB","wires":[]},{"id":"Voice_Out1","type":"TabOutput","name":"Out1","comment":"","x":805,"y":145,"z":"4c6f22c7.190434","bgColor":"#cce6ff","wires":[]}]
/**
* This is a single voice with two "generators" and one envelope
*/
class Voice
{
public:
const float noteFreqs[128] = {8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602, 21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032, 5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85};
byte note = 0;
byte isNoteOn = 0;
byte isSustain = 0;
AudioSynthWaveformModulated waveformMod1;
AudioSynthWaveformModulated waveformMod2;
AudioMixer<2> mixer;
AudioEffectEnvelope envelope;
AudioConnection *patchCord[3]; // total patchCordCount:3 including array typed ones.
Voice() // constructor (this is called when class-object is created)
{
int pci = 0; // used only for adding new patchcords
patchCord[pci++] = new AudioConnection(waveformMod1, 0, mixer, 0);
patchCord[pci++] = new AudioConnection(waveformMod2, 0, mixer, 1);
patchCord[pci++] = new AudioConnection(mixer, 0, envelope, 0);
}
void begin()
{
waveformMod1.begin(WAVEFORM_SINE);
waveformMod2.begin(WAVEFORM_SQUARE);
mixer.gain(0, 0.5f);
mixer.gain(1, 0.5f);
}
/*
* this takes care of all the tasks that
* needs to be taken care of when doing
* a note on/off
*/
void noteOn(byte Note, byte velocity)
{
float newAmp = 0.0f;
if (Note >= sizeof(noteFreqs)) return;
note = Note;
isNoteOn = 1;
waveformMod1.frequency(noteFreqs[Note]);
waveformMod2.frequency(noteFreqs[Note]);
newAmp = (float)velocity*(1.0f / 127.0f);
waveformMod1.amplitude(newAmp);
waveformMod2.amplitude(newAmp);
envelope.noteOn();
}
void noteOff()
{
isNoteOn = 0;
if (!isSustain)
{
envelope.noteOff();
}
}
bool isNotPlaying()
{
if (!envelope.isActive())
return true;
else
return false;
}
};
// GUItool: end automatically generated code