Created
November 18, 2021 02:59
-
-
Save Ghillermo/753d66df96c8d02061e28cf1aca5dbbc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <MIDI.h> | |
#include <FastLED.h> | |
#include "EncoderStepCounter.h" | |
//PINES EN USO: | |
#define LEDPIN 9// Led Ring | |
//BOTONERA: | |
#define PREV A0 //Siguiente pista | |
#define NEXT A1 //Anterior pista | |
#define NOTEADD A6 //Subir semitono | |
#define NOTEDEC A7 //Bajar semitono | |
#define OFFSETADD A5 //Rotación horaria | |
#define OFFSETDEC A4 //Rotación antihoraria | |
#define NUMBERADD A2 //Más notas | |
#define NUMBERDEC A3 //Menos notas | |
//ENCODER | |
//ENCODER | |
#define ENCODER_PIN1 2 //PIN CLOCK | |
#define ENCODER_INT1 digitalPinToInterrupt(ENCODER_PIN1) | |
#define ENCODER_PIN2 3 //PIN DATA | |
#define ENCODER_INT2 digitalPinToInterrupt(ENCODER_PIN2) | |
EncoderStepCounter encoder(ENCODER_PIN1, ENCODER_PIN2, HALF_STEP); | |
#define ENC_SW 4 | |
//Valores y globales: | |
#define DELAYVAL 200 // Time (in milliseconds) to pause between pixels | |
#define BPM 120 | |
#define MIDI_VELOCITY 123 //El CC midi 123 es la intensidad, la reduciremos a cero cuando queramos silencio | |
#define NUM_LEDS 16 | |
#define STEPS 16 | |
int Delay = 15000 / BPM; | |
MIDI_CREATE_DEFAULT_INSTANCE(); | |
byte Pista = 0; | |
byte Paso = 0; | |
CRGBArray<NUM_LEDS> leds; | |
class Track { //Clase track. El secuenciador lleva una serie de tracks superpuestos. | |
private: | |
byte Note; //Tono | |
byte Offset; //Rotación | |
byte Number; //Número de notas | |
unsigned int Euclidean; //Distribución euclídea de las notas | |
public: | |
unsigned int rotateBitShiftRight(unsigned int chunk, byte rotation) {//bitshift but trim part is parsed to the opposite side: | |
chunk = (chunk >> rotation) | (chunk << (16 - rotation)); //Suma lógica (OR) del valor con bitshift desde LSB y complementaria desde MSB | |
return chunk; | |
} | |
unsigned int rotateBitShiftLeft(unsigned int chunk, byte rotation) { | |
chunk = (chunk << rotation) | (chunk >> (16 - rotation)); //Suma lógica (OR) del valor con bitshift desde LSB y complementaria desde MSB | |
return chunk; | |
} | |
void setTrack() { //Constructot | |
Note = 78; //C3 | |
Offset = 0; | |
Number = 0; | |
Euclidean = 0b0000000000000000; | |
} | |
void populateEuclidean() { //Rellena un patrón, cargándolo de la memoria del programa. | |
const unsigned int euclideanPatterns[17] = { //Precalculated Euclid patterns | |
0b0000000000000000, | |
0b1000000000000000, | |
0b1000000010000000, | |
0b1000010000100000, | |
0b1000100010001000, | |
0b1001001001001000, | |
0b1001010010010100, | |
0b1001010100101010, | |
0b1010101010101010, | |
0b1011010101101010, | |
0b1011010110110101, | |
0b1011011011011011, | |
0b1011101110111011, | |
0b1011110111101111, | |
0b1011111110111111, | |
0b1111111111111110, | |
0b1111111111111111 | |
}; | |
Euclidean = rotateBitShiftRight(euclideanPatterns[Number], Offset); //Rotated to Offset value | |
} | |
void addOffset() { | |
if ( Offset > 15 ) { | |
Offset = 0; | |
} else { | |
Offset++; | |
} | |
Euclidean = rotateBitShiftRight( Euclidean , 1 ); | |
} | |
void decOffset() { | |
if (Offset > 0) { | |
Offset--; | |
} else { | |
Offset = 15; | |
} | |
Euclidean = rotateBitShiftLeft( Euclidean , 1 ); | |
} | |
void addNumber() { | |
if (Number < STEPS) { | |
Number++; | |
} | |
else { | |
Number = 0; | |
} | |
populateEuclidean(); | |
} | |
void decNumber() { | |
if ( Number > 0) { | |
Number--; | |
} | |
else { | |
Number = STEPS; | |
} | |
populateEuclidean(); | |
} | |
void addNote() { | |
Note++; | |
} | |
void decNote() { | |
Note--; | |
} | |
byte getNote() { | |
return Note; | |
} | |
unsigned int getEuclidean() { | |
return Euclidean; | |
} | |
}; | |
Track track[6]; //Creamos un array de 6 tracks. | |
class Anillo { //Un Anillo es un secuenciador con leds que toca notas. | |
private: | |
byte Output[STEPS];//array 16 colores | |
byte Posicion;//posición del puntero | |
byte ColorActual;//color puntero | |
byte Anterior; //Ultima nota tocada | |
public: | |
void setAnillo() { | |
for (int i = 0; i < STEPS; i++) { | |
Output[i] = 0; | |
} | |
Posicion = 0; | |
ColorActual = 0; | |
} | |
void setAnillo(byte pos, byte col) { | |
Posicion = pos; | |
ColorActual = col; | |
} | |
voidSetPosicion(byte val) { | |
Posicion = val; | |
} | |
void crearFondo() { //Calcula la suma aleatoria de los 6 patrones. | |
for (int i = 15; i >= 0; i--) { | |
byte posibilidades[6] = {0, 0, 0, 0, 0, 0,}; | |
byte contador = 0; | |
for (int j = 0; j < 6; j++) { | |
if (bitRead(track[j].getEuclidean(), i)) { | |
//Serial.print("1-"); | |
posibilidades[contador] = track[j].getNote(); | |
contador++; | |
} | |
} | |
if (contador > 0) { | |
Output[i] = posibilidades[random(contador)]; | |
leds[i] = CHSV(map(Output[i], 60, 106, 0, 255), 250, 100); | |
} | |
else { | |
leds[i] = CRGB::Black; | |
Output[i] = 0; | |
//Serial.print("0-"); | |
} | |
} | |
} | |
void mostrarPatronActual() { //Muestra con más brillo el patrón seleccionado. | |
for (int i = 0; i < 16; i++) { | |
if ( bitRead(track[Pista].getEuclidean(), i)) { | |
leds[i].maximizeBrightness(150); | |
} | |
} | |
} | |
void crearPuntero() { //Marca el paso actual | |
setAnillo(Paso, CRGB::Orange); | |
leds[Posicion] = CRGB::Orange; | |
} | |
//borrar | |
void borrar() { | |
FastLED.clear(); | |
} | |
//mostrar | |
void mostrar() { //Necesario para que se actualice la info de los leds. | |
FastLED.show(); | |
} | |
void actualiza(byte val) { //Rutina que actualiza la pantalla en cada beat. | |
borrar(); | |
crearFondo(); | |
crearPuntero(); | |
mostrarPatronActual(); | |
mostrar(); | |
} | |
void silencio() { | |
MIDI.sendNoteOff(Anterior, 0, 1); | |
//MIDI.sendControlChange(MIDI_VELOCITY, 0, 1); | |
} | |
void toca(byte val) { | |
if (Output[val] != 0) { | |
MIDI.sendNoteOn(Output[val], 100, 1); | |
Anterior = Output[val]; | |
} | |
} | |
}; | |
Anillo seq; | |
void botones() { | |
static byte boton = 0; | |
static byte i = A0; | |
static byte contador = 0; | |
const int Theshold = 900; | |
const byte Debounce = 10; | |
static unsigned long int ultimaComprobacion = 0; | |
if (boton == 0) { | |
if (contador > Debounce) { | |
//Serial.print(i); | |
//Serial.print(" - "); | |
//Serial.println(contador); | |
contador = 0; | |
boton = i; | |
return; | |
} | |
else if (analogRead(i) > Theshold) { | |
if ((millis() - ultimaComprobacion) > 1) | |
{ | |
//Serial.print(analogRead(i)); | |
contador ++; | |
//Serial.print(contador); | |
//Serial.print(" "); | |
ultimaComprobacion = millis(); | |
} | |
} | |
else { | |
contador = 0; | |
i++; | |
if (i > A7) { | |
i = A0; | |
} | |
} | |
} else if (analogRead(boton) > Theshold) { | |
return; //No realiza la acción hasta soltar el boton. | |
} | |
else { | |
switch (boton) { | |
case PREV: (Pista == 0) ? Pista = 5 : Pista--; break; | |
case NEXT: (Pista == 5) ? Pista = 0 : Pista++; break; | |
case OFFSETADD: track[Pista].addOffset(); break; | |
case OFFSETDEC: track[Pista].decOffset(); break; | |
case NUMBERADD: track[Pista].addNumber(); break; | |
case NUMBERDEC: track[Pista].decNumber(); break; | |
case NOTEADD: track[Pista].addNote(); break; | |
case NOTEDEC: track[Pista].decNote(); break; | |
//Serial.println(); | |
//Serial.print("Botón pulsado: "); | |
//Serial.print(boton); | |
} | |
boton = 0; | |
seq.actualiza(Paso); //Si hay cambios actualiza el display. | |
} | |
} | |
bool encoderSW() { | |
if ( digitalRead(ENC_SW) == 1) { | |
return 0; | |
} | |
while ( digitalRead(ENC_SW) == 0) {} //return 1; | |
while ( digitalRead(ENC_SW) == 1) {} | |
while ( digitalRead(ENC_SW) == 0) {} | |
} | |
void setup() { | |
MIDI.begin(MIDI_CHANNEL_OMNI); | |
//Serial.begin(115200); | |
FastLED.addLeds<NEOPIXEL, LEDPIN>(leds, NUM_LEDS); | |
FastLED.setBrightness(25); | |
pinMode(A1, INPUT); | |
pinMode(A2, INPUT); | |
pinMode(A3, INPUT); | |
pinMode(A4, INPUT); | |
pinMode(A5, INPUT); | |
pinMode(A6, INPUT); | |
pinMode(A7, INPUT); | |
//ENCODER | |
encoder.begin(); | |
pinMode (ENC_SW, INPUT_PULLUP); | |
attachInterrupt(ENCODER_INT1, interrupt, CHANGE); | |
attachInterrupt(ENCODER_INT2, interrupt, CHANGE); | |
randomSeed(analogRead(A0)); | |
for (int i = 0; i < 6; i++) { | |
track[i].setTrack(); | |
} | |
} | |
void interrupt() { | |
encoder.tick(); | |
} | |
void loop() { | |
EVERY_N_MILLISECONDS_I(bpm, Delay) { | |
static byte cont = 0; | |
seq.silencio(); | |
Paso = cont; | |
seq.actualiza(cont); | |
seq.toca(cont); | |
cont++; | |
bpm.setPeriod(Delay); | |
if (cont >= STEPS) { | |
cont = 0; | |
} | |
} | |
botones(); | |
////Serial.println(myEnc.read()); | |
encoderSW(); | |
static unsigned int position = BPM; | |
signed char pos = encoder.getPosition(); | |
if (pos != 0) { | |
position += pos; | |
if (position == 0) { | |
position = 1; | |
} | |
encoder.reset(); | |
//Serial.println(position); | |
Delay = 15000 / position; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment