/*
* 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 nco[] =
{(SAW256_DATA), (SAW256_DATA), (SAW256_DATA)};
Oscil lfoOne(SIN256_DATA),
lfoTwo(SIN256_DATA);
ADSR adsr_envelope;
ADSR adsr_filter;
int noteBuffer[4];
int bufferIndex = 0;
float pbAmount = 0.0;
float lastMidiNote = 0.0;
float oscDet[2];
LowPassFilter lpf;
int lastLfoValues[2];
Multifilter mf(0);
bool lfoEffect[2][7]; //0:oscil1, 1:oscil2, 2:oscil3, 3:envelope, 4:cutoff, 5: det osc2, 6: det osc3
int lastFilter = 0;
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);
adsr_filter.noteOn();
adsr_envelope.noteOn();
}
void jouerNote(float note) {
// Note joué sur le clavier additionnée du pitch bend.
float totalNote = note + pbAmount;
nco[0].setFreq(Q16n16_to_float(Q16n16_mtof(float_to_Q16n16(totalNote))));
for(int i = 0; i < 2; i++) {
// Note globale plus le désacordage de l'oscillateur.
float noteOscil = oscDet[i] + totalNote;
nco[i+1].setFreq(Q16n16_to_float(Q16n16_mtof(float_to_Q16n16(noteOscil))));
}
//lastFreq = Q16n16_to_float(Q16n16_mtof(float_to_Q16n16(totalNote)));
//nco[0].setFreq(lastFreq);
// nco[1].setFreq(Q16n16_to_float(Q16n16_mtof(float_to_Q16n16(totalNote+12))));
// nco[2].setFreq(lastFreq);
lastMidiNote = note;
}
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);
nco[0].setFreq(400);
nco[1].setFreq(333);
//nco[2].setFreq(300);
startMozzi(CONTROL_RATE);
MIDI.begin();
lfoOne.setFreq((float)0.3);
lfoTwo.setFreq(5);
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;
for(int i=0; i<2; i++){
for(int j=0; j<5; j++){
lfoEffect[i][j]=false;
}
}
}
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;
}
for (int i = 0; i < 2; i ++){
if(lfoEffect[i][5] || true){
oscDet[0] = pgm_read_float_near(PB_ARRAY+((lastLfoValues[i]+127)>>1));
}
if(lfoEffect[i][6]){
oscDet[1] = pgm_read_float_near(PB_ARRAY+((lastLfoValues[i]+127)>>1));
}
}
// TODO : Lire la valeur sur des knobs.
int cutoff = 255;
for (int i = 0 ; i <2 ; i++){
if(lfoEffect[i][4]){
//cutoff = (cutoff * (lastLfoValues[i]+127)) >>7;
}
}
mf.setCutoffFreq(cutoff * adsr_envelope.next() >> 8);
// Lis et traite les valeurs midi.
MIDI.read();
jouerNote(lastMidiNote);
// Update l'adsr.
adsr_envelope.update();
}
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] || true) {
//osc2 = (osc2*lastLfoValues[i])>>7;
}
if(lfoEffect[i][2] || true) {
//osc3 = (osc3*lastLfoValues[i])>>7;
}
}
int total = (osc1+osc2+osc3)>>2;
for(int i=0; i<2; i++){
if(lfoEffect[i][3] || true) {
//total = (total*lastLfoValues[i])>>7;
}
}
return (int) (adsr_envelope.next()*(mf.next(total)))>>2;
}
}
void loop() {
audioHook();
}