[ { "type": "settings", "data": [ { "arduino": { "WriteJSONtoExportedFile": false, "ProjectName": "PhatBass", "StandardIncludeHeader": "#pragma once\n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \"types.h\"\n\n" } }, { "BiDirDataWebSocketBridge": {} }, { "workspaces": { "addToGroupAutosize": null } }, { "sidebar": {} }, { "palette": {} }, { "editor": {} }, { "devTest": {} } ] }, { "type": "tab", "id": "65451dc5.e7c4b4", "label": "LFOSources", "inputs": 0, "outputs": 2, "export": true, "isMain": false, "mainNameType": "tabName", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "LFONoiseSource_waveform1", "type": "AudioSynthWaveform", "name": "LFO1", "comment": "", "x": 210, "y": 140, "z": "65451dc5.e7c4b4", "bgColor": "#E6E0F8", "wires": [ [ "LFOSources_amp1:0" ] ] }, { "id": "LFONoiseSource_waveform2", "type": "AudioSynthWaveform", "name": "LFO2", "comment": "", "x": 210, "y": 200, "z": "65451dc5.e7c4b4", "bgColor": "#E6E0F8", "wires": [ [ "LFOSources_amp2:0" ] ] }, { "id": "LFOSources_vars1", "type": "Variables", "name": "LFOvars", "comment": "// LFO settings\r\nprivate:\r\nint lfo1Waveform = WAVEFORM_SINE;\r\nfloat lfo1Freq = 0.0;\r\nfloat lfo1Depth = 0.0;\r\nfloat lfo1PWM = 0.0;\r\n\r\nint lfo2Waveform = WAVEFORM_SINE;\r\nfloat lfo2Freq = 0.0;\r\nfloat lfo2Depth = 0.0;\r\nfloat lfo2PWM = 0.0;\r\n\r\npublic:\r\n", "x": 220, "y": 270, "z": "65451dc5.e7c4b4", "bgColor": "#DDFFBB", "wires": [] }, { "id": "LFOSources_ClassComment1", "type": "ClassComment", "name": "All voices share the same two LFOs", "x": 300, "y": 80, "z": "65451dc5.e7c4b4", "bgColor": "#CCFFCC", "wires": [] }, { "id": "LFOSources_amp1", "type": "AudioAmplifier", "name": "LFO1switch", "comment": "", "x": 355, "y": 140, "z": "65451dc5.e7c4b4", "bgColor": "#E6E0F8", "wires": [ [ "LFONoiseSource_Out1:0" ] ] }, { "id": "LFOSources_amp2", "type": "AudioAmplifier", "name": "LFO2switch", "comment": "", "x": 355, "y": 200, "z": "65451dc5.e7c4b4", "bgColor": "#E6E0F8", "wires": [ [ "LFONoiseSource_Out2:0" ] ] }, { "id": "LFOSources_constructor code1", "type": "ConstructorCode", "name": "LFOSources constructor", "comment": "updateLFO1();\r\nupdateLFO2();", "x": 390, "y": 270, "z": "65451dc5.e7c4b4", "bgColor": "#DDFFBB", "wires": [] }, { "id": "LFONoiseSource_Out1", "type": "TabOutput", "name": "LFO1Out", "comment": "", "x": 530, "y": 140, "z": "65451dc5.e7c4b4", "bgColor": "#CCE6FF", "wires": [] }, { "id": "LFONoiseSource_Out2", "type": "TabOutput", "name": "LFO2Out", "comment": "", "x": 530, "y": 200, "z": "65451dc5.e7c4b4", "bgColor": "#CCE6FF", "wires": [] }, { "id": "LFOSources_code1", "type": "Function", "name": "LFOcode", "comment": "private:\r\nvoid updateLFO1() {\r\n LFO1.begin(lfo1Waveform);\r\n LFO1.frequency(lfo1Freq);\r\n LFO1.amplitude(lfo1Depth);\r\n LFO1.pulseWidth(lfo1PWM);\r\n}\r\n\r\nvoid updateLFO2() {\r\n LFO2.begin(lfo2Waveform);\r\n LFO2.frequency(lfo2Freq);\r\n LFO2.amplitude(lfo2Depth);\r\n LFO2.pulseWidth(lfo2PWM);\r\n}\r\n\r\npublic:\r\nvoid setLFO1Waveform(int wave) {\r\n lfo1Waveform = wave;\r\n if (wave == 0) {\r\n LFO1switch.gain(0.0); \r\n }\r\n else {\r\n LFO1switch.gain(1.0);\r\n updateLFO1();\r\n }\r\n}\r\n\r\nvoid setLFO2Waveform(int wave) {\r\n lfo2Waveform = wave;\r\n if (wave == 0) {\r\n LFO2switch.gain(0.0);\r\n }\r\n else {\r\n LFO2switch.gain(1.0);\r\n updateLFO2();\r\n }\r\n}\r\n\r\nvoid setLFO1Freq(float freq) {\r\n lfo1Freq = freq;\r\n updateLFO1();\r\n}\r\n\r\nvoid setLFO2Freq(float freq) {\r\n lfo2Freq = freq;\r\n updateLFO2();\r\n}\r\n\r\nvoid setLFO1Depth(float depth) {\r\n lfo1Depth = depth;\r\n updateLFO1();\r\n}\r\n\r\nvoid setLFO2Depth(float depth) {\r\n lfo2Depth = depth;\r\n updateLFO2();\r\n}\r\n\r\nvoid setLFO1PWM(float pwm) {\r\n lfo1PWM = pwm;\r\n updateLFO1();\r\n}\r\n\r\nvoid setLFO2PWM(float pwm) {\r\n lfo2PWM = pwm;\r\n updateLFO2();\r\n}\r\n", "x": 570, "y": 270, "z": "65451dc5.e7c4b4", "bgColor": "#DDFFBB", "wires": [] }, { "type": "tab", "id": "Main", "label": "Voice", "inputs": 2, "outputs": 1, "export": true, "isMain": false, "mainNameType": "tabName", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "Voice_includeDef1", "type": "IncludeDef", "name": "\"src/GMinstrument/GMinst.h\"", "comment": "", "x": 165, "y": 135, "z": "Main", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Voice_In1", "type": "TabInput", "name": "LFOmod1", "comment": "", "x": 105, "y": 185, "z": "Main", "bgColor": "#CCE6FF", "wires": [ [ "Voice_waveformMod1:0" ] ] }, { "id": "Voice_In2", "type": "TabInput", "name": "LFOmod2", "comment": "", "x": 110, "y": 245, "z": "Main", "bgColor": "#CCE6FF", "wires": [ [ "Voice_waveformMod2:0" ] ] }, { "id": "Voice_vars1", "type": "Variables", "name": "Voicevars", "comment": "private:\r\n// modulator settings\r\nint osc1Waveform = WAVEFORM_SINE;\r\nfloat osc1Amplitude = 1.0;\r\nint osc1Octave = 0;\r\nint osc1Semis = 0;\r\nfloat osc1Detune = 1.0; // can range 1.0 to 0.85\r\nfloat osc1PB = 1.0;\r\nosc_mod_t osc1Mod = Mod_FM;\r\n\r\nint osc2Waveform = WAVEFORM_SAWTOOTH;\r\nfloat osc2Amplitude = 1.0;\r\nint osc2Octave = 0;\r\nint osc2Semis = 0;\r\nfloat osc2Detune = 1.0; // can range 1.0 to 0.85\r\nfloat osc2PB = 1.0;\r\nosc_mod_t osc2Mod = Mod_FM;\r\n\r\n// noise settings\r\nfloat noiseAmplitude = 1.0;\r\n\r\n// wavetable\r\nint waveInstrument = 0; // piano\r\nfloat waveAmplitude = 1.0;\r\n\r\n// Mixer settings\r\nfloat osc1Amp = 1.0;\r\nfloat osc2Amp = 0.0;\r\nfloat noiseAmp = 0.0;\r\nfloat waveAmp = 0.0;\r\n\r\n// ADSR envelope settings\r\nfloat envAttack = 10.5;\r\nfloat envDecay = 35;\r\nfloat envSustain = 0.5;\r\nfloat envRelease = 300;\r\n\r\npublic:\r\n", "x": 110, "y": 405, "z": "Main", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Voice_waveformMod1", "type": "AudioSynthWaveformModulated", "name": "VCO1", "comment": "", "x": 280, "y": 190, "z": "Main", "bgColor": "#E6E0F8", "wires": [ [ "Voice_amp1:0" ] ] }, { "id": "Voice_waveformMod2", "type": "AudioSynthWaveformModulated", "name": "VCO2", "comment": "", "x": 280, "y": 250, "z": "Main", "bgColor": "#E6E0F8", "wires": [ [ "Voice_amp2:0" ] ] }, { "id": "Voice_wavetable1", "type": "AudioSynthWavetable", "name": "WaveTable", "comment": "", "x": 270, "y": 300, "z": "Main", "bgColor": "#E6E0F8", "wires": [ [ "Voice_mixer4_1:2" ] ] }, { "id": "Voice_pink1", "type": "AudioSynthNoisePink", "name": "pinkNoise", "comment": "", "x": 275, "y": 350, "z": "Main", "bgColor": "#E6E0F8", "wires": [ [ "Voice_mixer4_1:3" ] ] }, { "id": "Voice_constructor code1", "type": "ConstructorCode", "name": "Voice constructor", "comment": "updateOsc1();\r\nupdateOsc2();\r\nupdateNoise();\r\nupdateMix(Mix_AllMix);\r\nupdateADSR(Env_AllADSR);", "x": 287, "y": 405, "z": "Main", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Voice_ClassComment1", "type": "ClassComment", "name": "A voice has two Osc, Noise and Wavetable. ", "x": 310, "y": 30, "z": "Main", "bgColor": "#CCFFCC", "wires": [] }, { "id": "Voice_ClassComment2", "type": "ClassComment", "name": "Each Osc are modulated by two external LFO.", "x": 320, "y": 60, "z": "Main", "bgColor": "#CCFFCC", "wires": [] }, { "id": "Voice_amp1", "type": "AudioAmplifier", "name": "VCO1switch", "comment": "", "x": 385, "y": 190, "z": "Main", "bgColor": "#E6E0F8", "wires": [ [ "Voice_mixer4_1:0" ] ] }, { "id": "Voice_amp2", "type": "AudioAmplifier", "name": "VCO2switch", "comment": "", "x": 385, "y": 250, "z": "Main", "bgColor": "#E6E0F8", "wires": [ [ "Voice_mixer4_1:1" ] ] }, { "id": "Voice_ClassComment3", "type": "ClassComment", "name": "Each voice has it's own ADSR so can be at a unique position in start/stop playing.", "x": 430, "y": 90, "z": "Main", "bgColor": "#CCFFCC", "wires": [] }, { "id": "Voice_code1", "type": "Function", "name": "Voicecode", "comment": "\r\nprivate:\r\nvoid updateMix(Mix_change_t change) {\r\n VoiceMixer.gain(0, osc1Amp); \r\n VoiceMixer.gain(1, osc2Amp);\r\n VoiceMixer.gain(2, waveAmp);\r\n VoiceMixer.gain(3, noiseAmp);\r\n //updateMixerBars(change);\r\n}\r\n\r\n\r\nvoid updateADSR(ADSR_change_t change) {\r\n ADSR.attack(envAttack);\r\n ADSR.decay(envDecay);\r\n ADSR.sustain(envSustain);\r\n ADSR.release(envRelease);\r\n //updateADSRBars(change);\r\n}\r\n\r\nvoid updateOsc1() {\r\n VCO1.begin(osc1Waveform);\r\n VCO1.amplitude(osc1Amplitude);\r\n if (osc1Mod == Mod_FM) {\r\n //TODO: consider allowing freq mod range to be changed\r\n VCO1.frequencyModulation(12);\r\n }\r\n else {\r\n //TODO: consider allowing phase mod range to be changed\r\n VCO1.phaseModulation(180);\r\n }\r\n}\r\n\r\nvoid updateOsc2() {\r\n VCO2.begin(osc2Waveform);\r\n VCO2.amplitude(osc2Amplitude);\r\n if (osc2Mod == Mod_FM) {\r\n VCO2.frequencyModulation(12);\r\n }\r\n else {\r\n VCO2.phaseModulation(180);\r\n }\r\n}\r\n\r\nvoid updateNoise() {\r\n pinkNoise.amplitude(noiseAmplitude);\r\n}\r\n\r\nvoid updateWave() {\r\n WaveTable.amplitude(waveAmplitude);\r\n WaveTable.setInstrument(*GMinst[waveInstrument]);\r\n}\r\n\r\npublic:\r\nvoid setOsc1Waveform(int wave) {\r\n osc1Waveform = wave;\r\n if (wave == 0) {\r\n VCO1switch.gain(0.0);\r\n }\r\n else {\r\n VCO1switch.gain(1.0);\r\n updateOsc1();\r\n }\r\n}\r\n\r\nvoid setOsc1Octave(int oct) {\r\n osc1Octave = oct;\r\n}\r\n\r\nvoid setOsc1Semis(int semis) {\r\n osc1Semis = semis;\r\n}\r\n\r\nvoid setOsc1Detune(float detune) {\r\n osc1Detune = detune;\r\n}\r\n\r\nvoid setOsc1PB(float PB) {\r\n osc1PB = PB;\r\n}\r\n\r\nvoid setOsc1Mod(osc_mod_t mod) {\r\n osc1Mod = mod;\r\n}\r\n\r\nvoid setOsc2Waveform(int wave) {\r\n osc2Waveform = wave;\r\n if (wave == 0) {\r\n VCO2switch.gain(0.0);\r\n }\r\n else {\r\n VCO2switch.gain(1.0);\r\n updateOsc2();\r\n }\r\n}\r\n\r\nvoid setOsc2Octave(int oct) {\r\n osc2Octave = oct;\r\n}\r\n\r\nvoid setOsc2Semis(int semis) {\r\n osc2Semis = semis;\r\n}\r\n\r\nvoid setOsc2Detune(float detune) {\r\n osc2Detune = detune;\r\n}\r\n\r\nvoid setOsc2PB(float PB) {\r\n osc2PB = PB;\r\n}\r\n\r\nvoid setOsc2Mod(osc_mod_t mod) {\r\n osc2Mod = mod;\r\n}\r\n\r\nvoid setOsc1Amp(float amp) {\r\n osc1Amp = amp;\r\n updateMix(Mix_OSC1);\r\n}\r\n\r\nvoid setOsc2Amp(float amp) {\r\n osc2Amp = amp;\r\n updateMix(Mix_OSC2);\r\n}\r\n\r\nvoid setNoiseAmp(float amp) {\r\n noiseAmp = amp;\r\n updateMix(Mix_Noise);\r\n}\r\n\r\nvoid setWaveAmp(float amp) {\r\n waveAmp = amp;\r\n updateMix(Mix_WaveTable);\r\n}\r\n\r\nvoid setADSRAttack(float attack) {\r\n envAttack = attack;\r\n updateADSR(Env_Attack);\r\n}\r\n\r\nvoid setADSRDecay(float decay) {\r\n envDecay = decay;\r\n updateADSR(Env_Decay);\r\n}\r\n\r\nvoid setADSRSustain(float sus) {\r\n envSustain = sus;\r\n updateADSR(Env_Sustain);\r\n}\r\n\r\nvoid setADSRRelease(float rel) {\r\n envRelease = rel;\r\n updateADSR(Env_Release);\r\n}\r\n", "x": 480, "y": 405, "z": "Main", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Voice_mixer4_1", "type": "AudioMixer4", "name": "VoiceMixer", "comment": "", "inputs": "4", "x": 575, "y": 270, "z": "Main", "bgColor": "#E6E0F8", "wires": [ [ "Voice_envelope1:0" ] ] }, { "id": "Voice_envelope1", "type": "AudioEffectEnvelope", "name": "ADSR", "comment": "", "x": 735, "y": 285, "z": "Main", "bgColor": "#E6E0F8", "wires": [ [ "Voice_Out1:0" ] ] }, { "id": "Voice_Out1", "type": "TabOutput", "name": "VoiceOut", "comment": "", "x": 845, "y": 285, "z": "Main", "bgColor": "#CCE6FF", "wires": [] }, { "type": "tab", "id": "5f997400.dc1cbc", "label": "FilterEffects", "inputs": 1, "outputs": 1, "export": true, "isMain": false, "mainNameType": "tabName", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "Output_In1", "type": "TabInput", "name": "InMixFilter", "comment": "", "x": 95, "y": 95, "z": "5f997400.dc1cbc", "bgColor": "#CCE6FF", "wires": [ [ "Output_mixer4_1:0", "Output_filter1:0" ] ] }, { "id": "FilterEffects_ClassComment1", "type": "ClassComment", "name": "Single filter and chorus for all voices", "x": 170, "y": 35, "z": "5f997400.dc1cbc", "bgColor": "#CCFFCC", "wires": [] }, { "id": "Output_filter1", "type": "AudioFilterStateVariable", "name": "filter1", "comment": "", "x": 265, "y": 140, "z": "5f997400.dc1cbc", "bgColor": "#E6E0F8", "wires": [ [ "Output_mixer4_1:1" ], [ "Output_mixer4_1:2" ], [ "Output_mixer4_1:3" ] ] }, { "id": "Output_dc1", "type": "AudioSynthWaveformDc", "name": "dc1", "comment": "", "x": 205, "y": 275, "z": "5f997400.dc1cbc", "bgColor": "#E6E0F8", "wires": [ [ "Output_envelope1:0" ] ] }, { "id": "FilterEffects_vars1", "type": "Variables", "name": "Filtervars", "comment": "private:\r\n// filter ADSR\r\nfloat filtEnvA = 10.5;\r\nfloat filtEnvD = 35;\r\nfloat filtEnvS = 0.5;\r\nfloat filtEnvR = 300;\r\n\r\n// filter main variables\r\nfilter_band_t filtBand = Filt_LPF;\r\nfloat filterFreq = 5000;\r\nfloat filterRes = 2.5;\r\nfloat filtDC = 1.0;\r\nint filtMod = 0;\r\n\r\n// chorus\r\nint chorusVoices;\r\n// Number of samples in each delay line\r\n// Allocate the delay lines for left and right channels\r\nshort delayline[CHORUS_DELAY_LENGTH];\r\n\r\npublic:\r\n", "x": 200, "y": 375, "z": "5f997400.dc1cbc", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Output_envelope1", "type": "AudioEffectEnvelope", "name": "FilterADSR", "comment": "", "x": 335, "y": 275, "z": "5f997400.dc1cbc", "bgColor": "#E6E0F8", "wires": [ [ "Output_amp1:0" ] ] }, { "id": "FilterEffects_constructor code1", "type": "ConstructorCode", "name": "FilterEffects constructor", "comment": "updateFiltADSR();\r\nupdateFilterBand();\r\nupdateFilter();\r\ninitChorus();\r\nupdateChorus();", "x": 325, "y": 375, "z": "5f997400.dc1cbc", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Output_mixer4_1", "type": "AudioMixer4", "name": "FilterSelect", "comment": "", "inputs": "4", "x": 470, "y": 125, "z": "5f997400.dc1cbc", "bgColor": "#E6E0F8", "wires": [ [ "Output_chorus1:0" ] ] }, { "id": "Output_amp1", "type": "AudioAmplifier", "name": "ModSwitch", "comment": "", "x": 485, "y": 275, "z": "5f997400.dc1cbc", "bgColor": "#E6E0F8", "wires": [ [ "Output_filter1:1" ] ] }, { "id": "FilterEffects_code1", "type": "Function", "name": "Filtercode", "comment": "private:\r\nvoid updateFiltADSR() {\r\n FilterADSR.attack(filtEnvA);\r\n FilterADSR.decay(filtEnvD);\r\n FilterADSR.sustain(filtEnvS);\r\n FilterADSR.release(filtEnvR);\r\n dc1.amplitude(filtDC);\r\n if (filtMod == 0) {\r\n ModSwitch.gain(0.0);\r\n }\r\n else {\r\n ModSwitch.gain(1.0);\r\n }\r\n}\r\n\r\nvoid updateFilterBand() {\r\n switch(filtBand) {\r\n case Filt_FILT_OFF:\r\n FilterSelect.gain(0, 1.00);\r\n FilterSelect.gain(1, 0);\r\n FilterSelect.gain(2, 0);\r\n FilterSelect.gain(3, 0);\r\n break;\r\n\r\n case Filt_LPF:\r\n FilterSelect.gain(0, 0);\r\n FilterSelect.gain(1, 1.0);\r\n FilterSelect.gain(2, 0);\r\n FilterSelect.gain(3, 0);\r\n break;\r\n\r\n case Filt_BPF:\r\n FilterSelect.gain(0, 0);\r\n FilterSelect.gain(1, 0);\r\n FilterSelect.gain(2, 1.0);\r\n FilterSelect.gain(3, 0);\r\n break;\r\n\r\n case Filt_HPF:\r\n FilterSelect.gain(0, 0);\r\n FilterSelect.gain(1, 0);\r\n FilterSelect.gain(2, 0);\r\n FilterSelect.gain(3, 1.0);\r\n break;\r\n }\r\n}\r\n\r\nvoid updateFilter() {\r\n filter1.frequency(filterFreq);\r\n filter1.resonance(filterRes);\r\n}\r\n\r\nvoid initChorus() {\r\n chorusVoices = 0; // off by default\r\n\r\n // Initialize the effect\r\n // address of delayline\r\n // total number of samples in the delay line\r\n // number of voices in the chorus INCLUDING the original voice\r\n if(!chorus.begin(delayline, CHORUS_DELAY_LENGTH, 6)) {\r\n Serial.println(\"AudioEffectChorus - left channel begin failed\");\r\n while(1);\r\n }\r\n}\r\n\r\nvoid updateChorus() {\r\n chorus.voices(chorusVoices);\r\n}\r\n\r\npublic:\r\nvoid setFiltAttack(float attack) {\r\n filtEnvA = attack;\r\n updateFiltADSR();\r\n}\r\n\r\nvoid setFiltDecay(float decay) {\r\n filtEnvD = decay;\r\n updateFiltADSR();\r\n}\r\n\r\nvoid setFiltSustain(float sus) {\r\n filtEnvS = sus;\r\n updateFiltADSR();\r\n}\r\n\r\nvoid setFiltRelease(float release) {\r\n filtEnvR = release;\r\n updateFiltADSR();\r\n}\r\n\r\nvoid setFiltDC(float dc) {\r\n filtDC = dc;\r\n updateFiltADSR();\r\n}\r\n\r\nvoid setFiltModulation(int mod) {\r\n filtMod = mod;\r\n updateFiltADSR();\r\n}\r\n\r\nvoid setFiltBand(filter_band_t band) {\r\n filtBand = band;\r\n updateFilterBand();\r\n}\r\n\r\nvoid setFiltFreq(float freq) {\r\n filterFreq = freq;\r\n updateFilter();\r\n}\r\n\r\nvoid setFiltRes(float res) {\r\n filterRes = res;\r\n updateFilter();\r\n}\r\n\r\nvoid setChorus(int voices) {\r\n chorusVoices = voices;\r\n updateChorus();\r\n}", "x": 560, "y": 375, "z": "5f997400.dc1cbc", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Output_chorus1", "type": "AudioEffectChorus", "name": "chorus", "comment": "", "x": 650, "y": 125, "z": "5f997400.dc1cbc", "bgColor": "#E6E0F8", "wires": [ [ "Output_Out1:0" ] ] }, { "id": "Output_Out1", "type": "TabOutput", "name": "OutMixFilter", "comment": "", "x": 800, "y": 125, "z": "5f997400.dc1cbc", "bgColor": "#CCE6FF", "wires": [] }, { "type": "tab", "id": "95654dc9.1fcd9", "label": "Arpeggiator", "inputs": 0, "outputs": 0, "export": true, "isMain": false, "mainNameType": "tabName", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "Arpeggiator_constValue1", "type": "ConstValue", "name": "NumStoredNotes", "value": "32", "valueType": "int", "x": 180, "y": 90, "z": "95654dc9.1fcd9", "bgColor": "#EB9834", "wires": [] }, { "id": "Arpeggiator_vars1", "type": "Variables", "name": "Arpvars", "comment": "// Arpeggiator\r\nprivate:\r\narp_mode_t arpMode;\r\nint arpOctave;\r\nfloat arpPeriod;\r\nbool arpLatch;\r\nfloat arpDelay;\r\nbool arpDelayActive;\r\nint arpTranspose;\r\nbyte arpNotes[NumStoredNotes]; \r\nint arpStoreIndex;\r\nint arpPlayIndex;\r\nint arpNumDown;\r\nint arpIncrement;\r\nint arpPlayOctave;\r\nint arpScaleMode;\r\n\r\nelapsedMillis lastMillis = 0;\r\n\r\npublic:", "x": 180, "y": 135, "z": "95654dc9.1fcd9", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Arpeggiator_ClassComment1", "type": "ClassComment", "name": "Can feed note (sequences) in place of input Note Handling", "x": 285, "y": 40, "z": "95654dc9.1fcd9", "bgColor": "#CCFFCC", "wires": [] }, { "id": "Arpeggiator_constructor code1", "type": "ConstructorCode", "name": "Arpeggiator constructor", "comment": "arpMode = Arp_Off;\r\narpLatch = false;\r\narpOctave = 0;\r\narpPeriod = 1000;\r\narpDelay = 0;\r\narpTranspose = 0;\r\n\r\n// checking", "x": 340, "y": 135, "z": "95654dc9.1fcd9", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Arpeggiator_code1", "type": "Function", "name": "Arpcode", "comment": "private:\r\nvoid sortNotes() {\r\n/* From Wikipedia \r\n * \r\nprocedure bubbleSort(A : list of sortable items)\r\n n := length(A)\r\n repeat\r\n newn := 0\r\n for i := 1 to n - 1 inclusive do\r\n if A[i - 1] > A[i] then\r\n swap(A[i - 1], A[i])\r\n newn := i\r\n end if\r\n end for\r\n n := newn\r\n until n ≤ 1\r\nend procedure\r\n*/\r\n int newLen;\r\n int len = arpStoreIndex + 1;\r\n#ifdef DEBUG_SORT \r\n Serial.print(\"Input = \");\r\n for (int i = 0; i < arpStoreIndex; i++) {\r\n Serial.printf(\"%d \", arpNotes[i]);\r\n }\r\n Serial.println();\r\n#endif \r\n do {\r\n newLen = 0;\r\n \r\n for (int i = 1; i < (len - 1); i++) {\r\n if (arpNotes[i - 1] > arpNotes[i]) {\r\n byte temp = arpNotes[i - 1];\r\n arpNotes[i - 1] = arpNotes[i];\r\n arpNotes[i] = temp;\r\n newLen = i + 1;\r\n }\r\n }\r\n len = newLen;\r\n } while(len > 1);\r\n}\r\n\r\npublic:\r\n\r\nstatic Arpeggiator& getInst() {\r\n static Arpeggiator instance;\r\n return instance;\r\n}\r\nstatic void update() { getInst().Iupdate(); }\r\nstatic void setArpLatch(bool latch) { getInst().IsetArpLatch(latch); } \r\nstatic void setArpMode(int value) { getInst().IsetArpMode(value); }\r\n \r\nvoid Iupdate() {\r\n if (arpMode != Arp_Off) {\r\n // play Arpeggiator notes\r\n if (arpStoreIndex != 0) { // any notes in the array to play?\r\n // are we in a post sequence delay?\r\n if ((arpDelay != 0) && (arpDelayActive == true)) {\r\n if (lastMillis > arpPeriod) {\r\n// Serial.printf(\"Osc off because lasmillis (%lu) beyond arpPeriod (%u)\", lastMillis, arpPeriod);\r\n SynthEngine::oscillatorsOff();\r\n }\r\n if (lastMillis > arpDelay) {\r\n arpDelayActive = false;\r\n Serial.println(\"Delay stop\");\r\n lastMillis = 0;\r\n }\r\n }\r\n else if (lastMillis > arpPeriod) {\r\n byte note2play;\r\n lastMillis = 0;\r\n Serial.print(\"[ \");\r\n for (int i = 0; i < arpStoreIndex; i++) {\r\n Serial.print(arpNotes[i]);\r\n if (i == arpPlayIndex) {\r\n Serial.print('*');\r\n }\r\n Serial.print(' ');\r\n }\r\n Serial.printf(\"] Octave=%u\\n\", arpPlayOctave);\r\n note2play = arpNotes[arpPlayIndex] + arpTranspose + (12 * arpPlayOctave);\r\n// Serial.println(\"Osc off because arpPeriod expired - cancel last playing note\");\r\n if (arpMode != Arp_Record) {\r\n SynthEngine::oscillatorsOff();\r\n SynthEngine::oscillatorsOn(note2play);\r\n }\r\n switch(arpMode) {\r\n case Arp_Up:\r\n case Arp_Scale:\r\n arpPlayIndex++;\r\n if (arpPlayIndex >= arpStoreIndex) {\r\n arpPlayIndex = 0;\r\n if (arpPlayOctave < arpOctave) {\r\n arpPlayOctave++;\r\n }\r\n else {\r\n arpDelayActive = true;\r\n arpPlayOctave = 0;\r\n Serial.println(\"Up: Delay start\");\r\n }\r\n }\r\n break;\r\n case Arp_Down:\r\n arpPlayIndex--;\r\n if (arpPlayIndex < 0) {\r\n arpPlayIndex = arpStoreIndex - 1;\r\n if (arpPlayOctave > 0) {\r\n arpPlayOctave--;\r\n }\r\n else {\r\n arpDelayActive = true;\r\n arpPlayOctave = arpOctave;\r\n Serial.println(\"Dn: Delay start\");\r\n }\r\n }\r\n break;\r\n case Arp_UpDown:\r\n arpPlayIndex += arpIncrement;\r\n if (arpPlayIndex >= arpStoreIndex) {\r\n if (arpPlayOctave < arpOctave) {\r\n arpPlayOctave++;\r\n arpPlayIndex = 0;\r\n }\r\n else {\r\n arpPlayIndex--;\r\n arpIncrement = -arpIncrement;\r\n arpDelayActive = true;\r\n Serial.println(\"Up*: Delay start\");\r\n }\r\n }\r\n if (arpPlayIndex < 0) {\r\n if (arpPlayOctave > 0) {\r\n arpPlayOctave--;\r\n arpPlayIndex = arpStoreIndex - 1;\r\n }\r\n else {\r\n arpPlayIndex++;\r\n arpIncrement = -arpIncrement;\r\n arpDelayActive = true;\r\n Serial.println(\"Dn*: Delay start\");\r\n }\r\n }\r\n break;\r\n case Arp_Random:\r\n arpPlayIndex = rand() % arpStoreIndex;\r\n if (arpOctave > 0) {\r\n arpPlayOctave = rand() % (arpOctave + 1);\r\n }\r\n else {\r\n arpPlayOctave = 0;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\nstatic void setArpOctave(int octave) {\r\n getInst().arpOctave = octave;\r\n}\r\n\r\nstatic void setArpPeriod(float period) {\r\n getInst().arpPeriod = period;\r\n}\r\n\r\nvoid IsetArpLatch(bool latch) {\r\n arpLatch = latch;\r\n if (latch == 0) {\r\n arpPlayIndex = 0;\r\n arpStoreIndex = 0;\r\n arpPlayOctave = 0;\r\n // Serial.println(\"Osc off because latch Off\");\r\n SynthEngine::oscillatorsOff();\r\n }\r\n}\r\n\r\nstatic void setArpDelay(float delay) {\r\n getInst().arpDelay = delay;\r\n}\r\n\r\nstatic void setArpDelayActive(bool active) {\r\n getInst().arpDelayActive = active;\r\n}\r\n\r\nstatic void setArpTranspose(int transpose) {\r\n getInst().arpTranspose = transpose;\r\n}\r\n\r\nstatic void setArpScaleMode(int n) {\r\n getInst().arpScaleMode = n;\r\n}\r\n\r\nvoid IsetArpMode(int value) {\r\n if (value == 0) {\r\n arpMode = Arp_Off;\r\n Serial.println(\"Arp Off - Osc Off\");\r\n SynthEngine::oscillatorsOff();\r\n arpStoreIndex = 0;\r\n arpPlayIndex = 0;\r\n }\r\n else if (value == 20) {\r\n arpMode = Arp_Up;\r\n Serial.println(\"Arp Up\");\r\n arpPlayIndex = 0;\r\n arpDelayActive = false;\r\n arpPlayOctave = 0;\r\n }\r\n else if (value == 40) {\r\n arpMode = Arp_Down;\r\n Serial.println(\"Arp Down\");\r\n arpPlayIndex = 0;\r\n arpDelayActive = false;\r\n arpPlayOctave = arpOctave;\r\n }\r\n else if (value == 60) {\r\n arpMode = Arp_UpDown;\r\n Serial.println(\"Arp Up/Down\");\r\n arpPlayIndex = 0;\r\n arpIncrement = 1; // start \"up\"\r\n arpDelayActive = false;\r\n arpPlayOctave = 0;\r\n }\r\n else if (value == 80) {\r\n arpMode = Arp_Random;\r\n Serial.println(\"Arp Random\");\r\n }\r\n else if (value == 100) {\r\n Serial.println(\"Arp Scales\");\r\n arpMode = Arp_Scale;\r\n arpPlayIndex = 0;\r\n arpDelayActive = false;\r\n arpPlayOctave = 0;\r\n }\r\n else if (value == 120) {\r\n Serial.println(\"Arp Record\");\r\n arpMode = Arp_Record;\r\n arpStoreIndex = 0;\r\n arpPlayIndex = 0;\r\n arpDelayActive = false;\r\n arpPlayOctave = 0;\r\n }\r\n}\r\n", "x": 520, "y": 135, "z": "95654dc9.1fcd9", "bgColor": "#DDFFBB", "wires": [] }, { "type": "tab", "id": "8ff6bbec.7eceb8", "label": "ContinuousController", "inputs": 0, "outputs": 0, "export": true, "isMain": false, "mainNameType": "tabName", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "ContinuousController_ClassComment1", "type": "ClassComment", "name": "Receives MIDI CC messages and directs to the right places", "x": 310, "y": 40, "z": "8ff6bbec.7eceb8", "bgColor": "#CCFFCC", "wires": [] }, { "id": "ContinuousController_constructor code1", "type": "ConstructorCode", "name": "CC constructor", "comment": "usbMIDI.setHandleControlChange(OnControlChange);\r\nMIDI.setHandleControlChange(OnControlChange);", "x": 325, "y": 90, "z": "8ff6bbec.7eceb8", "bgColor": "#DDFFBB", "wires": [] }, { "id": "ContinuousController_code1", "type": "Function", "name": "CCcode", "comment": "public:\r\nvoid dumpPatch() {\r\n Serial.println(\"====================================\");\r\n Serial.printf( \"OSC1: wave=%s, ampl=%.2f, octave=%d, semis=%u, detune=%.2f\\n\",\r\n waves[osc1Waveform], osc1Amplitude, osc1Octave, osc1Semis, osc1Detune);\r\n Serial.printf( \"LFO1: wave=%s, freq=%.2fHz, depth=%.2f, PWM=%.2f\\n\\n\",\r\n waves[lfo1Waveform], lfo1Freq, lfo1Depth, lfo1PWM);\r\n Serial.printf( \"OSC2: wave=%s, ampl=%.2f, octave=%d, semis=%u, detune= %.2f\\n\",\r\n waves[osc2Waveform], osc2Amplitude, osc2Octave, osc2Semis, osc2Detune);\r\n Serial.printf( \"LFO2: wave=%s, freq=%.2fHz, depth=%.2f, PWM=%.2f\\n\\n\",\r\n waves[lfo2Waveform], lfo2Freq, lfo2Depth, lfo2PWM);\r\n Serial.printf( \"Filter: band=%s, freq=%.2fHz, res=%.2f, DC=%.2f, modulated=%u\\n\\n\",\r\n bands[filtBand], filterFreq, filterRes, filtDC, filtMod);\r\n Serial.printf( \"Mix ADSR: attack=%.2f, decay=%.2f, sustain=%.2f, release=%.2f\\n\",\r\n envAttack, envDecay, envSustain, envRelease);\r\n Serial.printf( \"Filter ADSR: attack=%.2f, decay=%.2f, sustain=%.2f, release=%.2f\\n\\n\",\r\n filtEnvA, filtEnvD, filtEnvS, filtEnvR);\r\n Serial.printf( \"Mixer: osc1=%.2f, osc2=%.2f, noise=%.2f, wavetab=%.2f\\n\\n\",\r\n osc1Amp, osc2Amp, noiseAmp, waveAmp);\r\n Serial.printf( \" Arpeggiator: arpMode=%s, arpPeriod=%.2f, arpOctave=%u, arpLatch=%u, arpDelay=%.2f, arpTranspose=%d\\n\",\r\n arpModes[arpMode], arpPeriod, arpOctave, arpLatch, arpDelay, arpTranspose);\r\n Serial.println(\"====================================\");\r\n}\r\n\r\ndouble mapf(double x, double in_min, double in_max, double out_min, double out_max)\r\n{\r\n return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;\r\n}\r\n\r\nstatic void OnControlChange(byte channel, byte control /* CC num*/, byte value /* 0 .. 127 */) {\r\n int i, n;\r\n int change;\r\n float fTemp;\r\n int iTemp;\r\n Serial.printf(\"CC: %u = %u ==> \", control, value);\r\n switch(control) {\r\n case 1:\r\n Serial.println(\"Mod wheel\");\r\n break;\r\n // ====================== MIXER =====================\r\n case 75:\r\n fTemp = velocity2amplitude[value];\r\n Serial.printf(\"Mix: Osc1 amplitude = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc1Amp(fTemp);\r\n }\r\n break;\r\n\r\n case 76:\r\n fTemp = velocity2amplitude[value];\r\n Serial.printf(\"Mix: Osc2 amplitude = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc2Amp(fTemp);\r\n }\r\n break;\r\n\r\n case 77:\r\n fTemp = velocity2amplitude[value];\r\n Serial.printf(\"Mix: Wavetable amplitude = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setWaveAmp(fTemp);\r\n }\r\n break;\r\n\r\n case 102:\r\n fTemp = velocity2amplitude[value];\r\n Serial.printf(\"Mix: Noise amplitude = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setNoiseAmp(fTemp);\r\n }\r\n break;\r\n\r\n // ======================== Amp ADSR ==========================\r\n case 103:\r\n fTemp = mapf(value, 0, 127, 0.0, 3000.0);\r\n Serial.printf(\"Attack = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setADSRAttack(fTemp);\r\n }\r\n break;\r\n\r\n case 104:\r\n fTemp = mapf(value, 0, 127, 0.0, 3000.0);\r\n Serial.printf(\"Decay = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setADSRDecay(fTemp);\r\n }\r\n break;\r\n\r\n case 105:\r\n fTemp = mapf(value, 0, 127, 0.0, 1.0);\r\n Serial.printf(\"Sustain = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setADSRSustain(fTemp);\r\n }\r\n break;\r\n\r\n case 106:\r\n fTemp = mapf(value, 0, 127, 0.0, 3000.0);\r\n Serial.printf(\"Release = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setADSRRelease(fTemp);\r\n }\r\n break;\r\n\r\n // ========================= FILTER =======================\r\n case 107:\r\n {\r\n filter_band_t band;\r\n value /= 20;\r\n if (value == 0) {\r\n band = Filt_FILT_OFF;\r\n }\r\n else if (value == 1) {\r\n band= Filt_LPF;\r\n }\r\n else if (value = 2) {\r\n band= Filt_BPF;\r\n }\r\n else {\r\n band = Filt_HPF;\r\n }\r\n Serial.printf(\"Filter band = %s\\n\", bands[band]);\r\n SynthEngine::Filter.setFiltBand(band);\r\n }\r\n break;\r\n\r\n case 108:\r\n fTemp = mapf(value, 0, 127, 0, 10000);\r\n Serial.printf(\"Filter Freq = %.2fHz\\n\", fTemp);\r\n SynthEngine::Filter.setFiltFreq(fTemp);\r\n break;\r\n\r\n case 109:\r\n fTemp = mapf(value, 0, 127, 0.7, 5.0);\r\n Serial.printf(\"Resonance = %.2f\\n\", fTemp);\r\n SynthEngine::Filter.setFiltRes(fTemp);\r\n break;\r\n\r\n // =================== WAVE SHAPE ======================\r\n case 110:\r\n case 111:\r\n case 116:\r\n case 117:\r\n value /= 10;\r\n switch (value) {\r\n case 0:\r\n // nothing for now as it'll be used to disable source below\r\n break;\r\n case 1:\r\n default:\r\n change = WAVEFORM_SINE;\r\n break;\r\n case 2:\r\n change = WAVEFORM_SAWTOOTH;\r\n break;\r\n case 3:\r\n change = WAVEFORM_SAWTOOTH_REVERSE;\r\n break;\r\n case 4:\r\n change = WAVEFORM_SQUARE;\r\n break;\r\n case 5:\r\n change = WAVEFORM_TRIANGLE;\r\n break;\r\n case 6:\r\n change = WAVEFORM_SAMPLE_HOLD;\r\n break;\r\n case 7:\r\n change = WAVEFORM_ARBITRARY;\r\n break;\r\n case 8:\r\n change = WAVEFORM_PULSE;\r\n break;\r\n }\r\n Serial.printf(\"Wave: %s (\", (value == 0) ? \"Off\" : waves[change]);\r\n if (control == 110) {\r\n Serial.println(\"LFO1)\");\r\n SynthEngine::LFOs.setLFO1Waveform(change);\r\n }\r\n if (control == 111) {\r\n Serial.println(\"LFO2)\");\r\n SynthEngine::LFOs.setLFO2Waveform(change);\r\n }\r\n if (control == 116) {\r\n Serial.println(\"OSC1)\");\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc1Waveform(change);\r\n }\r\n }\r\n if (control == 117) {\r\n Serial.println(\"OSC2)\");\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc2Waveform(change);\r\n }\r\n }\r\n break;\r\n\r\n // =========================== LFO1 =====================\r\n case 112:\r\n if (value < 64) {\r\n fTemp = mapf(value, 0, 64, 0.0, 20.0); \r\n }\r\n else {\r\n fTemp = mapf(value, 64, 127, 20.0, 200.0);\r\n }\r\n Serial.printf(\"LFO1 freq = %.2fHz\\n\", fTemp);\r\n SynthEngine::LFOs.setLFO1Freq(fTemp);\r\n break;\r\n\r\n case 114:\r\n fTemp = mapf(value, 0, 127, 0.0, 0.2);\r\n Serial.printf(\"LFO1 depth = %.2f\\n\", fTemp);\r\n SynthEngine::LFOs.setLFO1Depth(ftemp);\r\n break;\r\n\r\n case 20:\r\n fTemp = mapf(value, 0, 127, 0.0, 1.0);\r\n Serial.printf(\"LFO1 PWM = %.2f\\n\", fTemp);\r\n SynthEngine::LFOs.setLFO1PWM(ftemp);\r\n break;\r\n\r\n // ===================== LFO2 ========================\r\n case 113:\r\n if (value < 64) {\r\n fTemp = mapf(value, 0, 64, 0.0, 20.0); \r\n }\r\n else {\r\n fTemp = mapf(value, 64, 127, 20.0, 200.0);\r\n }\r\n Serial.printf(\"LFO2 freq = %.2fHz\\n\", fTemp);\r\n SynthEngine::LFOs.setLFO2Freq(fTemp);\r\n break;\r\n\r\n case 115:\r\n fTemp = mapf(value, 0, 127, 0.0, 0.2);\r\n Serial.printf(\"LFO2 depth = %.2f\\n\", fTemp);\r\n SynthEngine::LFOs.setLFO2Depth(ftemp);\r\n break;\r\n\r\n case 21:\r\n fTemp = mapf(value, 0, 127, 0.0, 1.0);\r\n Serial.printf(\"LFO2 PWM = %.2f\\n\", fTemp);\r\n SynthEngine::LFOs.setLFO2PWM(ftemp);\r\n break;\r\n\r\n // ======================= OSC1 =======================\r\n case 118:\r\n fTemp = mapf(value, 0.0, 127, 0, 12);\r\n Serial.printf(\"Osc1 semis = %u\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc1Semis(fTemp);\r\n }\r\n break;\r\n\r\n case 23:\r\n // -2, -1, 0, +1, +2 octave (-24 to +24)\r\n value = (value > 48) ? 48 : value;\r\n n = (value / 12) * 12;\r\n n -= 24;\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc1Octave(n);\r\n }\r\n Serial.printf(\"Osc1 Octave: %d\\n\", n);\r\n break;\r\n\r\n case 25:\r\n fTemp = mapf(value, 0, 127, 1.0, 0.85);\r\n Serial.printf(\"Osc1 detune = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc1Detune(fTemp);\r\n }\r\n break;\r\n\r\n case 14:\r\n Serial.printf(\"Osc1 modulation = %s\\n\", value == 0 ? \"FM\" : \"PM\");\r\n // 0..63 = FM, 64..127 = PM\r\n if (value < 64) {\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc1Mod(Mod_FM);\r\n }\r\n }\r\n else {\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc1Mod(Mod_PM);\r\n }\r\n }\r\n break;\r\n\r\n // ======================= OSC2 ============================\r\n case 119:\r\n fTemp = mapf(value, 0.0, 127, 0, 12);\r\n Serial.printf(\"Osc2 semis = %u\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc2Semis(fTemp);\r\n }\r\n break;\r\n\r\n case 26:\r\n // -2, -1, 0, +1, +2 octave (-24 to +24)\r\n value = (value > 48) ? 48 : value;\r\n n = (value / 12) * 12;\r\n n -= 24;\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc2Octave(n);\r\n }\r\n Serial.printf(\"Osc1 Octave: %d\\n\", n);\r\n break;\r\n\r\n case 27:\r\n fTemp = mapf(value, 0, 127, 1.0, 0.85);\r\n Serial.printf(\"Osc1 detune = %.2f\\n\", fTemp);\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n mSynth.voice[i].setOsc2Detune(fTemp);\r\n }\r\n break;\r\n\r\n case 15:\r\n Serial.printf(\"Osc2 modulation = %s\\n\", value == 0 ? \"FM\" : \"PM\");\r\n // 0..63 = FM, 64..127 = PM\r\n if (value < 64) {\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc2Mod(Mod_FM);\r\n }\r\n }\r\n else {\r\n for (i = 0; i < NUM_VOICES; i++) {\r\n SynthEngine::voice[i].setOsc2Mod(Mod_PM);\r\n }\r\n }\r\n break;\r\n\r\n // ======================== Filter ADSR =======================\r\n case 22:\r\n fTemp = mapf(value, 0, 127, 0.0, 3000.0);\r\n Serial.printf(\"Filter Attack = %.2f\\n\", ftemp);\r\n SynthEngine::Filter.setFiltAttack(fTemp);\r\n break;\r\n\r\n case 24:\r\n fTemp = mapf(value, 0, 127, 0.0, 3000.0);\r\n Serial.printf(\"Filter Decay = %.2f\\n\", fTemp);\r\n SynthEngine::Filter.setFiltDecay(fTemp);\r\n break;\r\n\r\n case 28:\r\n fTemp = mapf(value, 0, 127, 0.0, 1.0);\r\n Serial.printf(\"Filter Sustain = %.2f\\n\", fTemp);\r\n SynthEngine::Filter.setFiltSustain(fTemp);\r\n break;\r\n\r\n case 29:\r\n fTemp = mapf(value, 0, 127, 0.0, 3000.0);\r\n Serial.printf(\"Filter Release = %.2f\\n\", fTemp);\r\n SynthEngine::Filter.setFiltRelease(fTemp);\r\n break;\r\n\r\n // ====================== FILTER ====================\r\n case 30:\r\n fTemp = mapf(value, 0, 127, -1.0, 1.0);\r\n Serial.printf(\"DC = %.2f\\n\", fTemp);\r\n SynthEngine::Filter.setFiltDC(fTemp);\r\n break;\r\n\r\n case 31:\r\n // use amp as a 0/1 switch for filter DC modulation\r\n n = (value < 64) ? 0 : 1;\r\n Serial.printf(\"Modulation = %d\\n\", n);\r\n SynthEngine::Filter.setFiltModulation(n);\r\n if (n == 0) {\r\n dumpPatch();\r\n }\r\n break;\r\n\r\n // ===================== ARPEGGIATOR ===================\r\n case 85:\r\n value /= 20;\r\n value *= 20;\r\n Arpeggiator::setArpMode(value);\r\n break;\r\n\r\n case 86:\r\n Arpeggiator::setArpOctave(value / 20);\r\n Serial.printf(\"Arp Octaves = %d\\n\", (value / 20) + 1);\r\n break;\r\n\r\n case 87:\r\n n = (value >= 64) ? 1 : 0; // 0 /1\r\n Arpeggiator::setArpOctave(n);\r\n Serial.printf(\"Arp Latch = %u\\n\", n);\r\n break;\r\n\r\n case 88:\r\n fTemp = mapf(value, 0, 127, 1200, 50); // not sure of units yet\r\n Arpeggiator::setArpPeriod(fTemp);\r\n Serial.printf(\"Arp Period = %.2f\\n\", fTemp);\r\n break;\r\n\r\n case 89:\r\n fTemp = mapf(value, 0, 127, 0, 2000);\r\n Arpeggiator::setArpDelay(fTemp);\r\n Serial.printf(\"Arp Delay = %.2f\\n\", fTemp);\r\n break;\r\n\r\n case 90:\r\n n = (int)mapf(value, 0, 127, 0, 11);\r\n Arpeggiator::setArpTranspose(n);\r\n Serial.printf(\"Arp Transpose = %u\\n\", n);\r\n break;\r\n\r\n case 92:\r\n Arpeggiator::setArpScaleMode(value);\r\n Serial.printf(\"Scale = %s\\n\", scaleModes[value].name);\r\n break;\r\n\r\n // ===================== CHORUS ====================\r\n case 91:\r\n value /= 20;\r\n value *= 20;\r\n if (value == 0) {\r\n n = 0;\r\n }\r\n else if (value == 20) {\r\n n = 2;\r\n }\r\n else if (value == 40) {\r\n n = 4;\r\n }\r\n else if (value == 60) {\r\n n = 6;\r\n }\r\n Serial.printf(\"Chorus = %u\\n\", n);\r\n SynthEngine::Filter.setChorusVoices(n);\r\n updateChorus();\r\n break;\r\n\r\n // ========================= PANIC =================\r\n case 123:\r\n // MIDI PANIC!!\r\n Arpeggiator::setArpMode(0); // off\r\n Serial.println(\"Osc off because Panic\");\r\n oscillatorsOff();\r\n break;\r\n\r\n default:\r\n // if unrecognised do nothing\r\n break;\r\n }\r\n}\r\n", "x": 480, "y": 90, "z": "8ff6bbec.7eceb8", "bgColor": "#DDFFBB", "wires": [] }, { "type": "tab", "id": "312a4458.4253ec", "label": "PitchBend", "inputs": 0, "outputs": 0, "export": true, "isMain": false, "mainNameType": "tabName", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "PitchBend_ClassComment1", "type": "ClassComment", "name": "Subscribes to MIDI PB and adjust oscillators", "x": 260, "y": 30, "z": "312a4458.4253ec", "bgColor": "#CCFFCC", "wires": [] }, { "id": "PitchBend_constructor code1", "type": "ConstructorCode", "name": "PitchBend constructor", "comment": "usbMIDI.setHandlePitchChange(onPitchChange);\r\nMIDI.setHandlePitchBend(onPitchChange);", "x": 310, "y": 80, "z": "312a4458.4253ec", "bgColor": "#DDFFBB", "wires": [] }, { "id": "PitchBend_code1", "type": "Function", "name": "PBcode", "comment": "static void onPitchChange(byte channel, int pitch) {\r\n float change = 0.0;\r\n Serial.printf(\"Pitch change: %d\\n\", pitch);\r\n if (pitch == 0) {\r\n osc1PB = 1.0;\r\n osc2PB = 1.0;\r\n }\r\n else {\r\n // pitch is -8192 to +8192 so convert that to -0.5 to +0.5\r\n change = (0.5 / 8192) * pitch;\r\n // so swing from 0.5 to 1.5\r\n osc1PB = 1.0 + change;\r\n osc2PB = 1.0 + change;\r\n }\r\n Serial.printf(\"Pitch change: %d so bend = %.05f, osc1PB = %.02f, osc2PB = %.02f\\n\", pitch, change, osc1PB, osc2PB);\r\n if (arpNumDown != 0) {\r\n // something already playing so retrigger with new freq\r\n oscillatorsOn();\r\n }\r\n}\r\n", "x": 500, "y": 80, "z": "312a4458.4253ec", "bgColor": "#DDFFBB", "wires": [] }, { "type": "tab", "id": "f32e2e0a.d7803", "label": "NoteHandling", "inputs": 0, "outputs": 0, "export": true, "isMain": false, "mainNameType": "tabName", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "NoteHandling_includeDef1", "type": "IncludeDef", "name": "\"NoteData.h\"", "comment": "", "x": 130, "y": 65, "z": "f32e2e0a.d7803", "bgColor": "#DDFFBB", "wires": [] }, { "id": "NoteHandling_ClassComment1", "type": "ClassComment", "name": "Subscribes and receives MIDI note on/off and passes on to oscillators", "x": 305, "y": 20, "z": "f32e2e0a.d7803", "bgColor": "#CCFFCC", "wires": [] }, { "id": "NoteHandling_constructor code1", "type": "ConstructorCode", "name": "NoteHandler constructor", "comment": "usbMIDI.setHandleNoteOff(OnNoteOff);\r\nusbMIDI.setHandleNoteOn(OnNoteOn);\r\nMIDI.setHandleNoteOff(OnNoteOff);\r\nMIDI.setHandleNoteOn(OnNoteOn);", "x": 325, "y": 115, "z": "f32e2e0a.d7803", "bgColor": "#DDFFBB", "wires": [] }, { "id": "NoteHandling_code1", "type": "Function", "name": "Notecode", "comment": "public:\r\n\r\nstatic void OnNoteOn(byte channel, byte note, byte velocity) {\r\n Serial.printf(\"ch: %u, note: %u, vel: %u \", channel, note, velocity);\r\n digitalWrite(LED_PIN, HIGH);\r\n if (note >= 48) {\r\n highlightKey(note, true);\r\n }\r\n arpNumDown++;\r\n if (arpMode == Arp_Off) {\r\n oscillatorsOn(note);\r\n }\r\n else if (arpStoreIndex < 20) {\r\n Serial.println(); // finish note info logging\r\n // just consider adding notes to be played to the Arp array\r\n\r\n if ((arpMode == Arp_Scale) && (arpStoreIndex != 0)) {\r\n // already playing a scale so clear all notes to allow\r\n // new one to be added\r\n arpStoreIndex = 0;\r\n arpPlayIndex = 0;\r\n arpPlayOctave = 0;\r\n }\r\n\r\n // usually just add one note to the sequence\r\n arpNotes[arpStoreIndex] = note;\r\n Serial.printf(\"Added note %u at entry %u\\n\", note, arpStoreIndex);\r\n arpStoreIndex++;\r\n\r\n // but want a whole scale if in scale mode...\r\n if (arpMode == Arp_Scale) {\r\n int currNote = note;\r\n // but if Scale mode add all the other notes of this scale...\r\n for (int n = 0; n < scaleModes[arpScaleMode].entries; n++) {\r\n currNote += scaleModes[arpScaleMode].offsets[n];\r\n arpNotes[arpStoreIndex++] = currNote;\r\n }\r\n }\r\n if (arpMode != Arp_Record) {\r\n sortNotes();\r\n }\r\n else {\r\n // in record mode we simply record everything played in order (no sort)\r\n Serial.printf(\"Playing %u while recording\\n\", note);\r\n oscillatorsOn(note);\r\n }\r\n }\r\n}\r\n\r\nstatic void OnNoteOff(byte channel, byte note, byte velocity) {\r\n if (note >= 48) {\r\n highlightKey(note, false);\r\n }\r\n digitalWrite(LED_PIN, LOW);\r\n arpNumDown--;\r\n if (!arpLatch) {\r\n // remove the off note from the array\r\n for (int i = 0; i < arpStoreIndex; i++) {\r\n if (arpNotes[i] == note) {\r\n // shuffle remaining back 1 to this slot\r\n for (int j = i + 1; j < arpStoreIndex; j++) {\r\n arpNotes[j - 1] = arpNotes[j];\r\n }\r\n // and reduce number in array.\r\n arpStoreIndex--;\r\n break;\r\n }\r\n }\r\n }\r\n// Serial.println(\"Osc off because NoteOff\");\r\n oscillatorsOff();\r\n}\r\n", "x": 505, "y": 115, "z": "f32e2e0a.d7803", "bgColor": "#DDFFBB", "wires": [] }, { "type": "tab", "id": "b0f58453.3aa3a8", "label": "ProgChange", "inputs": 0, "outputs": 0, "export": true, "isMain": false, "mainNameType": "tabName", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "ProgChange_ClassComment1", "type": "ClassComment", "name": "Subscribes to MIDI Prog Change and sets wavetable", "x": 280, "y": 30, "z": "b0f58453.3aa3a8", "bgColor": "#CCFFCC", "wires": [] }, { "id": "ProgChange_constructor code1", "type": "ConstructorCode", "name": "ProgChange constructor", "comment": "usbMIDI.setHandleProgramChange(onProgramChange);\r\nMIDI.setHandleProgramChange(onProgramChange);", "x": 350, "y": 80, "z": "b0f58453.3aa3a8", "bgColor": "#DDFFBB", "wires": [] }, { "id": "ProgChange_code1", "type": "Function", "name": "ProgChangecode", "comment": "static void onProgramChange(byte channel, byte program) {\r\n program &= 0x7F;\r\n for (int i = 0; i < NUM_VOICES; i++) {\r\n SyntheEngine::voices[i].setWaveInstrument(program); // currently so limit 0..127\r\n }\r\n Serial.printf(\"Progran change: %u = %s\\n\", program, instrumentNames[program]);\r\n}\r\n", "x": 570, "y": 80, "z": "b0f58453.3aa3a8", "bgColor": "#DDFFBB", "wires": [] }, { "type": "tab", "id": "5d3343db.fec47c", "label": "SynthEngine", "inputs": 0, "outputs": 0, "export": true, "isMain": false, "mainNameType": "main", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "Synth_includeDef1", "type": "IncludeDef", "name": "\"themixer.h\"", "comment": "", "x": 105, "y": 80, "z": "5d3343db.fec47c", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Synth_LFOSources1", "type": "LFOSources", "name": "LFOs", "x": 100, "y": 170, "z": "5d3343db.fec47c", "bgColor": "#CCFFCC", "wires": [ [ "Synth_Voice1:0" ], [ "Synth_Voice1:1" ] ] }, { "id": "Synth_vars1", "type": "Variables", "name": "Synthvars", "comment": "private:\r\nint clickCount = 0;\r\nelapsedMillis lastMillis = 0;\r\nelapsedMillis last_time = 0;\r\nlong encPos = -999;\r\nint encVal = 0;\r\n\r\nbyte currentNote;\r\n\r\npublic:\r\n", "x": 140, "y": 275, "z": "5d3343db.fec47c", "bgColor": "#DDFFBB", "wires": [] }, { "id": "SynthEngine_ClassComment1", "type": "ClassComment", "name": "Core engine of synth that ties LFOs, Oscs and Filter", "x": 230, "y": 30, "z": "5d3343db.fec47c", "bgColor": "#CCFFCC", "wires": [] }, { "id": "Synth_Voice1", "type": "Voice", "name": "voice[8]", "x": 245, "y": 170, "z": "5d3343db.fec47c", "bgColor": "#CCFFCC", "wires": [ [ "Synth_mixer1:0" ] ] }, { "id": "Synth_mixer1", "type": "AudioMixer", "name": "MixVoices", "inputs": "1", "comment": "", "x": 385, "y": 170, "z": "5d3343db.fec47c", "bgColor": "#E6E0F8", "wires": [ [ "Synth_FilterEffects1:0" ] ] }, { "id": "Synth_code1", "type": "Function", "name": "Synthcode", "comment": "static SynthEngine& getInst() {\r\n static SynthEngine instance;\r\n return instance;\r\n}\r\nstatic void update() { getInst().Iupdate(); }\r\n\r\nvoid Iupdate() {\r\n // put your main code here, to run repeatedly:\r\n usbMIDI.read();\r\n\r\n#ifdef USE_TOUCH\r\n if (ts.touched()) {\r\n int X, Y;\r\n TS_Point p = ts.getPoint();\r\n X = p.x - 231;\r\n X = map(X, 3482, 0, 0, 320);\r\n Y = p.y - 360;\r\n Y = map(Y, 3465, 0, 0, 240);\r\n tft.setFont(Arial_14);\r\n tft.fillRect(240, 5, 100, 30, ILI9341_BLACK);\r\n tft.setTextColor(ILI9341_RED);\r\n tft.setCursor(240, 5);\r\n int Aval;\r\n Aval = pointInBar(X, Y, ADSR_PANEL_X + 5, ADSR_PANEL_Y);\r\n if (Aval > 0) {\r\n tft.print(Aval);\r\n OnControlChange(1, 103, Aval);\r\n }\r\n int Dval;\r\n Dval = pointInBar(X, Y, ADSR_PANEL_X + 30, ADSR_PANEL_Y);\r\n if (Dval > 0) {\r\n tft.print(Dval);\r\n OnControlChange(1, 104, Dval);\r\n }\r\n int Sval;\r\n Sval = pointInBar(X, Y, ADSR_PANEL_X + 55, ADSR_PANEL_Y);\r\n if (Sval > 0) {\r\n tft.print(Sval);\r\n OnControlChange(1, 105, Sval);\r\n }\r\n int Rval;\r\n Rval = pointInBar(X, Y, ADSR_PANEL_X + 80, ADSR_PANEL_Y);\r\n if (Rval > 0) {\r\n tft.print(Rval);\r\n OnControlChange(1, 106, Rval);\r\n }\r\n int O1val;\r\n O1val = pointInBar(X, Y, MIX_PANEL_X + 5, MIX_PANEL_Y);\r\n if (O1val > 0) {\r\n tft.print(O1val);\r\n OnControlChange(1, 100, O1val);\r\n }\r\n int O2val;\r\n O2val = pointInBar(X, Y, MIX_PANEL_X + 30, MIX_PANEL_Y);\r\n if (O2val > 0) {\r\n tft.print(O2val);\r\n OnControlChange(1, 101, O2val);\r\n }\r\n int Nval;\r\n Nval = pointInBar(X, Y, MIX_PANEL_X + 55, MIX_PANEL_Y);\r\n if (Nval > 0) {\r\n tft.print(Nval);\r\n OnControlChange(1, 102, Nval);\r\n }\r\n }\r\n #endif\r\n\r\n if(0) {\r\n if(last_time >= 5000) {\r\n Serial.print(\"Proc = \");\r\n Serial.print(AudioProcessorUsage());\r\n Serial.print(\" (\"); \r\n Serial.print(AudioProcessorUsageMax());\r\n Serial.print(\"), Mem = \");\r\n Serial.print(AudioMemoryUsage());\r\n Serial.print(\" (\"); \r\n Serial.print(AudioMemoryUsageMax());\r\n Serial.println(\")\");\r\n last_time = 0;\r\n }\r\n }\r\n}\r\n\r\nvoid oscillatorsOn() {\r\n oscillatorsOn(currentNote);\r\n}\r\n\r\nvoid oscillatorsOn(byte playNote) {\r\n currentNote = playNote; // in case we need to retrigger after recalculating pitch bend\r\n \r\n byte note;\r\n note = playNote; \r\n\r\n note += osc1Octave; // -24, -12, 0, 12 or 24\r\n note += osc1Semis;\r\n if (note < 0) {\r\n note = 0;\r\n }\r\n if (note > 127) {\r\n note = 127;\r\n }\r\n Serial.printf(\"Osc1 note=%d (%s%u) \", note, noteNames[note %12], (note / 12) - 1);\r\n float freq = tune_frequencies2_PGM[note];\r\n freq *= osc1Detune; // mult 0.85 .. 1.0\r\n freq *= osc1PB;\r\n Serial.printf(\"so freq1 = %.2fHz, \", freq);\r\n waveformMod1.frequency(freq);\r\n\r\n wavetable1.playFrequency(freq, 127);\r\n\r\n note = playNote;\r\n note += osc2Octave; // -24, -12, 0, 12 or 24\r\n note += osc2Semis;\r\n if (note < 0) {\r\n note = 0;\r\n }\r\n if (note > 127) {\r\n note = 127;\r\n }\r\n Serial.printf(\"Osc2 note=%d (%s%u) \", note, noteNames[note %12], (note / 12) - 1);\r\n freq = tune_frequencies2_PGM[note];\r\n freq *= osc2Detune; // mult 0.85 .. 1.0\r\n freq *= osc2PB;\r\n Serial.printf(\"freq2 = %.2fHz\\n\", freq);\r\n waveformMod2.frequency(freq);\r\n // sound ADSR\r\n envelope1.noteOn();\r\n // filter ADSR\r\n envelope2.noteOn();\r\n// Serial.println(\"Both Env triggered\");\r\n}\r\n\r\nvoid oscillatorsOff() {\r\n envelope1.noteOff();\r\n envelope2.noteOff();\r\n wavetable1.stop();\r\n}\r\n", "x": 450, "y": 270, "z": "5d3343db.fec47c", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Synth_FilterEffects1", "type": "FilterEffects", "name": "Filter", "x": 540, "y": 170, "z": "5d3343db.fec47c", "bgColor": "#CCFFCC", "wires": [ [ "Synth_i2s1:0", "Synth_i2s1:1", "Synth_usb1:0", "Synth_usb1:1" ] ] }, { "id": "Synth_sgtl5000_1", "type": "AudioControlSGTL5000", "name": "sgtl5000_1", "comment": "", "x": 600, "y": 90, "z": "5d3343db.fec47c", "bgColor": "#E6E0F8", "wires": [] }, { "id": "Synth_i2s1", "type": "AudioOutputI2S", "name": "i2s1", "comment": "", "x": 775, "y": 145, "z": "5d3343db.fec47c", "bgColor": "#E6E0F8", "wires": [] }, { "id": "Synth_usb1", "type": "AudioOutputUSB", "name": "usb1", "comment": "", "x": 780, "y": 210, "z": "5d3343db.fec47c", "bgColor": "#E6E0F8", "wires": [] }, { "type": "tab", "id": "fc36cdca.24645", "label": "PhatBass", "inputs": 0, "outputs": 0, "export": true, "isMain": true, "mainNameType": "tabName", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "PhatBass_includeDef1", "type": "IncludeDef", "name": "", "comment": "", "x": 190, "y": 25, "z": "fc36cdca.24645", "bgColor": "#DDFFBB", "wires": [] }, { "id": "PhatBass_includeDef3", "type": "IncludeDef", "name": "", "comment": "", "x": 175, "y": 65, "z": "fc36cdca.24645", "bgColor": "#DDFFBB", "wires": [] }, { "id": "PhatBass_SynthEngine1", "type": "SynthEngine", "name": "unused_Synth", "x": 185, "y": 105, "z": "fc36cdca.24645", "bgColor": "#CCFFCC", "wires": [] }, { "id": "PhatBass_Arpeggiator1", "type": "Arpeggiator", "name": "unused_Arp", "x": 185, "y": 150, "z": "fc36cdca.24645", "bgColor": "#CCFFCC", "wires": [] }, { "id": "PhatBass_ContinuousController1", "type": "ContinuousController", "name": "CCHndlr", "x": 175, "y": 195, "z": "fc36cdca.24645", "bgColor": "#CCFFCC", "wires": [] }, { "id": "PhatBass_ProgChange1", "type": "ProgChange", "name": "ProgHndlr", "x": 180, "y": 240, "z": "fc36cdca.24645", "bgColor": "#CCFFCC", "wires": [] }, { "id": "PhatBass_vars1", "type": "Variables", "name": "phatBass vars", "comment": "// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC\r\nILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);\r\nXPT2046_Touchscreen ts(TOUCH_CS);\r\nEncoder enc(2,3);\r\nMIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);\r\n", "x": 195, "y": 310, "z": "fc36cdca.24645", "bgColor": "#DDFFBB", "wires": [] }, { "id": "PhatBass_includeDef4", "type": "IncludeDef", "name": "", "comment": "", "x": 355, "y": 65, "z": "fc36cdca.24645", "bgColor": "#DDFFBB", "wires": [] }, { "id": "PhatBass_PitchBend1", "type": "PitchBend", "name": "PBHndlr", "x": 310, "y": 240, "z": "fc36cdca.24645", "bgColor": "#CCFFCC", "wires": [] }, { "id": "PhatBass_code1", "type": "Function", "name": "phatBass code", "comment": "void setup() {\r\n pinMode(LED_PIN, OUTPUT);\r\n pinMode(JOY_SW, INPUT_PULLUP);\r\n Serial.begin(9600);\r\n Serial1.begin(31250);\r\n Serial.println(\"The bastard is Alive!\");\r\n MIDI.begin();\r\n ts.begin();\r\n ts.setRotation(3);\r\n tftInit(); \r\n AudioMemory(20);\r\n sgtl5000_1.enable();\r\n sgtl5000_1.volume(0.75);\r\n}\r\n\r\nvoid loop() {\r\n MIDI.read()\r\n\r\n SynthEngine::update();\r\n Arpeggiator::update();\r\n}\r\n", "x": 350, "y": 315, "z": "fc36cdca.24645", "bgColor": "#DDFFBB", "wires": [] }, { "id": "PhatBass_includeDef2", "type": "IncludeDef", "name": "", "comment": "", "x": 400, "y": 20, "z": "fc36cdca.24645", "bgColor": "#DDFFBB", "wires": [] }, { "id": "PhatBass_NoteHandling1", "type": "NoteHandling", "name": "NoteHndlr", "x": 435, "y": 240, "z": "fc36cdca.24645", "bgColor": "#CCFFCC", "wires": [] }, { "type": "tab", "id": "9c8b761f.abaf18", "label": "data_files", "inputs": 0, "outputs": 0, "export": false, "isMain": false, "mainNameType": "main", "mainNameExt": ".ino", "nodes": [], "settings": {} }, { "id": "Sheet_2_codeFile2", "type": "CodeFile", "name": "name.c", "comment": "// To give your project a unique name, this code must be\r\n// placed into a .c file (its own tab). It can not be in\r\n// a .cpp file or your main sketch (the .ino file).\r\n\r\n#include \"usb_names.h\"\r\n\r\n// Edit these lines to create your own name. The length must\r\n// match the number of characters in your custom name.\r\n\r\n#define MIDI_NAME {'P','h','a','t',' ','B','a','s','s','(','t','a','r','d',')'}\r\n#define MIDI_NAME_LEN 15\r\n\r\n// Do not change this part. This exact format is required by USB.\r\n\r\nstruct usb_string_descriptor_struct usb_string_product_name = {\r\n 2 + MIDI_NAME_LEN * 2,\r\n 3,\r\n MIDI_NAME\r\n};\r\n", "x": 125, "y": 40, "z": "9c8b761f.abaf18", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Sheet_2_codeFile4", "type": "CodeFile", "name": "NoteData.h", "comment": "// Table of midi note frequencies * 2\r\n// They are times 2 for greater accuracy, yet still fits in a word.\r\n// Generated from Excel by =ROUND(2*440/32*(2^((x-9)/12)),0) for 0\r\n#include \r\n#include \r\n#include \"defines.h\"\r\n\r\ntypedef enum {\r\n Mix_AllMix,\r\n Mix_OSC1,\r\n Mix_OSC2,\r\n Mix_Noise,\r\n Mix_WaveTable\r\n} Mix_change_t;\r\n\r\ntypedef enum {\r\n Env_AllADSR,\r\n Env_Attack,\r\n Env_Decay,\r\n Env_Sustain,\r\n Env_Release\r\n} ADSR_change_t;\r\n\r\ntypedef enum {\r\n Filt_FILT_OFF,\r\n Filt_LPF,\r\n Filt_BPF,\r\n Filt_HPF\r\n} filter_band_t;\r\n\r\ntypedef enum {\r\n Arp_Off,\r\n Arp_Up,\r\n Arp_Down,\r\n Arp_UpDown,\r\n Arp_Random,\r\n Arp_Scale,\r\n Arp_Record\r\n} arp_mode_t;\r\n\r\ntypedef enum {\r\n Mod_FM,\r\n Mod_PM\r\n} osc_mod_t;\r\n\r\ntypedef struct {\r\n uint8_t type;\r\n float offset;\r\n} keyb_t;\r\n\r\ntypedef struct {\r\n char name[20]; // max is actually 15\r\n int entries;\r\n char offsets[14]; // max actually 12\r\n} scale_chord_t;\r\n\r\n#endif\r\n", "x": 125, "y": 260, "z": "9c8b761f.abaf18", "bgColor": "#DDFFBB", "wires": [] }, { "id": "data_files_codeFile1", "type": "CodeFile", "name": "defines.h", "comment": "#ifndef _DEFINES_H_\r\n#define _DEFINES_H_\r\n\r\n#define NUM_VOICES 8\r\n\r\n#define LED_PIN 13\r\n#define TFT_DC 9\r\n#define TFT_CS 10\r\n#define TOUCH_CS 8\r\n#define JOY_SW 2\r\n#define JOY_X 8 // pin 22\r\n#define JOY_Y 5 // pin 19\r\n\r\n#define PANEL_H 140\r\n#define BAR_HEIGHT 100\r\n#define BAR_WIDTH 20\r\n#define BAR_OFFSET 15\r\n#define MIX_PANEL_X 10\r\n#define MIX_PANEL_Y 20\r\n#define MIX_PANEL_W 80\r\n#define ADSR_PANEL_X 120\r\n#define ADSR_PANEL_Y 20\r\n#define ADSR_PANEL_W 100\r\n#define KEYB_X 10\r\n#define KEYB_Y 200\r\n#define KEY_WIDTH 12\r\n\r\n#define CHORUS_DELAY_LENGTH (32*AUDIO_BLOCK_SAMPLES)\r\n\r\n#endif\r\n", "x": 120, "y": 320, "z": "9c8b761f.abaf18", "bgColor": "#DDFFBB", "wires": [] }, { "id": "data_files_codeFile2", "type": "CodeFile", "name": "themixer.h", "comment": "/* Audio Library for Teensy 3.X\r\n * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com\r\n *\r\n * Development of this audio library was funded by PJRC.COM, LLC by sales of\r\n * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop\r\n * open source software by purchasing Teensy or other PJRC products.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice, development funding notice, and this permission\r\n * notice shall be included in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n * THE SOFTWARE.\r\n */\r\n\r\n#ifndef themixer_h_\r\n#define themixer_h_\r\n\r\n#include \r\n#include \r\n\r\n//#define AudioMixer4 AudioMixer<4>\r\n\r\n#if defined(__ARM_ARCH_7EM__)\r\n\r\n#define MULTI_UNITYGAIN 65536\r\n#define MULTI_UNITYGAIN_F 65536.0f\r\n#define MAX_GAIN 32767.0f\r\n#define MIN_GAIN -32767.0f\r\n#define MULT_DATA_TYPE int32_t\r\n\r\n#elif defined(KINETISL)\r\n\r\n#define MULTI_UNITYGAIN 256\r\n#define MULTI_UNITYGAIN_F 256.0f\r\n#define MAX_GAIN 127.0f\r\n#define MIN_GAIN -127.0f\r\n#define MULT_DATA_TYPE int16_t\r\n\r\n#endif\r\n\r\ntemplate class AudioMixer : public AudioStream\r\n{\r\npublic:\r\n AudioMixer(void) : AudioStream(NN, inputQueueArray) {\r\n for (int i=0; i> 8); // overflow possible??\r\n *dst++ = signed_saturate_rshift(val, 16, 0);\r\n } while (dst < end);\r\n }\r\n }\r\n#endif\r\n\r\ntemplate void AudioMixer::gain(unsigned int channel, float gain) {\r\n if (channel >= NN) return;\r\n if (gain > MAX_GAIN) gain = MAX_GAIN;\r\n else if (gain < MIN_GAIN) gain = MIN_GAIN;\r\n multiplier[channel] = gain * MULTI_UNITYGAIN_F; // TODO: proper roundoff?\r\n}\r\n\r\ntemplate void AudioMixer::gain(float gain) {\r\n for (int i = 0; i < NN; i++) {\r\n if (gain > MAX_GAIN) gain = MAX_GAIN;\r\n else if (gain < MIN_GAIN) gain = MIN_GAIN;\r\n multiplier[i] = gain * MULTI_UNITYGAIN_F; // TODO: proper roundoff?\r\n } \r\n}\r\n\r\ntemplate void AudioMixer::update() {\r\n audio_block_t *in, *out=NULL;\r\n unsigned int channel;\r\n for (channel=0; channel < NN; channel++) {\r\n if (!out) {\r\n out = receiveWritable(channel);\r\n if (out) {\r\n int32_t mult = multiplier[channel];\r\n if (mult != MULTI_UNITYGAIN) applyGain(out->data, mult);\r\n }\r\n } else {\r\n in = receiveReadOnly(channel);\r\n if (in) {\r\n applyGainThenAdd(out->data, in->data, multiplier[channel]);\r\n release(in);\r\n }\r\n }\r\n }\r\n if (out) {\r\n transmit(out);\r\n release(out);\r\n }\r\n}\r\n// this class and function forces include \r\n// of functions applyGainThenAdd and applyGain used by the template\r\nclass DummyClass\r\n{\r\n public:\r\n virtual void dummyFunction();\r\n};\r\nvoid DummyClass::dummyFunction() {\r\n applyGainThenAdd(0, 0, 0);\r\n applyGain(0,0);\r\n \r\n}\r\n\r\n#endif", "x": 115, "y": 370, "z": "9c8b761f.abaf18", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Sheet_2_Comment2", "type": "Comment", "name": "Mainly debug strings", "comment": "", "x": 290, "y": 150, "z": "9c8b761f.abaf18", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Sheet_2_Comment1", "type": "Comment", "name": "This sets the USB device name", "comment": "This sets the USB device name", "x": 325, "y": 40, "z": "9c8b761f.abaf18", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Sheet_2_Comment5", "type": "Comment", "name": "This has midi note num to freq lookup, also non-linear volume lookup", "comment": "", "x": 310, "y": 100, "z": "9c8b761f.abaf18", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Sheet_2_Comment3", "type": "Comment", "name": "Simply header for the above", "comment": "", "x": 315, "y": 205, "z": "9c8b761f.abaf18", "bgColor": "#DDFFBB", "wires": [] }, { "id": "Sheet_2_Comment4", "type": "Comment", "name": "Mainly enums for various modules/classes", "comment": "", "x": 360, "y": 260, "z": "9c8b761f.abaf18", "bgColor": "#DDFFBB", "wires": [] } ]