/* * squelette_synth_midi.ino * * Copyright 2014 Guillaume Riou, Aude Forcione-Lambert & Nicolas Hurtubise. * * This file is part of Llammas. * * Llammas is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Llammas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Llammas. If not, see . * */ #include #include #include #include #include #include #include #include #include #include "pitchbendArray.h" #include "multiFilter.h" #include "lfoFreqArray.h" #define CONTROL_RATE 256 int tableChange = 0; Oscil ncoOne(SAW256_DATA), ncoTwo(SAW256_DATA), ncoThree(SAW256_DATA); Oscil lfoOne(SIN256_DATA), lfoTwo(SIN256_DATA); ADSR adsr_envelope; ADSR adsr_filter; float lastFreq = 0; int noteBuffer[4]; int bufferIndex = 0; float pbAmount = 0.0; float lastMidiNote = 0.0; LowPassFilter lpf; int lastLfoValues[2]; Multifilter mf(0); bool lfoEffect[2][5]; //0:oscil1, 1:oscil2, 2:oscil3, 3:envelope, 4:detune void handlePitchBend(byte channel, byte lsb, byte msb) { pbAmount = pgm_read_float_near(PB_ARRAY+msb); jouerNote(lastMidiNote); } void handleNoteOn(byte channel, byte note, byte velocity) { //If velocity is 0, the noteOn message is equivalent to a noteOff message. if(velocity == 0) { handleNoteOff(channel, note, velocity); return; } for(int i = 3; i > 0; i--) { noteBuffer[i] = noteBuffer[i - 1]; } noteBuffer[0] = note; jouerNote((float)note); } void jouerNote(float note) { float totalNote = note + pbAmount; lastFreq = Q16n16_to_float(Q16n16_mtof(float_to_Q16n16(totalNote))); ncoOne.setFreq(lastFreq); lastMidiNote = note; adsr_filter.noteOn(); adsr_envelope.noteOn(); } void handleNoteOff(byte channel, byte note, byte velocity) { int i = 0; while(i < 3 && noteBuffer[i] != note) { i++; } while(i < 3) { noteBuffer[i] = noteBuffer[i + 1]; i += 1; } if(i < 4) { noteBuffer[3] = -1; } if(noteBuffer[0] != -1) { jouerNote((float)noteBuffer[0]); } else { adsr_filter.noteOff(); adsr_envelope.noteOff(); } } void setup() { MIDI.setHandleNoteOn(handleNoteOn); MIDI.setHandleNoteOff(handleNoteOff); MIDI.setHandlePitchBend(handlePitchBend); ncoOne.setFreq(400); startMozzi(CONTROL_RATE); MIDI.begin(); lfoOne.setFreq(1); for(int i = 0; i < 3; i++) { noteBuffer[i] = -1; } adsr_envelope.setADLevels(255, 210); adsr_envelope.setTimes(188, 345, 65000, 345); adsr_envelope.setSustainLevel(255); mf.setResonance(156); lastLfoValues[0] = 0; lastLfoValues[1] = 0; } int lastFilter = 0; void updateControl() { lastLfoValues[0] = lfoOne.next(); lastLfoValues[1] = lfoTwo.next(); // Oscillator detune. // int filterReading = mozziAnalogRead(0)>>8; if (lastFilter != filterReading ) { mf.changeFilter(filterReading); lastFilter = filterReading; } MIDI.read(); adsr_envelope.update(); mf.setCutoffFreq(255 * adsr_envelope.next() >> 8); } int updateAudio() { //adsr.next(); /** int osc1 = ncoOne.next(); int osc2 = ncoTwo.next(); int osc3 = ncoThree.next(); */ /** for(int i=0;i<2;i++) { if(lfoEffect[i][0] { osc1 = osc1*lastLfoValues[i]; } if(lfoEffect[i][1] { osc2 = osc2*lastLfoValues[i]; } if(lfoEffect[i][2] { osc3 = osc3*lastLfoValues[i]; } if(lfoEffect[i][3] { //envelope } if(lfoEffect[i][4] { //detune } } */ return (int) (adsr_envelope.next()*(mf.next((ncoOne.next() + ncoTwo.next() + ncoThree.next()) >> 2))) >> 2; } void loop() { audioHook(); }