BODYSEQ/examples/CFO_BODYSEQ_3buttons/CFO_BODYSEQ_3buttons.ino

466 lines
12 KiB
Arduino
Raw Normal View History

2018-12-01 12:57:32 +01:00
//______________________/\\\\\__________________________/\\\______________________________/\\\__________________________________________________________
// ____________________/\\\///__________________________\/\\\_____________________________\/\\\__________________________________________________________
// ___________________/\\\______________________________\/\\\_____________________________\/\\\_____/\\\__/\\\_______________________________/\\\\\\\\___
// _____/\\\\\\\\__/\\\\\\\\\_______/\\\\\______________\/\\\____________/\\\\\___________\/\\\____\//\\\/\\\___/\\\\\\\\\\_____/\\\\\\\\___/\\\////\\\__
// ___/\\\//////__\////\\\//______/\\\///\\\____________\/\\\\\\\\\____/\\\///\\\____/\\\\\\\\\_____\//\\\\\___\/\\\//////____/\\\/////\\\_\//\\\\\\\\\__
// __/\\\____________\/\\\_______/\\\__\//\\\___________\/\\\////\\\__/\\\__\//\\\__/\\\////\\\______\//\\\____\/\\\\\\\\\\__/\\\\\\\\\\\___\///////\\\__
// _\//\\\___________\/\\\______\//\\\__/\\\____________\/\\\__\/\\\_\//\\\__/\\\__\/\\\__\/\\\___/\\_/\\\_____\////////\\\_\//\\///////__________\/\\\__
// __\///\\\\\\\\____\/\\\_______\///\\\\\/_____________\/\\\\\\\\\___\///\\\\\/___\//\\\\\\\/\\_\//\\\\/_______/\\\\\\\\\\__\//\\\\\\\\\\________\/\\\\_
// ____\////////_____\///__________\/////_______________\/////////______\/////______\///////\//___\////________\//////////____\//////////_________\////__
// CFO BODYSEQ sequencer, 3 button version, reworked interaction, http://www.vsionhairies.info/
#define MIDI_CHANNEL 1
#include <spi4teensy3.h>
#include <EEPROM.h>
#include <CFO_BODYSEQ.h>
const int seqLed [] = {3,4,5,6,7,8,9,10};
int seqLedVal [] = {0,0,0,0,0,0,0,0};
const int statusLed1 = 13;
const int buttonPin [] = {11,12,2};
const int pot1 = A0, pot2 = A1;
const int bodySwitch [] = {A2,A3,A4,A5,A6,A7,A8,A9};
unsigned long lastPrint = millis();
boolean sequenceRunning = true;
float maxBodyReading = 0;
float maxBodyFadeout = 0.9999;
float averageNoise = 0;
int inputFreq = 10;
unsigned long lastInput = millis();
int seqStep = 0;
int seqLength = 7;
int seqNote[] = {-1,-1,0,-1,12,-1,-1,-1,-1,-1,0,-1,24,-1,-1,-1,-1,-1,0,-1,36,-1,-1,-1,-1,-1,0,-1,0,-1,-1,-1,-1,-1,0,-1,12,-1,-1,-1,-1,-1,0,-1,24,-1,-1,-1,-1,-1,0,-1,36,-1,-1,-1,-1,-1,0,-1,0,-1,-1,-1};
int activeSeq = 0, seqStart = 0, seqEnd = 7;
unsigned long lastStep = millis();
int stepTime = 200;
int baseNote = 36;
const int scale[3][7] = {
{0,2,4,5,7,9,11}, // major
{0,2,3,5,6,7,10}, // blues
{0,3,4,7,9,10,-1} // rock
};
const int scaleLength = 24;
int activeScale [scaleLength];
int bodySwitchVal [] = {0,0,0,0,0,0,0,0};
boolean bodySwitchesTouched = false;
int mode = 0;
int preset = 16;
boolean buttonState [] = {HIGH, HIGH, HIGH};
boolean buttonAction [] = {false, false, false};
int potVal1 = 0, potVal2 = 0;
boolean pot1Moved = false, pot2Moved = false, potsMoved = false;
int potNoise = 1;
boolean debug = true;
void setup() {
// We initialise the sound engine by calling Music.init() which outputs a tone
Music.init();
// Music.setSampler(true);
Music.enableEnvelope1();
Music.enableEnvelope2();
Music.getPreset(21);
Music.setEnv1Decay(36);
Music.setEnv1Sustain(0);
usbMIDI.setHandleNoteOff(OnNoteOff);
usbMIDI.setHandleNoteOn(OnNoteOn);
usbMIDI.setHandleControlChange(OnControlChange);
usbMIDI.setHandleRealTimeSystem(RealTimeSystem);
analogReadAveraging(32);
Serial.begin(9600);
delay(100);
Serial.println("hello");
pinMode(buttonPin[0], INPUT_PULLUP);
pinMode(buttonPin[1], INPUT_PULLUP);
pinMode(buttonPin[2], INPUT_PULLUP);
newActiveScale(scaleLength);
pinMode(statusLed1,OUTPUT);
for (int i = 0; i<8; i++) {
pinMode(seqLed[i], OUTPUT);
}
startupAnimation();
sampleAverageNoise();
}
void loop() {
// check for incoming USB MIDI messages
usbMIDI.read();
if (lastInput + inputFreq < millis()) {
// check user input
readPots();
readBodyswitches();
readButtons();
// general navigation
// button 0 pushed
if (buttonState[0] == LOW) {
noteInputFromBodyswitches();
}
// button 1 pushed
if (buttonState[1] == LOW) {
eraseNotesFromBodyswitches();
if (pot1Moved) {
// change sequencer speed
stepTime = map(analogRead(pot1),0,1023,1000,0);
potsMoved = false;
}
}
// button 2 pushed
if (buttonState[2] == LOW) {
changeMode();
activeSeq = mode;
if (pot2Moved) {
changePreset();
potsMoved = false;
}
if (pot1Moved) {
changeOctave();
potsMoved = false;
}
}
// button 0 and 2 pushed
if (buttonState[2] == LOW && buttonState[0] == LOW) {
int lowestSwitch = 0, highestSwitch = 0;
if (bodySwitchesTouched) {
for (int i = 0; i<8; i++) {
if (bodySwitchVal[i] > 0) {
highestSwitch = i;
}
if (bodySwitchVal[7-i] > 0) {
lowestSwitch = 7-i;
}
}
seqStart = lowestSwitch;
seqEnd = highestSwitch;
}
}
lastInput = millis();
}
if (sequenceRunning) updateSequence();
if (potsMoved) setCutoffFromPots();
}
void sampleAverageNoise() {
Serial.print("sampling average noise levels: ");
for (int i = 0; i<8; i++) {
pinMode(seqLed[i], OUTPUT);
averageNoise += analogRead(bodySwitch[i]);
}
averageNoise = averageNoise/8 + 3;
Serial.println(averageNoise);
}
void setCutoffFromPots() {
Music.setCutoff((analogRead(pot1))*64);
Music.setCutoffModAmount((analogRead(pot2))*64);
}
void updateLEDs() {
for (int i = 0; i<8; i++) {
if (seqNote[activeSeq*8+i] != -1) {
digitalWrite(seqLed[i], HIGH);
}
else {
digitalWrite(seqLed[i], LOW);
}
}
}
void newActiveScale (int length) {
Serial.println("lets make a new active scale");
int amountOfNotesInScale = 0;
for (int i = 0; i<7; i++) {
if (scale[1][i] != -1) amountOfNotesInScale++;
}
for (int i = 0; i<length+1; i++) {
int currentOctave = i/amountOfNotesInScale;
Serial.print("octave ");
Serial.print(currentOctave);
int currentNote = scale[1][i%amountOfNotesInScale];
Serial.print("\tnote ");
Serial.print(currentNote);
activeScale[i] = currentOctave*12+currentNote;
Serial.print("\tthis yields ");
Serial.println(activeScale[i]);
}
}
void eraseNotesFromBodyswitches() {
for (int i = 0; i<8; i++) {
if (bodySwitchVal[i] > 0) {
seqNote[activeSeq*8+i] = -1;
}
}
updateLEDs();
}
void noteInputFromBodyswitches() {
for (int i = 0; i<8; i++) {
if (bodySwitchVal[i] > 0) {
if (debug) Serial.print(i);
if (debug) Serial.print(": ");
if (debug) Serial.print(bodySwitchVal[i]);
int note = map(bodySwitchVal[i],0,127,0,scaleLength-1);
if (debug) Serial.print("\tnote: ");
if (debug) Serial.print(note);
seqNote[activeSeq*8+i] = activeScale[note];
if (debug) Serial.print("\tseqNote: ");
if (debug) Serial.println(seqNote[activeSeq*8+i]);
}
}
updateLEDs();
}
void readPots() {
int newPotVal1 = 1023-analogRead(pot1);
int newPotVal2 = 1023-analogRead(pot2);
potsMoved = false;
if ( (newPotVal1 < (potVal1-potNoise)) || (newPotVal1 > (potVal1+potNoise)) ) {
potVal1 = newPotVal1;
pot1Moved = true;
potsMoved = true;
}
else {
pot1Moved = false;
}
if ( (newPotVal2 < (potVal2-potNoise)) || (newPotVal2 > (potVal2+potNoise)) ) {
potVal2 = newPotVal2;
pot2Moved = true;
potsMoved = true;
}
else {
pot2Moved = false;
}
if (potsMoved) {
Serial.print("pot 1 ");
Serial.println(potVal1);
Serial.print("pot 2 ");
Serial.println(potVal2);
}
}
void changeOctave() {
// change from pot
int newOctave = map(analogRead(pot1),0,1023,-3,4);
baseNote = 36 + newOctave*12;
for (int i = 0; i<8; i++) {
if (newOctave+3 == i) {
// SoftPWMSet(seqLed[i],255);
digitalWrite(seqLed[i],HIGH);
}
else {
// SoftPWMSet(seqLed[i],0);
digitalWrite(seqLed[i],LOW);
}
}
}
void changeMode() {
// select mode with body switches
int highest = -1, highestVal = averageNoise;
for (int i=0; i<8; i++) {
if (bodySwitchVal[i] > highestVal) {
highest = i;
highestVal = bodySwitchVal[i];
}
}
if (highest != -1) {
mode = highest;
}
updateLEDs();
}
void changePreset() {
int newPreset = map(analogRead(pot2),0,1023,63,0);
if (preset != newPreset) { // only do something if preset has changed
// NB! user preset 0-16 might be empty, resulting in crazy sounds!
if (debug) Serial.print("new preset ");
if (debug) Serial.println(newPreset);
preset = newPreset;
Music.getPreset(preset);
}
}
void updateSequence() {
if (lastStep + stepTime < millis()) {
seqStep++;
if (seqStep > seqEnd) seqStep = seqStart;
int note = activeSeq*8+seqStep;
if (seqNote[note] != -1) {
Music.noteOn(baseNote+seqNote[note]);
}
lastStep = millis();
}
updateLEDs();
int blinkTime = max(stepTime/5,100);
if (lastStep + blinkTime < millis()) {
digitalWrite(seqLed[seqStep], HIGH);
}
if (lastStep + stepTime - blinkTime < millis()) {
digitalWrite(seqLed[seqStep], LOW);
}
}
void readBodyswitches() {
bodySwitchesTouched = false;
for (int i = 0; i<8; i++) {
int reading = constrain(analogRead (bodySwitch[i]),0,127);
maxBodyReading = max(maxBodyReading, reading);
if (reading > averageNoise) { // averageNoise is sampled on startup
int midiVal = map (reading, averageNoise, maxBodyReading, 0, 127);
bodySwitchVal[i] = constrain(midiVal,0,127);
bodySwitchesTouched = true;
}
else {
bodySwitchVal[i] = 0;
reading = 0;
}
seqLedVal[i] = reading*2;
}
maxBodyReading = maxBodyReading * maxBodyFadeout;
}
void printFeedback() {
for (int i = 0; i<8; i++) {
int reading = analogRead (bodySwitch[i]);
seqLedVal[i] = reading/4;
Serial.print(i);
Serial.print(": ");
Serial.print(reading);
Serial.print("\t");
}
Serial.println();
int potVal1 = analogRead(pot1);
int potVal2 = analogRead(pot2);
Serial.print(potVal1);
Serial.print("\t");
Serial.print(potVal2);
Serial.println();
}
void startupAnimation() {
digitalWrite(statusLed1, HIGH);
for (int i = 0; i<8; i++) {
digitalWrite(seqLed[i],HIGH);
delay(30);
}
for (int i = 0; i<8; i++) {
digitalWrite(seqLed[i],LOW);
delay(30);
}
for (int i = 0; i<8; i++) {
digitalWrite(seqLed[7-i],HIGH);
delay(30);
}
for (int i = 0; i<8; i++) {
digitalWrite(seqLed[7-i],LOW);
delay(30);
}
digitalWrite(statusLed1, LOW);
delay(100);
}
void readButtons() {
// buttons are active low
for (int i = 0; i<3; i++) {
if (digitalRead(buttonPin[i]) == HIGH) {
if (buttonState[i] == LOW) {
// button has just been released
buttonAction[i] = true;
if (debug) Serial.print("button ");
if (debug) Serial.print(i);
if (debug) Serial.println(" has just been released");
} else {
// button was already released, no action here
buttonAction[i] = false;
}
buttonState[i] = HIGH;
}
if (digitalRead(buttonPin[i]) == LOW) {
if (buttonState[i] == HIGH) {
// button has just been pushed
buttonAction[i] = true;
if (debug) Serial.print("button ");
if (debug) Serial.print(i);
if (debug) Serial.println(" has just been pushed");
buttonState[i] = LOW;
} else {
// button was already psuhed, no action here
buttonAction[i] = false;
}
}
}
}