Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 8 of 8

Thread: Problems about using multiple audio objects, T4

  1. #1
    Junior Member
    Join Date
    Sep 2019
    Location
    Sevilla, Spain
    Posts
    19

    Problems about using multiple audio objects, T4

    Hi there,
    I'm working in a 8 track sequencer, using Teensy 4 (which is amazing btw) The project uses a few big arrays (64 patterns with 8 tracks and 64 steps each) and I have arrays for the patterns itself, probability, velocity, play mode... but I'm facing some weird problems because I want to make it to play audio, apart of the midi & trigger outs.
    For the leds I'm using WS2812Serial.h which has no glitches when using audio like other WS2812 libraries.
    So actually has 8 basic drum synths, a noise generator connected to 8 envelopes, 8 filters and about 16 mixers to put all this together, the thing is that some stuff just stop working, like the code for saving the projects to the SD card needs to be disabled or the machine gets stuck on start up (loading presets works btw), every time I add other audio object, even if it's not connected to anything, something happens like a drum synth stops working, first 2 tracks start to play backwards...
    Tried with the SdFat library but it does not work if the Audio library is there.
    I've been measuring the audio memory and it was not too big (about 30 if I remember well, and I have set 100) so that shouldn't be the problem.
    the statics when compiling are:
    RAM: 32.2% (used 168628 bytes from 524288 bytes)
    Flash: 3.5% (used 71184 bytes from 2031616 bytes)
    the code is about 2500 lines so posting here may be not convenient,
    this is the part that saves the project to a SD card, maybe someone can tell me a better way to do this (my coding skills are pretty limited indeed):
    Code:
    void saveAll()
    {
      File dataFile;
    
      SD.remove("val.dat");
      dataFile = SD.open("val.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&val, sizeof(val));
      dataFile.close();
    
      SD.remove("prob.dat");
      dataFile = SD.open("prob.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&prob, sizeof(prob));
      dataFile.close();
    
      SD.remove("steps.dat");
      dataFile = SD.open("steps.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&steps, sizeof(steps));
      dataFile.close();
    
      SD.remove("pMode.dat");
      dataFile = SD.open("pMode.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&pMode, sizeof(pMode));
      dataFile.close();
    
      SD.remove("clockDiv.dat");
      dataFile = SD.open("clockDiv.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&clockDiv, sizeof(clockDiv));
      dataFile.close();
    
      SD.remove("euclNum.dat");
      dataFile = SD.open("euclNum.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&euclNum, sizeof(euclNum));
      dataFile.close();
    
      SD.remove("dot.dat");
      dataFile = SD.open("dot.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&dot, sizeof(dot));
      dataFile.close();
    
      SD.remove("roll.dat");
      dataFile = SD.open("roll.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&roll, sizeof(roll));
      dataFile.close();
    
      SD.remove("midiNote.dat");
      dataFile = SD.open("midiNote.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&midiNote, sizeof(midiNote));
      dataFile.close();
    
      SD.remove("menuVar.dat");
      dataFile = SD.open("menuVar.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&menuVar, sizeof(menuVar));
      dataFile.close();
    
      SD.remove("noInitPatt.dat");
      dataFile = SD.open("noInitPatt.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&noInitPatt, sizeof(noInitPatt));
      dataFile.close();
    
      SD.remove("raw.dat");
      dataFile = SD.open("raw.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&raw, sizeof(raw));
      dataFile.close();
    }
    and if some one has a clue, would like to know:
    -is there a limit for the audio objects in a project?
    -would help to allocate some of the bigger arrays maybe in the program memory to save some ram?
    -could the 'save' function be done in a better way(so it does not create any conflict)?
    thanks a lot in advance

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,417
    The symptoms suggest that you are running out of memory or having a problem indexing outside an array.
    some of the bigger arrays
    How many and how big? Are you using malloc or new to allocate them?
    It might be best to post a zip archive of your code.

    Pete

  3. #3
    Junior Member
    Join Date
    Sep 2019
    Location
    Sevilla, Spain
    Posts
    19
    i've just read something about this, probably I'm using too much global variables, will start modifying the code in that direction, also I've been using lots of byte or unit8_t to save ram but looks like in terms of speed unit32_t is the best, specially in functions etc, at least I do have now something to start tweaking,
    those are some of the variables and arrays:

    Code:
    uint64_t dot[64][8];
    byte prob[64][8][64];
    uint64_t roll[64][8];
    byte val[64][8][64]; //  velocidad midi 
    byte steps[64][8]; // duracion de cada linea
    byte pMode[64][8];     // 0 normal, 1 reverse, 2 pendulum
    byte clockDiv[64][8];    // division de reloj del row -1 ( 0 para clock divison = 1 ),
    byte euclNum[64][8];
    unsigned long long noInitPatt;
    unsigned long long masterTrack;
    bool resetSeq_;
    bool playDrum[8] = { true, true, true, true, true, true, true, true };
    byte midiNote[8];
    byte actPatt;
    byte nextPatt;
    byte pattCounter;
    byte part[65][64];
    byte loopSize[65];
    byte actPart = 64;
    unsigned long long noInitPart; 
    int multButtMax = 0;
    int multButtMin = 63;
    int multButt = -1; //  el ultimo botón pulsado y si se ha pulsado algo
    byte multButt_ = 64; // esto es para ajustar con el primer loop
    bool liveRecord_;
    // otras variables relativas a las secuencias:
    int pos[8];       // posicion  de reproducción
    int count[8];       // contador para el clock divider
    byte page[8]; // contador de paginas para del display d cada pista
    bool dir[8] = { true, true, true, true, true, true, true, true }; // direccion de la reproduccion para el modo pendulum
    bool mute[8];
    byte sculpt[8]; // random offset
    int i;               // loop helpers
    byte n;
    int x;
    int y;
    int y_; // pulso de la secuencia que representa el display
    int x_; //
    byte suma;
    int xx;
    int yy;
    int zz;
    // control de tempo:
    bool intTempo = false; // tempo interno, false seria externo (clock input)
    int tempo = 120; // 120/min = 2/seg = 500 milis;  tempo en la medida tradicional,
    elapsedMicros temp;
    unsigned int temp_ = 125000; // deducido a partir de tempo o viceversa, lo q debe durar temp
    unsigned int t32 = temp_ / 2;

  4. #4
    Junior Member
    Join Date
    Sep 2019
    Location
    Sevilla, Spain
    Posts
    19
    Quote Originally Posted by el_supremo View Post
    How many and how big? Are you using malloc or new to allocate them?
    Pete
    I'm doing nothing, just declaring variables, mo idea what malloc is...sorry...as I told my skills are pretty limited

  5. #5
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,417
    uint32_t might speed up your code a bit but lack of speed isn't your problem right now. It appears to be lack of space. Currently, the uint8_t arrays that you've shown in your message take up nearly 80kB. If you change them to uint32_t that will increase your memory requirement to 320kB which will only make the problem much worse.
    I would still like to see *all* your code.

    Pete

  6. #6
    Junior Member
    Join Date
    Sep 2019
    Location
    Sevilla, Spain
    Posts
    19
    well, I moved many variables that were declared as global to the main loop or functions, on every step things became more normal, first 2 tracks are not playing reversed anymore and everything is working, all drums are back to life now and the save function is active too without making the machine to crash on startup,
    anyway for sure there are a lot of things that could be improved.
    Quote Originally Posted by el_supremo View Post
    I would still like to see *all* your code.
    here is it, any tip would be much appreciated
    there are 3 files ( 5 indeed but one has all the code commented and the other is just a led pattern for the start up...so those 3 are the only important ones)
    ini.h :
    Code:
    // constantes, variables y ajustes
    
    #define bitSet64(value, bit) ((value) |= (1ULL << (bit)))
    #define bitClear64(value, bit) ((value) &= ~(1ULL << (bit)))
    #define bitWrite64(value, bit, bitvalue) (bitvalue ? bitSet64(value, bit) : bitClear64(value, bit))
    
    #define sonido
    //#define debug
    #define midi_
    //#define midiSync
    //#define SAMPLER
    #define DRUM
    #define DRUMS
    #include <math.h>
    #include <SD.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SerialFlash.h>
    
    #ifdef sonido
    //------------------AUDIO DESIGN TOOL----------------
    
    // GUItool: begin automatically generated code
    #ifdef SAMPLER
    String muestra[64] = {  "1.raw",  "2.raw",  "3.raw",  "4.raw",  "5.raw",  "6.raw",  "7.raw",  "8.raw",  "9.raw",  "10.raw",
                            "11.raw", "12.raw", "13.raw", "14.raw", "15.raw", "16.raw", "17.raw", "18.raw", "19.raw", "20.raw",
                            "21.raw", "22.raw", "23.raw", "24.raw", "25.raw", "26.raw", "27.raw", "28.raw", "29.raw", "30.raw",
                            "31.raw", "32.raw", "33.raw", "34.raw", "35.raw", "36.raw", "37.raw", "38.raw", "39.raw", "40.raw",
                            "41.raw", "42.raw", "43.raw", "44.raw", "45.raw", "46.raw", "47.raw", "48.raw", "49.raw", "50.raw",
                            "51.raw", "52.raw", "53.raw", "54.raw", "55.raw", "56.raw", "57.raw", "58.raw", "59.raw", "60.raw",
                            "61.raw", "62.raw", "63.raw", "64.raw"
                         };
    AudioPlaySdRaw           sample0;        //xy=220,122
    AudioPlaySdRaw           sample1;        //xy=220,242
    AudioPlaySdRaw           sample2;        //xy=220,362
    AudioPlaySdRaw           sample3;        //xy=220,482
    AudioPlaySdRaw           sample4;        //xy=220,602
    AudioPlaySdRaw           sample5;        //xy=220,722
    AudioPlaySdRaw           sample6;        //xy=220,842
    AudioPlaySdRaw           sample7;        //xy=220,962
    AudioConnection          patchCord12(sample0, 0, mixer0, 2);
    AudioConnection          patchCord14(sample1, 0, mixer1, 2);
    AudioConnection          patchCord16(sample2, 0, mixer2, 2);
    AudioConnection          patchCord18(sample3, 0, mixer3, 2);
    AudioConnection          patchCord20(sample4, 0, mixer4, 2);
    AudioConnection          patchCord22(sample5, 0, mixer5, 2);
    AudioConnection          patchCord23(sample6, 0, mixer6, 2);
    AudioConnection          patchCord24(sample7, 0, mixer7, 2);
    #endif
    
    AudioSynthNoiseWhite     noise1;         //xy=57,331.2500047683716
    
    AudioMixer4              mixer1;         //xy=379,202
    AudioMixer4              mixer2;         //xy=379,322
    AudioMixer4              mixer3;         //xy=379,442
    AudioMixer4              mixer4;         //xy=379,562
    AudioMixer4              mixer0;         //xy=381,94.75
    AudioMixer4              mixer5;         //xy=379,682
    AudioMixer4              mixer6;         //xy=379,802
    AudioMixer4              mixer7;         //xy=379,922
    #ifdef DRUMS
    AudioSynthSimpleDrum     drum1;          //xy=219,162
    AudioSynthSimpleDrum     drum2;          //xy=219,282
    AudioSynthSimpleDrum     drum0;          //xy=220,35
    AudioSynthSimpleDrum     drum3;          //xy=219,402
    AudioSynthSimpleDrum     drum4;          //xy=219,522
    AudioSynthSimpleDrum     drum5;          //xy=219,642
    AudioSynthSimpleDrum     drum6;          //xy=219,762
    AudioSynthSimpleDrum     drum7;          //xy=219,882
    AudioConnection          patchCord9(drum1, 0, mixer1, 0);
    AudioConnection          patchCord10(drum2, 0, mixer2, 0);
    AudioConnection          patchCord11(drum0, 0, mixer0, 0);
    AudioConnection          patchCord13(drum3, 0, mixer3, 0);
    AudioConnection          patchCord15(drum4, 0, mixer4, 0);
    AudioConnection          patchCord17(drum5, 0, mixer5, 0);
    AudioConnection          patchCord19(drum6, 0, mixer6, 0);
    AudioConnection          patchCord21(drum7, 0, mixer7, 0);
    #endif
    AudioEffectEnvelope      envelope0;      //xy=229.75,76.75
    AudioEffectEnvelope      envelope1;      //xy=230,202
    AudioEffectEnvelope      envelope2;      //xy=230,322
    AudioEffectEnvelope      envelope3;      //xy=230,442
    AudioEffectEnvelope      envelope4;      //xy=230,562
    AudioEffectEnvelope      envelope5;      //xy=230,682
    AudioEffectEnvelope      envelope6;      //xy=230,802
    AudioEffectEnvelope      envelope7;      //xy=230,922
    AudioFilterBiquad        biquad1;        //xy=522,202
    AudioFilterBiquad        biquad2;        //xy=522,322
    AudioFilterBiquad        biquad0;        //xy=523.2500076293945,109.50000095367432
    AudioFilterBiquad        biquad3;        //xy=522,442
    AudioFilterBiquad        biquad4;        //xy=522,562
    AudioFilterBiquad        biquad5;        //xy=522,682
    //AudioFilterStateVariable filter1;        //xy=525,33.75
    
    AudioFilterBiquad        biquad6;        //xy=522,802
    AudioFilterBiquad        biquad7;        //xy=522,922
    AudioMixer4              mixer10;        //xy=707,710
    AudioMixer4              mixer11;        //xy=709,845
    AudioMixer4              mixer13;        //xy=710,598
    AudioMixer4              mixer12;        //xy=714,384
    AudioMixer4              mixer9;         //xy=719,276
    AudioMixer4              mixer8;         //xy=721,150
    AudioMixer4              mixer16;        //xy=808,483
    //AudioEffectFreeverb      freeverb1;      //xy=950,487
    AudioMixer4              mixer15;        //xy=1086,599
    AudioMixer4              mixer14;        //xy=1090,371
    AudioOutputI2S           i2s1;           //xy=1216,481
    AudioConnection          patchCord1(noise1, envelope1);
    AudioConnection          patchCord2(noise1, envelope2);
    AudioConnection          patchCord3(noise1, envelope3);
    AudioConnection          patchCord4(noise1, envelope4);
    AudioConnection          patchCord5(noise1, envelope5);
    AudioConnection          patchCord6(noise1, envelope6);
    AudioConnection          patchCord7(noise1, envelope7);
    AudioConnection          patchCord8(noise1, envelope0);
    AudioConnection          patchCord25(envelope0, 0, mixer0, 1);
    AudioConnection          patchCord26(envelope1, 0, mixer1, 1);
    AudioConnection          patchCord27(envelope2, 0, mixer2, 1);
    AudioConnection          patchCord28(envelope3, 0, mixer3, 1);
    AudioConnection          patchCord29(envelope4, 0, mixer4, 1);
    AudioConnection          patchCord30(envelope5, 0, mixer5, 1);
    AudioConnection          patchCord31(envelope6, 0, mixer6, 1);
    AudioConnection          patchCord32(envelope7, 0, mixer7, 1);
    AudioConnection          patchCord33(mixer1, biquad1);
    AudioConnection          patchCord34(mixer2, biquad2);
    AudioConnection          patchCord35(mixer3, biquad3);
    AudioConnection          patchCord36(mixer4, biquad4);
    //AudioConnection          patchCord37(mixer0, 0, filter1, 0);
    AudioConnection          patchCord37(mixer0,  biquad0);
    
    AudioConnection          patchCord38(mixer5, biquad5);
    AudioConnection          patchCord39(mixer6, biquad6);
    AudioConnection          patchCord40(mixer7, biquad7);
    AudioConnection          patchCord41(biquad1, 0, mixer8, 1);
    AudioConnection          patchCord42(biquad1, 0, mixer9, 1);
    AudioConnection          patchCord43(biquad1, 0, mixer12, 1);
    AudioConnection          patchCord44(biquad2, 0, mixer8, 2);
    AudioConnection          patchCord45(biquad2, 0, mixer9, 2);
    AudioConnection          patchCord46(biquad2, 0, mixer12, 2);
    AudioConnection          patchCord47(biquad3, 0, mixer8, 3);
    AudioConnection          patchCord48(biquad3, 0, mixer9, 3);
    AudioConnection          patchCord49(biquad3, 0, mixer12, 3);
    AudioConnection          patchCord50(biquad4, 0, mixer10, 0);
    AudioConnection          patchCord51(biquad4, 0, mixer11, 0);
    AudioConnection          patchCord52(biquad4, 0, mixer13, 0);
    AudioConnection          patchCord53(biquad5, 0, mixer10, 1);
    AudioConnection          patchCord54(biquad5, 0, mixer11, 1);
    AudioConnection          patchCord55(biquad5, 0, mixer13, 1);
    //AudioConnection          patchCord56(filter1, 0, mixer8, 0);
    //AudioConnection          patchCord57(filter1, 0, mixer9, 0);
    //AudioConnection          patchCord58(filter1, 0, mixer12, 0);
    AudioConnection          patchCord56(biquad0, 0, mixer8, 0);
    AudioConnection          patchCord57(biquad0, 0, mixer9, 0);
    AudioConnection          patchCord58(biquad0, 0, mixer12, 0);
    AudioConnection          patchCord59(biquad6, 0, mixer10, 2);
    AudioConnection          patchCord60(biquad6, 0, mixer11, 2);
    AudioConnection          patchCord61(biquad6, 0, mixer13, 2);
    AudioConnection          patchCord62(biquad7, 0, mixer10, 3);
    AudioConnection          patchCord63(biquad7, 0, mixer11, 3);
    AudioConnection          patchCord64(biquad7, 0, mixer13, 3);
    AudioConnection          patchCord65(mixer10, 0, mixer14, 1);
    AudioConnection          patchCord66(mixer11, 0, mixer15, 1);
    AudioConnection          patchCord67(mixer13, 0, mixer16, 1);
    AudioConnection          patchCord68(mixer12, 0, mixer16, 0);
    AudioConnection          patchCord69(mixer9, 0, mixer15, 0);
    AudioConnection          patchCord70(mixer8, 0, mixer14, 0);
    //AudioConnection          patchCord71(mixer16, freeverb1);
    //AudioConnection          patchCord72(freeverb1, 0, mixer14, 2);
    //AudioConnection          patchCord73(freeverb1, 0, mixer15, 2);
    AudioConnection          patchCord74(mixer15, 0, i2s1, 1);
    AudioConnection          patchCord75(mixer14, 0, i2s1, 0);
    // GUItool: end automatically generated code
    
    
    //------------------AUDIO DESIGN TOOL----------------
    #ifdef DRUMS
    AudioSynthSimpleDrum     *drum[8] =
    {
      &drum0, &drum1, &drum2, &drum3, &drum4, &drum5, &drum6, &drum7
    };
    #endif
    
    #ifdef SAMPLER
    AudioPlaySdRaw           *sample[8] =
    {
      &sample0, &sample1, &sample2, &sample3, &sample4, &sample5, &sample6, &sample7
    };
    #endif
    AudioEffectEnvelope      *envelope[8] =
    {
      &envelope0, &envelope1, &envelope2, &envelope3, &envelope4, &envelope5, &envelope6, &envelope7
    };
    AudioFilterBiquad        *biquad[8] =
    {
      &biquad0, &biquad1, &biquad2, &biquad3, &biquad4, &biquad5, &biquad6, &biquad7
    };
    AudioMixer4              *mixer[17] =
    {
      &mixer0, &mixer1, &mixer2,  &mixer3,  &mixer4,  &mixer5,  &mixer6,  &mixer7,
      &mixer8, &mixer9, &mixer10, &mixer11, &mixer12, &mixer13, &mixer14, &mixer15,
      &mixer16
    };
    #endif
    
    /*
      AudioPlayMemory          sample[8];
      #include "AudioSampleHat01wavv.h"
      #include "AudioSampleHat02wavv.h"
      #include "AudioSampleKick02wavq.h"
      #include "AudioSampleKickwavq.h"
      #include "AudioSampleSnarewavq.h"
      #include "AudioSampleSnare01wavq.h"
      #include "AudioSampleSnare02wavq.h"
    */
    
    #ifdef midi_
    #include <MIDI.h>
    MIDI_CREATE_DEFAULT_INSTANCE();
    #endif
    
    #ifdef midiSync
    byte counter;
    byte CLOCK = 248;
    byte START = 250;
    byte CONTINUE = 251;
    byte STOP = 252;
    #endif
    
    #include <EEPROM.h>
    //int eeAddress;   //Location we want the data to be put.
    
    //  L E D S
    #include <WS2812Serial.h>
    #define numled 72
    #define PIN0 17
    byte BRIGHTNESS = 30;
    byte drawingMemory[numled * 3];       //  3 bytes per LED
    DMAMEM byte displayMemory[numled * 12]; // 12 bytes per LED
    WS2812Serial leds(numled, displayMemory, drawingMemory, PIN0, WS2812_GRB);
    
    int ledRef = 0; // contador para refresco de los leds
    // numero de ciclos del loop necesarios para la escritura de los leds
    #define ledRefMini 40 //50 // reloj perfecto pero mucha latencia?
    int ledRef_ = ( ledRefMini * 81 ) - 1; // los 80 ciclos del grid y el pico final!!
    
    // E N C O D E R :
    //#define ENCODER_OPTIMIZE_INTERRUPTS
    #define ENCODER_DO_NOT_USE_INTERRUPTS
    #include <Encoder.h>
    #define encA 14
    #define encB 15
    #define encClick 16
    Encoder myEnc( encA, encB );
    byte enc4;
    byte _enc4;
    int enc;
    int _enc;
    byte encPos;
    byte actRow;
    byte actCol;
    bool encButt;
    bool _encButt;
    bool encButt_;
    bool shuttle;
    
    #define row0  30 // pins for 4051 row
    #define row1  31
    #define row2  8
    #define col0  12 // pins for column
    #define col1  13
    #define col2  27
    #define col3  26
    #define pad 33      // COLUMN, pin de lectura del los pad del panel
    #define triggIn  19  // entrada de relog
    #define resetInput 18
    
    
    bool butt[8][10];    // lectura de los pads,
    bool _butt[8][10];  // comparador
    bool butt_[8][8];  // estado del boton, las dos ultimas columnas no se estanb utilizando
    bool recModulation;
    bool recMode = true; //'true' sería insert note,false sería delete, muy guapo para performance
    const byte triggOut[] =  {2, 3, 4, 5, 6, 9, 10, 11};// pines de salida para las 8 pistas de triggers
    bool resetIn;
    bool _resetIn;
    bool trigg;       // entrada del clock
    bool _trigg;
    
    #define maxSteps 63 // longitud maxima de la secuencia ( quitandole -1 )
    
    //  VARIABLES PARA ALMACENAR COMO PRESET:
    uint64_t dot[64][8];
    uint64_t roll[64][8];
    byte prob[64][8][(maxSteps + 1)];
    byte val[64][8][maxSteps + 1]; // esta variablepodríamos usarlapara la velocidad midi x ejemplo
    byte steps[64][8]; // duracion de cada linea
    byte pMode[64][8];     // 0 normal, 1 reverse, 2 pendulum
    byte clockDiv[64][8];    // division de reloj del row -1 ( 0 para clock divison = 1 ),
    byte euclNum[64][8];
    uint64_t noInitPatt;
    uint64_t masterTrack;
    uint64_t noInitProject;
    byte part[65][64];
    uint64_t noInitPart; // incluir en los presets
    //--------GLOBAL SETTINGS---------
    bool playSample[8] = { false, false, false, false, false, false, false, false };
    bool playDrum[8] = { true, true, true, true, true, true, true, true };
    byte midiNote[8];
    uint8_t raw[8] = { 2, 3, 4, 5, 6, 7, 8, 9 }; // archivo que reproducira cada sampler/pista
    bool resetSeq_;
    byte actPatt;
    byte nextPatt;
    byte pattCounter;
    byte loopSize[65];
    byte actPart = 64;
    
    byte multButtMax = 0;
    byte multButtMin = 63;
    int multButt = -1; // esto nos sirve para saber el ultimo botón pulsado y si se ha pulsado algo
    byte multButt_ = 64; // esto es para ajustar con el primer loop
    bool liveRecord_;
    
    // otras variables relativas a las secuencias:
    int pos[8];       // posicion del puntero de reproducción
    int count[8];       // contador para el clock divider
    byte page[8]; // contador de paginas para del display d cada pista
    bool dir[8] = { true, true, true, true, true, true, true, true }; // direccion de la reproduccion para el modo pendulum
    //int numeroClave; // variable para mi script de random, calculado a partir del contador de espera de los leds.
    
    // implementaciones avanzadas
    
    //byte ramification; // ciclo acumulativo de remates
    /* tipose de rwamidficacion
       proprcional
       aritmetica */
    
    //byte alg; // algoritmo de remates
    /*  nothing
        inverse
        reverse
        re-order 3.3.2.3.3.2. -> 3.3.3.3.2.2. */
    //bool logic; // para las pistas lógicas
    //byte logicType; // quizasa no hace falta bool, solo el tipo > 0
    bool mute[8];
    int8_t  sculpt[8]; // random offset
    int i;               // loop helpers
    byte x;
    byte y;
    byte suma;
    
    // control de tempo:
    bool intTempo = false; // tempo interno, false seria externo (clock input)
    int tempo = 120; // 120/min = 2/seg = 500 milis;  tempo en la medida tradicional,
    elapsedMicros temp;
    uint32_t temp_ = 125000; // deducido a partir de tempo o viceversa, lo q debe durar temp
    unsigned int t32 = temp_ / 2;
    int stepCount; // byte es poco para un contador de pulsos
    byte beatCount; // este es para los trsillos y el swing
    byte swingAmount; // de 0 a 100
    unsigned int swingTemp_; //el tiempo de retraso que lleva el golpe de swing, máximo 1/3 del pulso
    bool t32_; // esto no me mola, usaremos algo distinto para el contador del relog
    //bool t64;
    
    #define triggLength  1000 //duracion de los triggers en microsegundos
    byte editMode; // probando con tempo
    byte lastEditMode;
    // 0 - normal
    // 1 - length     -> azul
    // 2 - play mode -> no deberia ser un menu, encoder y selector de pistas
    // 3 - clock div  -> verde
    // 4 - probabilidad
    // 5 - roll
    // 6 - rotate
    // 7 - euclidean -> no deberia ser un menu, encoder y selector de pistas
    // 8 - tempo -> no deberia ser un menu, encoder
    // 9 - midi -> no deberia ser un menu, encoder y selector de pistas
    // 10 - val
    // 11 - audio
    // 12 - brillo y settings?
    // 13 - swing -> no deberia ser un menu, encoder
    // 14 - modulacion
    // 15 - pattern
    // 16 - drum settings
    // 17 - mute
    // 18 - invert
    // 19 - editPart
    // 20 - part grid
    // 21 - song editor
    // 22 - shuttle
    // 23 - escoger muestra
    
    bool edit; // esto se usa para que el encoder no se mueva,
    //comprobar en que menus haria falta movimiento
    
    // M E N U  - H O R I Z O N T A L
    bool menu2 = false;
    
    // M E N U  V E R T I C A L
    bool menuVertical; // activa la vision de menu horizontal
    byte menuIndex; // 0 audio, 1 mezcla, 2 modulacion
    byte menuParam; // parámtros del 1 al 8
    int menuVar[3][8][8]; // [menuIndex][actTrack][menuParam]
    
    //drum synth
    #define drumVol 0
    #define drumDecay 1
    #define drumFreq 2
    #define drumMod 3
    #define drumSecond 4
    #define noiseVol 5
    #define noiseDecay 6
    
    //---------------
    
    #define volumen 0
    #define panoramica 1
    #define revAmount 2
    #define filterFreq 3 
    #define resonancia 4
    #define filterType 5 
    
    //channel mixer
    //reverb settings
    #define revSize 0
    #define revDamp 1
    #define revL 2
    #define revR 3
    /*
      Mix(1, 2, 3):
      -vol
      -pan
      -reverb
      Mod:
    */
    // P U S H  B U T T O N S - en principio no estoy usando los 'bool' excepto en el encoder
    
    // pasa por lo modos de edicion
    #define playStopButt 0
    #define tempoButt 0
    #define homeButt 1
    #define settingsButt 1
    #define lengthButt 2
    #define divButt 2
    #define pattButt 3
    #define saveAllButt 3  // esto deberia ser save project?
    #define playModeButt 4
    #define masterTrackButt 4
    #define fillButt 5
    #define euclButt 5
    #define muteButt 6
    // mute all
    #define provButt 7
    // prob roll
    #define invButt 8 // tambien invert all
    // inv all
    #define rollButt 9
    #define midiButt 9
    #define rotateButt 10 //tambien rotate all
    //rotate all
    #define valButt 11
    #define modButt 11
    #define trippButt 12 //tresillos
    #define swingButt 12
    #define audioButt 13 // drumSynth
    #define shiftButt 14
    #define zoomButt 15
    #define brightButt 15
    // botones de funcion del grid:
    // D R U M   S Y T N H - linea 7
    #define drumSynthVol 49
    #define drumSynthDecay 50
    #define drumSynthFreq 51
    #define drumSynthMod 52
    #define drumSynthSecond 53
    #define noiseSynthVol 54
    #define noiseSynthDecay 55
    // M I X E R - ultima linea
    #define mixerVol 57
    #define mixerPan 58
    #define mixerReverbSend 59
    #define mixerFilterFreq 60
    #define mixerFilterRes 61
    #define mixerFilterType 62
    
    bool shiftButt_; // para las egundas funsiones de cada boton, tambien como track select?
    bool zoom; //estado del zoom
    byte zoomTrack;
    // ENTRADAS DE CV Y MATRIZ DE MODULACIÓN:
    const byte cvIn[4] = { 22 , 22 , 22 , 22 };// 22, 23, 24, 25
    int cvRead[4]; //lectura de CV
    int8_t modMatrix[3][8][7]; // cuatro canales de CV, de -100 a 100%
    byte modSource[3][8][7]; // [menuIndex][actTrack][menuParam]
    long rndNumber = random(16);
    tukra.ino :
    Code:
    //
    // T U K R A trigger sequencer
    //
    //     Tesseract Modular
    //
    //      Mangu Díaz 2020
    
    // unsigned const int * samples[] = {AudioSampleSnare, AudioSampleHihat};
    
    #include "ini.h"
    
    void setup()
    {
    
    #ifdef sonido
      AudioMemory(60); //120
      for (i = 0; i < 8; i++)
      {
        envelope[i]->attack(0.0);
        envelope[i]->hold(0.0);
        envelope[i]->sustain(0.0);
        envelope[i]->release(0.0);
        envelope[i]->releaseNoteOn(0.0);
      }
      noise1.amplitude(0.5);
    
      SD.begin(BUILTIN_SDCARD);
    #endif
    
    #ifdef midi_
      MIDI.begin();
    #endif
    
    #ifdef midiSync
      MIDI.setHandleRealTimeSystem(RealTimeSystem);
    #endif
    
    #ifdef debug
      while (!Serial)
        ;
      Serial.print("T U K R A  Firmware Debug Mode\n");
      Serial.print("ledRef_ : ");
      Serial.print(ledRef_);
      Serial.print("\n");
      intTempo = false;
    #endif
      for (i = 0; i < 8; i++)
      {
        pinMode(triggOut[i], OUTPUT);
      }
    
      // setting pins for buttons etc:
      pinMode(triggIn, INPUT);
      pinMode(encClick, INPUT_PULLUP);
      pinMode(resetInput, INPUT);
    
      //  multiplexer:
      pinMode(row0, OUTPUT);
      pinMode(row1, OUTPUT);
      pinMode(row2, OUTPUT);
      pinMode(col0, OUTPUT);
      pinMode(col1, OUTPUT);
      pinMode(col2, OUTPUT);
      pinMode(col3, OUTPUT);
      pinMode(pad, INPUT_PULLUP);
    
      // ENTRADAS DE CV
      analogReadResolution(10);
      pinMode(cvIn[0], INPUT); //empezamos jugando solo con una entrada
      //pinMode(cvIn[1], INPUT);
      //pinMode(cvIn[2], INPUT);
      //pinMode(cvIn[3], INPUT);
    
      // LEDS:
      leds.setBrightness(BRIGHTNESS);
      leds.begin();
    
      //inicializar el projecto
      for (i = 0; i < 64; i++)
      {
        actPatt = i;
        initPatt();
      }
      actPatt = 0;
      part[64][0] = 0;
      loopSize[64] = 0;
      loadAll();
      // readPreset();
    
    #include "bootSeq.h"
    }
    
    void loop()
    {
    #ifdef midiSync
      MIDI.read();
    #endif
      // byte menuParam;
      ledRef++;
    
      // M A T R I X   B U T T O N   R E A D:
      if ((ledRef % ledRefMini) == 0)
      {
        butt[x][y] = digitalRead(pad);
        if (y == 9)
        {
          x++;
          if (x > 7)
          {
            x = 0;
          }
          uint8_t r0 = bitRead(x, 0);
          uint8_t r1 = bitRead(x, 1);
          uint8_t r2 = bitRead(x, 2);
          digitalWrite(row0, r0);
          digitalWrite(row1, r1);
          digitalWrite(row2, r2);
        }
        y++;
        if (y > 9)
        {
          y = 0;
        }
        uint8_t c0 = bitRead(y, 0);
        uint8_t c1 = bitRead(y, 1);
        uint8_t c2 = bitRead(y, 2);
        uint8_t c3 = bitRead(y, 3);
        digitalWrite(col0, c0);
        digitalWrite(col1, c1);
        digitalWrite(col2, c2);
        digitalWrite(col3, c3);
    
        // G R I D   8 X 8
    
        if (y < 8)
        {
          //reseteamos los valores para empezar
          uint32_t redVal = 0;
          uint32_t blueVal = 0;
          uint32_t greenVal = 0;
          byte x_;
          byte y_;
          suma = (x * 8) + y;
          if (butt[x][y] != _butt[x][y])
          {
            if (butt[x][y] == LOW)
            {
              multButt_++;
              if ((shiftButt_) && (y == 0) && (editMode != 15)) // selección de pista
              {
                actRow = x;
                zoomTrack = x; 
              }
              else
              {
                butt_[x][y] = true;
                if ((!menuVertical) && (editMode != 14)) // hay conflicto aqui con el menu horizontal y el menu modulacion
                {
                  encPos = suma;
                  actRow = x;
                  actPos();
                }
              }
            }
            else
            {
              multButt_--;
              /*
                #ifdef debug
                Serial.print("botones pulsados..."); Serial.print(multButt_); Serial.print("\n");
                #endif
              */
            }
            _butt[x][y] = butt[x][y];
          }
          if (menuVertical) // MENU VERTICAL
          {
            if ((y > 0) && ((menuVar[menuIndex][actRow][y - 1] / 128) >= (7 - x)))
            {
              redVal = (7 - x) * 10;
              greenVal = 70 - ((7 - x) * 10);
            }
            if (((y == menuParam + 1) && (x == 7))) // esto nos indica el parametro seleccionado
            {
              blueVal = 30;
            }
            if ((y == 0) && (x == actRow)) // selección de pista
            {
              blueVal = 100;
            }
            if (butt_[x][y] == true)
            {
              if (y == 0)
              {
                actRow = x;
              }
              else
              {
                menuVar[menuIndex][actRow][y - 1] = (128 * (7 - x));
                menuParam = y - 1;
              }
            }
          }
    
          // nuevo Menu Horizontal 
          // falta por implementar el encoder!
          else if (menu2)
          {
            if ((menuVar[menuIndex][x][menuParam] / 128) >= y)
            {
              redVal = y * 10;
              blueVal = 70 - (y * 10);
            }
            if (butt_[x][y] == true)
            {
              menuVar[menuIndex][x][menuParam] = (128 * y);
            }
          }
          else // si no hay menu horizontal o vertical procesamos todo lo demas,
          {
            if (zoom == false)
            {
              page[x] = (pos[x] / 8);
              y_ = (y + (page[x] * 8));
              x_ = x;
            }
            else
            {
              x_ = zoomTrack;
              y_ = (suma);
            }
    
            if (bitRead(dot[actPatt][x_], y_) == true) // hay un golpe ahi
            {
              blueVal = 50;
            }
    
            if ((pos[x_] == y_)) // posicion de reproduccion
            {
              redVal = 50; 
            }
    
            if (encPos == suma) //posicion del encoder
            {
              greenVal = 50;
              if (encButt_ == true) // E N C O D E R .  B U T T O N
              {
                switch (editMode)
                {
                case 0:
                  bitWrite64(dot[actPatt][x_], y_, !bitRead(dot[actPatt][x_], y_));
                  bitSet64(noInitPatt, actPatt); // el patron tiene contenido
                  break;
                case 5: //roll
                  if (bitRead(dot[actPatt][x_], y_) == true)
                  {
                    if (bitRead(roll[actPatt][x_], y_) == true)
                    {
                      bitClear64(roll[actPatt][x_], y_);
                    }
                    else
                    {
                      bitSet64(roll[actPatt][x_], y_);
                    }
                  }
                  break;
                default:
                  edit = !edit;
                  if (edit == false)
                  {
                    actPos();
                  }
                  break;
                }
                encButt_ = false;
              }
            }
    
            switch (editMode) // B U T T O N   G R I D   M O D E
            {
            case 0: // H O M E
              if (butt_[x][y] == true)
              {
                if (shiftButt_)
                {
                  switch (suma)
                  {
                  case 1: // R E C   M O D E
                    liveRecord_ = !liveRecord_;
                    break;
                  case 2: // P A R T   E D I T O R
                    editMode = 19;
                    break;
                  case 9: // S H U T T L E
                    shuttle = true;
                    break;
                  case 17: // INVERTIR DIRECCIÓN
                    invertDir();
                    break;
                  case 18: // I N I T   P A R T
                    initPatt();
                    break;
                  case 10: // part grid
                    editMode = 20;
                    break;
                  case 25: // S E L E C T   R A W
                    editMode = 23;
                    edit = true;
                    break;
                  //----------MENU HORIZONTAL-----------
                  case mixerVol: // MIXER -> VOLUMEN
                    menu2 = true;
                    edit = true;
                    menuIndex = 1;
                    menuParam = 0;
                    break;
                  case mixerPan: // MIXER -> PAN
                    menu2 = true;
                    edit = true;
                    menuIndex = 1;
                    menuParam = 1;
                    break;
                  case mixerReverbSend: // MIXER -> REVERB SEND
                    menu2 = true;
                    edit = true;
                    menuIndex = 1;
                    menuParam = 2;
                    break;
                  case mixerFilterFreq: // MIXER -> FILTER CUTOFF
                    menu2 = true;
                    edit = true;
                    menuIndex = 1;
                    menuParam = 3;
                    break;
                  case mixerFilterRes: // MIXER -> FILTER RES
                    menu2 = true;
                    edit = true;
                    menuIndex = 1;
                    menuParam = 4;
                    break;
                  case mixerFilterType: // MIXER -> FILTER TYPE
                    menu2 = true;
                    edit = true;
                    menuIndex = 1;
                    menuParam = 5;
                    break;
                  case drumSynthVol: // DRUM -> VOLUMEN
                    menu2 = true;
                    edit = true;
                    menuIndex = 0;
                    menuParam = 0;
                    break;
                  case drumSynthDecay: // DRUM -> DECAY
                    menu2 = true;
                    edit = true;
                    menuIndex = 0;
                    menuParam = 1;
                    break;
                  case drumSynthFreq: // DRUM -> PITCH
                    menu2 = true;
                    edit = true;
                    menuIndex = 0;
                    menuParam = 2;
                    break;
                  case drumSynthMod: // DRUM -> PITCH ENV
                    menu2 = true;
                    edit = true;
                    menuIndex = 0;
                    menuParam = 3;
                    break;
                  case drumSynthSecond: // DRUM -> 5º
                    menu2 = true;
                    edit = true;
                    menuIndex = 0;
                    menuParam = 4;
                    break;
                  case noiseSynthVol: // NOISE -> VOL
                    menu2 = true;
                    edit = true;
                    menuIndex = 0;
                    menuParam = 5;
                    break;
                  case noiseSynthDecay: // NOISE -> DECAY
                    menu2 = true;
                    edit = true;
                    menuIndex = 0;
                    menuParam = 6;
                    break;
                  }
                }
                else if (liveRecord_)
                {
                  liveRecord();
                }
                else
                {
                  bitWrite64(dot[actPatt][x_], y_, !bitRead(dot[actPatt][x_], y_));
                  bitSet64(noInitPatt, actPatt);
                }
              }
              break;
            case 1: // S T E P S
              if (steps[actPatt][x_] >= (zoom * x * 8) + y)
              {
                blueVal += 10;
              }
              if (butt_[x][y] == true)
              {
                steps[actPatt][x_] = y_;
              }
              break;
            case 2: // P L A Y   M O D E
              break;
            case 3: // div, step repeat
              if (clockDiv[actPatt][x_] >= y)
              {
                greenVal += 10;
              }
              if (butt_[x][y] == true)
              {
                clockDiv[actPatt][x_] = y_;
              }
              break;
            case 4: // prob
              if (bitRead(dot[actPatt][x_], y_) == true)
              {
                redVal = (225 / (prob[actPatt][x_][y_] + 1));
                blueVal = (prob[actPatt][x_][y_] * 14);
              }
              break;
            case 5: // roll
              if (bitRead(roll[actPatt][x_], y_) == true)
              {
                redVal += 40;
              }
              if (butt_[x][y] == true)
              {
                bitWrite64(roll[actPatt][x_], y_, !bitRead(roll[actPatt][x_], y_));
              }
              break;
            case 10: // VAL,
                     //quitamos el condicional ...solo sirve para jugar con la modulacion cruzada!
              //if  ( bitRead(dot[actPatt][x_], y_) == true ) // hay un golpe ahi
              //{
              redVal = val[actPatt][x_][y_] / 2;
              blueVal = 127 - val[actPatt][x_][y_];
              //}
              if (butt_[x][y] == true)
              {
                multButt = suma;
                if (multButt > multButtMax)
                {
                  multButtMax = multButt;
                }
                if (multButt < multButtMin)
                {
                  multButtMin = multButt;
                }
              }
              else
              {
                if ((multButt != -1) && (multButt_ == 0)) // esto nos indica que nigun boton esta pulsado pero no se ha reseteado
                {
                  // reset:
                  multButtMin = 63;
                  multButtMax = 0;
                  multButt = -1;
                }
              }
              break;
            case 14:     // M O D   M A T R I X
              if (y > 0) // grid de puntos de modulacion, offset 'y-1'
              {
                if (modMatrix[menuIndex][x][y - 1] > 0) // colores para modulación positiva
                {
                  redVal = 30 + (modMatrix[menuIndex][x][y - 1] * 2);
                  greenVal = (100 - modMatrix[menuIndex][x][y - 1]) / 2;
                }
                else if (modMatrix[menuIndex][x][y - 1] < 0) // modulación negativa
                {
                  blueVal = 30 + (modMatrix[menuIndex][x][y - 1] * -2);
                  redVal = (100 + modMatrix[menuIndex][x][y - 1]) / 2;
                  greenVal = 0;
                }
                else
                {
                  redVal = 0;
                  blueVal = 0;
                }
    
                if (butt_[x][y] == true)
                {
                  encPos = suma;
                  edit = true;
                  actRow = x;
                  actCol = y;
                }
              }
              else // primera columna, seleccion de CV del parametro seleccionado
              {
                redVal = 0;
                blueVal = 0;
                greenVal = 0;
                if (x == modSource[menuIndex][actRow][actCol - 1])
                {
                  greenVal = 100;
                }
                if (menuIndex == x - 6)
                {
                  blueVal = 100;
                }
                if (butt_[x][y] == true)
                {
                  if (x < 5) // seleccion del cv de 1 a 4, luego ya veremos
                  {
                    modSource[menuIndex][actRow][actCol - 1] = x;
                  }
                  // seleccion del menuIndex, de momento 0 o 1 (drumSynth y audio)
                  else if (x > 5)
                  {
                    menuIndex = x - 6;
                  }
                }
              }
              break;
            case 15: // P A T T E R N
              redVal = 0;
              blueVal = 0;
              if (actPatt == suma) // patron en reproduccion
              {
                greenVal = 50;
              }
              else if ((suma >= part[64][0]) && (suma <= part[64][loopSize[64]])) // rango de patrones del loop
              {
                redVal = 100;
              }
              else // fuera del loop
              {
                blueVal = 20;
                redVal = bitRead(noInitPatt, suma) * 50;
              }
              if (butt_[x][y] == true)
              {
                multButt = suma;
                if (multButt > multButtMax)
                {
                  multButtMax = multButt;
                }
                if (multButt < multButtMin)
                {
                  multButtMin = multButt;
                }
                if (shiftButt_ == true)
                {
                  copyPatt();
                  actPatt = suma;
                }
              }
              else
              {
                if ((multButt != -1) && (multButt_ == 0)) // esto nos indica que nigun boton esta pulsado en este ciclo pero que hay un loop por procesar!
                {
                  makeLoop();
                  // reset:
                  multButtMin = 63;
                  multButtMax = 0;
                  multButt = -1;
                }
              }
              break;
            case 18: // invert sequence
              if (butt_[x][y] == true)
              {
                invertSeq(actRow);
              }
              break;
            case 17: // M U T E
              if (mute[x_] == true)
              {
                redVal += 15;
                greenVal += 10;
              }
              if (butt_[x][y] == true)
              {
                mute[actRow] = !mute[actRow];
              }
              break;
            case 19: // p a t t e r n
              if (suma > loopSize[actPart])
              {
                redVal = 0;
                greenVal = 0;
                blueVal = 0;
              }
              else
              {
                redVal = part[actPart][suma] * 2;
                greenVal = (part[actPart][suma] % 3) * 30;
                blueVal = 63 - (part[actPart][suma]);
              }
              if (butt_[x][y] == true)
              {
                if (shiftButt_ == true)
                {
                  //hacer algo
                  part[actPart][suma] = actPatt;
                }
                else
                {
                  //abrir o guardar parte
                  actPatt = part[actPart][suma];
                }
              }
              break;
            case 20: // P A T T E R N   G R I D
              blueVal = 20 * bitRead(noInitPart, suma);
              if (suma == actPart)
              {
                redVal = 80;
              }
              else
              {
                redVal = 40;
                greenVal += 20;
              }
              if (butt_[x][y] == true)
              {
                if (shiftButt_ == true)
                {
                  //guardar la parte actual en ese slot
                  for (i = 0; i < 64; i++)
                  {
                    part[suma][i] = part[actPart][i];
                  }
                  loopSize[suma] = loopSize[actPart];
                  bitSet64(noInitPart, suma);
                }
                else
                {
                  //abrir parte
                  actPart = suma;
                }
              }
              break;
            } // end of GRID
          }   // final del condicional 'no horizontal menu'
          leds.setPixelColor((suma), leds.Color(redVal, greenVal, blueVal));
          butt_[x][y] = false;
        } // fin de si y < 8
    
        if (y > 7) // F U N C T I O N  B U T T O N S
        {
          byte buttCount = (x * 2) + y - 8;
          if (butt[x][y] != _butt[x][y])
          {
            if (butt[x][y] == LOW)
            {
              if (shiftButt_)
              {
                switch (buttCount) // f u n c i o n e s   s e c u n d a r i a s
                {
                case euclButt:
                  if (editMode == 7)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 7;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 7;
                  }
                  break;
                case brightButt: // edit BRIGHTNESS
                  editMode = 12;
                  edit = true;
                  break;
                case tempoButt: // edit tempo
                  editMode = 8;
                  edit = true;
                  break;
                case modButt: // mod settings
                  editMode = 14;
                  edit = false;
                  menuVertical = false;
                  leds.setPixelColor(64, leds.Color((1023 - cvRead[0]) / 10, cvRead[0] / 10, 0));
                  leds.setPixelColor(65, leds.Color((1023 - cvRead[1]) / 10, cvRead[1] / 10, 0));
                  leds.setPixelColor(66, leds.Color((1023 - cvRead[2]) / 10, cvRead[2] / 10, 0));
                  leds.setPixelColor(67, leds.Color((1023 - cvRead[3]) / 10, cvRead[3] / 10, 0));
                  break;
                case midiButt:
                  editMode = 9;
                  break;
                case swingButt: // swing control
                  editMode = 13;
                  edit = true;
                  break;
                case divButt:
                  editMode = 3;
                  edit = true;
                  menuVertical = false;
                  break;
                case saveAllButt: // save project
                  saveAll();
                  break;
                case masterTrackButt: // el track 1 resetea a los demas
                  bitWrite64(masterTrack, actPatt, !bitRead(masterTrack, actPatt));
                  break;
                case audioButt: // M I X E R settings
                  lastEditMode = editMode;
                  // editMode = 11; 16 ??
                  menuIndex = 1; // corresponde all array de audio
                  menuVertical = true;
                  break;
                }
              }
              else
              {
                switch (buttCount)
                {
                case homeButt: // H O M E
                  if ((editMode == 0) && (zoom == true))
                  {
                    zoom = false;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 0;
                    menuVertical = false;
                    menu2 = false;
                    edit = false; //igual esta la tenemos q sacar de aqui
                  }
                  break;
                case playStopButt:
                  intTempo = !intTempo;
                  if (intTempo)
                  {
                    temp_ = 15000000 / tempo;
                    t32 = temp_ / 2;
                    swingCalculator();
                    resetSeq();
                    writeTrigg();
                    temp = 0;
                    beatCount = 1;
                  }
                  break;
                case zoomButt:
                  zoom = !zoom;
                  if (zoom == true)
                  {
                    zoomTrack = actRow;
                  }
                  break;
                case lengthButt:
                  if (editMode == 1)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 1;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 1;
                    edit = true;
                    menuVertical = false;
                  }
                  break;
                case playModeButt:
                  if (editMode == 2)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 2;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 2;
                  }
                  break;
                case provButt:
                  if (editMode == 4)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 4;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 4;
                  }
                  break;
                case rollButt:
                  if (editMode == 5)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 5;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 5;
                  }
                  break;
                case valButt: // val edit
                  if (editMode == 10)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 10;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 10;
                  }
                  break;
                case rotateButt:
                  if (editMode == 6)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 6;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 6;
                  }
                  break;
                case audioButt: // drum settings
                  if (editMode == 16)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 16;
                    menuVertical = false;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 16;
                    menuIndex = 0; // corresponde all array de DRUM SETTING
                    menuVertical = true;
                  }
                  break;
                case shiftButt: // trackSelect
                  shiftButt_ = true;
                  break;
                case muteButt: // M U T E
                  if (editMode == 17)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 17;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 17;
                    menuVertical = false;
                    //edit = true;
                  }
                  break;
                case pattButt:
                  if (editMode == 15)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 15;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 15;
                    menuVertical = false;
                    edit = false;
                    encPos = actPatt;
                    actPos();
                  }
                  break;
                case invButt: // invertir los golpes
                  if (editMode == 18)
                  {
                    editMode = lastEditMode;
                    lastEditMode = 18;
                  }
                  else
                  {
                    lastEditMode = editMode;
                    editMode = 18;
                  }
                  break;
                }
              }
            }
            else if (buttCount == shiftButt) // release
            {
              shiftButt_ = false;
            }
            _butt[x][y] = butt[x][y];
          }
        } // fin si x> 8
      }   // fin ledref 
      if (ledRef == ledRef_)
      {
        cvRead[0] = 1023 - analogRead(cvIn[0]);
        cvRead[1] = 1023 - analogRead(cvIn[1]);
        cvRead[2] = 1023 - analogRead(cvIn[2]);
        cvRead[3] = 1023 - analogRead(cvIn[3]);
        // tolerancia:
        // cvRead[cvSelect] = constrain( cvRead[cvSelect], 0, 1023 );
        // borrar esto luego:
        leds.setPixelColor(64, leds.Color(cvRead[0] / 5, cvRead[0] / 10, 0));
        leds.setPixelColor(65, leds.Color(cvRead[1] / 5, cvRead[1] / 10, 0));
        leds.setPixelColor(66, leds.Color(cvRead[2] / 5, cvRead[2] / 10, 0));
        leds.setPixelColor(67, leds.Color(cvRead[3] / 5, cvRead[3] / 10, 0));
    
    #include "enc.h"
        // lectura de encoder click:
        encButt = digitalRead(encClick);
        if (encButt != _encButt)
        {
          if (encButt == LOW)
          {
            encButt_ = true;
          }
          _encButt = encButt;
        }
        if (edit == true) // avisador del encoder!!
        {
          leds.setPixelColor(71, leds.Color(100 - enc, enc, 0));
        }
        else
        {
          leds.setPixelColor(71, leds.Color(0, 0, 0));
        }
        leds.show();
        ledRef = 0;
      }
    
      // escritura de los pulsos etc:
      // R E L O G   I N T E R N O
      if (intTempo == true)
      {
        if ((((beatCount == 0) || (beatCount == 2)) && (temp >= (temp_ - swingTemp_))) || (temp >= (temp_ + swingTemp_)))
        {
          temp = 0;
          t32_ = true;
          if ((beatCount == 0) || (beatCount == 2))
          {
            t32 = (temp_ + swingTemp_) / 2; // remainder 0
          }
          else
          {
            t32 = (temp_ - swingTemp_) / 2; // remainder 1 de 'beatCount % 2'
          }
          go();
          writeTrigg();
          beatCount++;
          rndNumber = random(16);
          if (beatCount > 3)
          {
            beatCount = 0;
          }
        }
      }
      else // el tempo no es interno, se lee la entrada del relog
      {
        // R E S E T
        resetIn = digitalRead(resetInput);
        if (_resetIn != resetIn)
        {
          if (resetIn == LOW) //podriamos poner un condicional!
          {
            //resetSeq();
            resetSeq_ = true;
          }
          _resetIn = resetIn;
        }
    
        trigg = digitalRead(triggIn);
        if (trigg != _trigg)
        {
          if (trigg == LOW)
          {
            temp_ = temp;
            if (temp_ > 1500000)
            {
              temp_ = 1500000;
            }
            if (temp_ < 60000)
            {
              temp_ = 60000;
            }
            swingCalculator();
            if ((beatCount == 0) || (beatCount == 2))
            {
    #ifdef debug
              //yy = temp / xx;
              //zz = AudioMemoryUsageMax();
              //Serial.print("\n temp..."); Serial.print(temp); Serial.print(" - temp_..."); Serial.print(temp_);
              // Serial.print(" ciclos..."); Serial.print(xx);
              // Serial.print(" promedio(microsegundos)..."); Serial.print(yy); Serial.print(" audio memory "); Serial.print(zz);
              //xx = 0;
    #endif
              temp = 0;
              t32_ = true;
              t32 = (temp_ + swingTemp_) / 2;
              go();
              writeTrigg();
              beatCount++;
              rndNumber = random(16);
              if (beatCount > 3)
              {
                beatCount = 0;
              }
            }
            else // calculamos el roll del offbeat
            {
              t32 = (temp_ - swingTemp_) / 2;
            }
          }
          _trigg = trigg;
        }
        if (((beatCount == 1) || (beatCount == 3)) && (temp >= (temp_ - swingTemp_)))
        {
          temp = 0;
          t32_ = true;
          go();
          writeTrigg();
          beatCount++;
          rndNumber = random(16);
          if (beatCount > 3)
          {
            beatCount = 0;
          }
        }
      } // fin tempo externo
    
      if (temp >= triggLength)
      {
        clearTrigg();
      }
    
      if ((t32_ == true) && (temp >= t32))
      {
        rollOn();
        t32_ = false;
      }
    }
    void go() // avanzar en la secuencia
    {
      for (i = 0; i < 8; i++)
      {
        count[i]--;
        if (count[i] < 0)
        {
          count[i] = clockDiv[actPatt][i];
          switch (pMode[actPatt][i])
          {
          case 0:
            pos[i]++;
            if (pos[i] > steps[actPatt][i])
            {
              pos[i] = 0;
            }
            break;
          case 1:
            pos[i]--;
            if (pos[i] < 0)
            {
              pos[i] = steps[actPatt][i];
            }
            break;
          case 2: // pendulum
            if (dir[i] == true)
            {
              pos[i]++;
              if (pos[i] > steps[actPatt][i])
              {
                pos[i] = steps[actPatt][i];
                dir[i] = false;
              }
            }
            else
            {
              pos[i]--;
              if (pos[i] < 0)
              {
                pos[i] = 0;
                dir[i] = true;
              }
            }
            break;
          case 3: // 4 random
            // do the random shit
            break;
          }
        }
      }
    
      if (((pMode[actPatt][0] == 0) && (pos[0] == 0)) || ((pMode[actPatt][0] == 1) && (pos[0] == steps[actPatt][0])))
      {
        // lectura del la cadena PARTE
        if (loopSize > 0) //loppsiz podria eliminarse
        {
          pattCounter++;
          if (pattCounter > loopSize[actPart])
          {
            pattCounter = 0;
          }
          if (pattCounter == loopSize[actPart])
          {
            nextPatt = part[actPart][0];
          }
          else
          {
            nextPatt = part[actPart][pattCounter + 1];
          }
        }
        actPatt = part[actPart][pattCounter];
        //actPatt = nextPatt; // pasamos al siguiente patron
        if (bitRead(masterTrack, actPatt) == true)
        {
          resetSeq();
        }
      }
      stepCount++; // esto es para 'ramifications'
    }
    void rollOn() // rehacer todo esto, de momento es solo un tipo de redoble
    {
    
      for (i = 0; i < 8; i++)
      {
        if ((bitRead(roll[actPatt][i], (pos[i])) == true) && (bitRead(dot[actPatt][i], pos[i]) == true) && (count[i] == clockDiv[actPatt][i]) && (mute[i] == false) && (rndNumber + sculpt[i] >= prob[actPatt][i][pos[i]]))
        {
          digitalWrite(triggOut[i], HIGH);
    
    #ifdef sonido
          drumSynth();
    #endif
    
    #ifdef midi_
          MIDI.sendNoteOn(midiNote[i], val[actPatt][i][pos[i]], 1);
    #endif
        }
      }
    }
    
    void writeTrigg() 
    { // si estos parametros no vamos a automatizarlos podemos quitarlos de aqui
      // reasignar estos parametros...
      /*
        tempFloat = fscale( 0, 1023, 0.00, 1.00, menuVar[1][0][revSize], 0.3 , 0);
        freeverb1.roomsize(tempFloat);
        tempFloat = fscale( 0, 1023, 0.00, 1.00, menuVar[1][0][revDamp], 0.3 , 0);
        freeverb1.damping(tempFloat);
        tempFloat = fscale( 0, 1023, 0.00, 1.00, menuVar[1][0][revL], 0.3 , 0);
        mixer[14]->gain(3, tempFloat);
        tempFloat = fscale( 0, 1023, 0.00, 1.00, menuVar[1][0][revR], 0.3 , 0);
        mixer[15]->gain(3, tempFloat);
      */
      for (i = 0; i < 8; i++)
      {
        if ((count[i] == clockDiv[actPatt][i]) && (bitRead(dot[actPatt][i], pos[i]) == true) && (mute[i] == false) && (rndNumber + sculpt[i] >= prob[actPatt][i][pos[i]]))
    
        {
          digitalWrite(triggOut[i], LOW);
    
    #ifdef midi_
          MIDI.sendNoteOn(midiNote[i], val[actPatt][i][pos[i]], 1);
    #endif
    
    #ifdef sonido
          drumSynth();
    #endif
        }
      }
    }
    
    void clearTrigg()
    {
      for (i = 0; i < 8; i++)
      {
        digitalWrite(triggOut[i], HIGH);
    #ifdef sonido
        //   envelope1.noteOff();
    #endif
      }
    #ifdef midi_
       MIDI.sendControlChange(123,0,0);
      // all note off
    #endif
    }
    
    void resetSeq()
    {
      for (i = 0; i < 8; i++)
      {
        if (pMode[actPatt][i] == 1)
        {
          pos[i] = steps[actPatt][i];
        }
        else
        {
          pos[i] = 0;
        }
      }
      beatCount = 0;
    }
    
    void actPos()
    {
      enc4 = encPos;
      _enc4 = enc4;
      enc = (enc4 * 4);
      _enc = enc;
      myEnc.write(enc);
    }
    
    void preset() // preset  write
    {
      uint32_t eeAddress = 0;
    
      EEPROM.put(eeAddress, midiNote);
      eeAddress += sizeof(midiNote);
      EEPROM.put(eeAddress, menuVar);
      eeAddress += sizeof(menuVar);
      EEPROM.put(eeAddress, modMatrix);
      eeAddress += sizeof(modMatrix);
      EEPROM.put(eeAddress, modSource);
      eeAddress += sizeof(modSource);
    }
    
    void readPreset()
    {
      uint32_t eeAddress = 0;
      EEPROM.get(eeAddress, midiNote);
      eeAddress += sizeof(midiNote);
      EEPROM.get(eeAddress, menuVar);
      eeAddress += sizeof(menuVar);
      EEPROM.get(eeAddress, modMatrix);
      eeAddress += sizeof(modMatrix);
      EEPROM.get(eeAddress, modSource);
      eeAddress += sizeof(modSource);
    }
    
    void euclFunct(int track) // cuclidean caculator
    {
      int bucket = 0;
      for (i = 0; i <= steps[actPatt][track]; i++)
      {
        bucket += euclNum[actPatt][track];
        if (bucket > steps[actPatt][track])
        {
          bucket -= (steps[actPatt][track] + 1);
          bitSet64(dot[actPatt][track], i);
        }
        else
        {
          bitClear64(dot[actPatt][track], i);
        }
      }
      rotateSeq(track);
    }
    // atencion, la rotacion no esta afectando a los otros parametros! pero esto podría implementarse facilmente
    // pero tendríamos que declarar funciones diferentes  para no rotar la secuencia cada vez que hagamos un euclidiano!
    // void rotateAll rotateAllNeg
    void rotateSeq(uint32_t track) //  rotate a sequence
    {
      bool h = bitRead(dot[actPatt][track], steps[actPatt][track]);
      for (i = steps[actPatt][track]; i > 0; i--)
      {
        bitWrite64(dot[actPatt][track], i, bitRead(dot[actPatt][track], i - 1));
      }
      bitWrite64(dot[actPatt][track], 0, h);
    }
    
    void rotateSeqNeg(uint32_t track)
    {
      bool h = bitRead(dot[actPatt][track], 0);
      for (i = 0; i < steps[actPatt][track]; i++)
      {
        bitWrite64(dot[actPatt][track], i, bitRead(dot[actPatt][track], i + 1));
      }
      bitWrite64(dot[actPatt][track], steps[actPatt][track], h);
    }
    
    void liveRecord()
    {
      // para cuatizar los golpes,
      if (temp < t32)
      {
        digitalWrite(triggOut[x], LOW);
    #ifdef midi_
        MIDI.sendNoteOn(midiNote[x], (y * 16), 1);
    #endif
    #ifdef sonido
        i = x;
        drumSynth();
    #endif
        bitWrite64(dot[actPatt][x], pos[x], recMode);
        if (recModulation)
        {
          val[actPatt][x][pos[x]] = (y * 16) - 1; // en caso de que el rango sea 0-127
        }
      }
      else
      {
        bitWrite64(dot[actPatt][x], pos[x] + 1, recMode);
        if (recModulation)
        {
          val[actPatt][x][pos[x] + 1] = (y * 16) - 1; // en caso de que el rango sea 0-127
        }
      }
      // escribimos o borramos el golpe, recMode 'insert'(true) o 'clear'(false)
    }
    
    float fscale(float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve)
    {
      //version recortada, la curva debe ser de -1.0 a 1.0 y los valores sin invertir
      float OriginalRange = 0;
      float NewRange = 0;
      float zeroRefCurVal = 0;
      float normalizedCurVal = 0;
      float rangedValue = 0;
      curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function
      OriginalRange = originalMax - originalMin;
      NewRange = newEnd - newBegin;
      zeroRefCurVal = inputValue - originalMin;
      normalizedCurVal = zeroRefCurVal / OriginalRange; // normalize to 0 - 1 float
      rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin;
      return rangedValue;
    }
    void swingCalculator()
    {
      swingTemp_ = (swingAmount * (temp_ / 3) / 100);
    }
    
    void saveAll()
    {
      /*
        if (!SD.exists("1"))
        {
        //crear directorio
        SD.mkdir("1");
        }
        else
        {
        //borrar archivos antes de escribir los nuevos
        }
    */
      File dataFile;
      SD.remove("val.dat");
      dataFile = SD.open("val.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&val, sizeof(val));
      dataFile.close();
    
      SD.remove("prob.dat");
      dataFile = SD.open("prob.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&prob, sizeof(prob));
      dataFile.close();
    
      SD.remove("steps.dat");
      dataFile = SD.open("steps.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&steps, sizeof(steps));
      dataFile.close();
    
      SD.remove("pMode.dat");
      dataFile = SD.open("pMode.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&pMode, sizeof(pMode));
      dataFile.close();
    
      SD.remove("clockDiv.dat");
      dataFile = SD.open("clockDiv.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&clockDiv, sizeof(clockDiv));
      dataFile.close();
    
      SD.remove("euclNum.dat");
      dataFile = SD.open("euclNum.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&euclNum, sizeof(euclNum));
      dataFile.close();
    
      SD.remove("dot.dat");
      dataFile = SD.open("dot.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&dot, sizeof(dot));
      dataFile.close();
    
      SD.remove("roll.dat");
      dataFile = SD.open("roll.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&roll, sizeof(roll));
      dataFile.close();
    
      SD.remove("midiNote.dat");
      dataFile = SD.open("midiNote.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&midiNote, sizeof(midiNote));
      dataFile.close();
    
      SD.remove("menuVar.dat");
      dataFile = SD.open("menuVar.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&menuVar, sizeof(menuVar));
      dataFile.close();
    
      SD.remove("noInitPatt.dat");
      dataFile = SD.open("noInitPatt.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&noInitPatt, sizeof(noInitPatt));
      dataFile.close();
    
      SD.remove("raw.dat");
      dataFile = SD.open("raw.dat", FILE_WRITE);
      dataFile.write((uint8_t *)&raw, sizeof(raw));
      dataFile.close();
    }
    void loadAll()
    {
      File dataFile;
      dataFile = SD.open("val.dat", FILE_READ);
      dataFile.read((uint8_t *)&val, sizeof(val));
      dataFile = SD.open("prob.dat", FILE_READ);
      dataFile.read((uint8_t *)&prob, sizeof(prob));
      dataFile = SD.open("steps.dat", FILE_READ);
      dataFile.read((uint8_t *)&steps, sizeof(steps));
      dataFile = SD.open("pMode.dat", FILE_READ);
      dataFile.read((uint8_t *)&pMode, sizeof(pMode));
      dataFile = SD.open("clockDiv.dat", FILE_READ);
      dataFile.read((uint8_t *)&clockDiv, sizeof(clockDiv));
      dataFile = SD.open("euclNum.dat", FILE_READ);
      dataFile.read((uint8_t *)&euclNum, sizeof(euclNum));
      dataFile = SD.open("dot.dat", FILE_READ);
      dataFile.read((uint8_t *)&dot, sizeof(dot));
      dataFile = SD.open("roll.dat", FILE_READ);
      dataFile.read((uint8_t *)&roll, sizeof(roll));
      dataFile = SD.open("midiNote.dat", FILE_READ);
      dataFile.read((uint8_t *)&midiNote, sizeof(midiNote));
      dataFile = SD.open("menuVar.dat", FILE_READ);
      dataFile.read((uint8_t *)&menuVar, sizeof(menuVar));
      dataFile = SD.open("noInitPatt.dat", FILE_READ);
      dataFile.read((uint8_t *)&noInitPatt, sizeof(noInitPatt));
      dataFile = SD.open("raw.dat", FILE_READ);
      dataFile.read((uint8_t *)&raw, sizeof(raw));
    
      dataFile.close();
    }
    void initPatt()
    {
      // inicializacion de las variables, patron inicial
      byte a;
      byte b;
      for (a = 0; a < 8; a++)
      {
        steps[actPatt][a] = 7;
        pMode[actPatt][a] = 0;
        clockDiv[actPatt][a] = 0;
        euclNum[actPatt][a] = 0;
        midiNote[a] = a * 2;
        roll[actPatt][a] = 0;
        dot[actPatt][a] = 0;
        // default settings for filter & volume
        menuVar[0][a][drumMod] = 512;
        menuVar[1][a][filterFreq] = 896;
        menuVar[1][a][volumen] = 896;
        menuVar[1][a][panoramica] = 512;
        for (b = 0; b <= maxSteps; b++)
        {
          prob[actPatt][a][b] = 0;
          val[actPatt][a][b] = 120;
        }
      }
    }
    
    void invertSeq(byte track)
    {
      dot[actPatt][track] = ~dot[actPatt][track];
    }
    
    void copyPatt()
    {
      for (i = 0; i < 8; i++)
      {
        dot[suma][i] = dot[actPatt][i];
        roll[suma][i] = roll[actPatt][i];
        steps[suma][i] = steps[actPatt][i];
        pMode[suma][i] = pMode[actPatt][i];
        clockDiv[suma][i] = clockDiv[actPatt][i];
        euclNum[suma][i] = euclNum[actPatt][i];
    
        for (byte n = 0; n < 64; n++)
        {
          prob[suma][i][n] = prob[actPatt][i][n];
          val[suma][i][n] = val[actPatt][i][n];
        }
      }
      bitSet64(noInitPatt, suma);
    }
    void drumSynth() // i es el track!
    {
    #ifdef sonido
      // VOLUMEN Y PANORAMICA
      // calculamos este valor combinando los valores de 'volumen' y 'panorámica'
    
      // L:
      float tempFloat2 = (calcMod(1, i, volumen) * (constrain((1023 - calcMod(1, i, panoramica)) * 2, 0, 1023))) / 1023;
      float tempFloat = fscale(0, 1024, 0.0, 1.0, tempFloat2, 0.3);
      mixer[(8 + ((i / 4) * 2))]->gain((i % 4), tempFloat);
    
      // R:
      tempFloat2 = (calcMod(1, i, volumen) * (constrain(calcMod(1, i, panoramica) * 2, 0, 1023))) / 1023;
      tempFloat = fscale(0, 1024, 0.0, 1.0, tempFloat2, 0.3);
      mixer[(9 + ((i / 4) * 2))]->gain((i % 4), tempFloat);
    
      // R E V E R B
      //tempFloat = fscale(0, 1024, 0.0, 1.0, calcMod(1, i, revAmount), 0.3);
      //mixer[(12 + ((i / 4) * 2))]->gain((i % 4), tempFloat);
    
      // F I L T R O
      // resonancia:
      tempFloat2 = fscale(0, 1024, 0.7, 5.0, calcMod(1, i, resonancia), 0);
    
      //cutOff:
      tempFloat = fscale(0, 1024, 20, 20000, calcMod(1, i, filterFreq), 0.4);
    
      if (menuVar[1][i][filterType] < 333)
      {
        biquad[i]->setLowpass(0, tempFloat, tempFloat2);
      }
      else if (menuVar[1][i][filterType] > 666)
      {
        biquad[i]->setHighpass(0, tempFloat, tempFloat2);
      }
      else
      {
        biquad[i]->setBandpass(0, tempFloat, tempFloat2);
      }
      /*
        // esto es para el otro filtro, ya veremos si lo usamos!
        tempFloat = fscale(0, 1024, 20, 20000, calcMod(1, i, filterFreq), 0.4);
        filter1.frequency(tempFloat);
    
        tempFloat = fscale(0, 1024, 0.7, 5.0, calcMod(1, i, resonancia), 0);
        filter1.resonance(tempFloat);
    */
    #ifdef DRUM
      if (playDrum[i] == true)
      {
    // D R U M
    #ifdef DRUMS
        tempFloat = fscale(0, 1023, 0.00, 1.00, calcMod(0, i, drumVol), 0.3);
        mixer[i]->gain(0, tempFloat);
    
        tempFloat = fscale(0, 1023, 40, 2000, calcMod(0, i, drumFreq), 0.4);
        drum[i]->frequency(tempFloat);
    
        tempFloat = fscale(0, 1023, 10, 2000, calcMod(0, i, drumDecay), 0.4);
        drum[i]->length(tempFloat);
    
        tempFloat = fscale(0, 1023, 0.0, 1.0, calcMod(0, i, drumMod), 0);
        drum[i]->pitchMod(tempFloat);
    
        tempFloat = fscale(0, 1023, 0.0, 1.0, calcMod(0, i, drumSecond), 0);
        drum[i]->secondMix(tempFloat);
    #endif
    
        //  N O I S E
        tempFloat = fscale(0, 1023, 0.00, 0.50, calcMod(0, i, noiseVol), 0.3);
        mixer[i]->gain(1, tempFloat);
    
        tempFloat = fscale(0, 1023, 1, 2000, calcMod(0, i, noiseDecay), 0.4);
        envelope[i]->decay(tempFloat);
    
    #ifdef DRUMS
        drum[i]->noteOn();
    #endif
        envelope[i]->noteOn();
      }
    #endif
    
    #ifdef SAMPLER
      if (playSample[i] == true)
      {
        sample[i]->play(muestra[raw[i]].c_str());
      }
      //      sample[i].play(AudioSampleKickwavq);
    #endif
    #endif
    }
    void makeLoop()
    {
      if (multButtMax != multButtMin)
      {
        loopSize[64] = multButtMax - multButtMin; // el array de partes va a tener un contador también,
        for (i = 0; i <= loopSize[64]; i++)
        {
          part[64][i] = i + multButtMin;
        }
        actPart = 64; // parte temporal
      }
      else
      {
        actPatt = multButtMax;
      }
      /*
        if (intTempo)
        {
        nextPatt = part[64][0]; //esperamos al siguiente ciclo si esta andando
        }
        else
        {
        actPatt = part[64][0];
        nextPatt = part[64][0];
        }
      */
      /*
        #ifdef debug
        Serial.print("\n actPatt..."); Serial.print(actPatt); Serial.print(" - nextPatt..."); Serial.print(nextPatt); //Serial.print("\n");
        #endif
      */
    }
    void invertDir()
    {
      for (i = 0; i < 8; i++)
      {
        switch (pMode[actPatt][i])
        {
        case 0:
          pMode[actPatt][i] = 1;
          break;
        case 1:
          pMode[actPatt][i] = 0;
          break;
        case 2:
          dir[i] = !dir[i];
          break;
        }
      }
    }
    // M I D I   S Y N C H
    #ifdef midiSync
    /*
      void RealTimeSystem(byte realtimebyte) {
      if (realtimebyte == 248) {
        //Serial1.write(248);
        counter++;
        if (counter == 24)
        {
          counter = 0;
          // CORCHEA
        }
    
        if (counter == 12)
        {
          //ROLL
        }
      }
    
      if (realtimebyte == START || realtimebyte == CONTINUE) {
        counter = 0;
        // PLAY
      }
    
      if (realtimebyte == STOP) {
        // STOP
      }
      }
    */
    #endif
    void checkDir()
    { /*
        for (i = 0; i < 64; i++ )
        {
        // folder = String(i);
        if ( SD.exists("1") )
        {
          bitSet64(noInitProject, i);
        }
        } */
    }
    int calcMod(byte menuIndex2, byte track2, byte menuParam2)
    {
      int result;
      int inputValue2 = menuVar[menuIndex2][track2][menuParam2];
      if (modMatrix[menuIndex2][track2][menuParam2] == 0)
      {
        result = inputValue2;
      }
      else
      {
        if (modSource[menuIndex2][track2][menuParam2] != 4)
        {
          result = constrain((inputValue2 + (cvRead[modSource[menuIndex2][track2][menuParam2]] * modMatrix[menuIndex2][track2][menuParam2] / 100)), 0, 1023);
        }
        else if (modSource[menuIndex2][track2][menuParam2] == 4) // cvSource 4 -> calculamos con VAL
        {
          result = constrain((inputValue2 + ((val[actPatt][track2][pos[track2]] * 8) * modMatrix[menuIndex2][track2][menuParam2] / 100)), 0, 1023);
        }
      }
      return result;
    }
    enc.h :
    Code:
    // E N C O D E R:
    
    // lectura inicial de del encoder
    enc = myEnc.read();
    if ( enc != _enc )
    {
      if ( enc > 255 )
      {
        enc = 0;
        myEnc.write(0);
      }
      else if ( enc < 0 )
      {
        enc = 255;
        myEnc.write(255);
      }
      enc4 = ( enc / 4);
      _enc = enc;
    }
    // valores sobre los que trabajamos ( div 4 )
    if ( enc4 != _enc4 )
    {
      if ( shuttle == true)
      {
        if ( enc4 > _enc4 )
        {
          go();
          writeTrigg();
        }
        else
        {
          invertDir();// invertir la dirección
          go();
          writeTrigg();
          invertDir();
        }
      }
      else if (menuVertical == true)
      {
        if ( enc4 > _enc4 )
        {
          menuVar[menuIndex][actRow][menuParam] += 10 ;
        }
        else
        {
          menuVar[menuIndex][actRow][menuParam] -= 10 ;
        }
        menuVar[menuIndex][actRow][menuParam] = constrain( menuVar[menuIndex][actRow][menuParam], 0, 1023 );
      }
      else if ((edit == false ) || ( editMode == 0) || ( editMode == 5 ))
      {
        encPos = enc4;
        if ( zoom == false )
        {
          actRow = ( encPos / 8 );
          actCol = ( encPos % 8 );
        }
        else
        {
          actRow = zoomTrack;
          actCol = encPos;
        }
      }
      else switch ( editMode )
        {
          case 1: // EDIT LENGTH, el formato podria ser distinto, ajustando la duracion con el click del encoder
            if (( enc4 > _enc4 ) && ( steps[actPatt][actRow] < maxSteps ))
            {
              steps[actPatt][actRow]++ ;
            }
            else if (( enc4 < _enc4 ) && ( steps[actPatt][actRow] > 0 ))
            {
              steps[actPatt][actRow]-- ;
            }
            break;
          case 2: // EDIT PLAY MODE
            if ( enc4 != _enc4)
            {
              if ( enc4 > _enc4 ) 
              {
                pMode[actPatt][actRow]++ ;
              }
              else
              {
                pMode[actPatt][actRow]-- ;
              }
              if ( pMode[actPatt][actRow] > 250 )
              {
                pMode[actPatt][actRow] = 2;
              }
              else if ( pMode[actPatt][actRow] > 2 )
              {
                pMode[actPatt][actRow] = 0;
              }
            }
            break;
          case 3: // EDIT STEP REPEAT
            if (( enc4 > _enc4 ) && ( clockDiv[actPatt][actRow] < 8 ))
            {
              clockDiv[actPatt][actRow]++ ;
            }
            else if (( enc4 < _enc4 ) && ( clockDiv[actPatt][actRow] > 0 ))
            {
              clockDiv[actPatt][actRow]-- ;
            }
            break;
          case 4: // P R O B A B I L I D A D - funciona al reves, menos es mas!
            if ( bitRead(dot[actPatt][actRow], actCol) == true )
            {
              if (( enc4 > _enc4 ) && ( prob[actPatt][actRow][actCol] > 0 ))
              {
                prob[actPatt][actRow][actCol]-- ;
              }
              else if (( enc4 < _enc4 ) && ( prob[actPatt][actRow][actCol] < 15 ))
              {
                prob[actPatt][actRow][actCol]++ ;
              }
            }
            break;
          case 6:
            // R O T A T E
            if ( enc4 > _enc4 )
            {
              rotateSeq(actRow);
            }
            else
            {
              rotateSeqNeg(actRow);
            }
            break;
          case 7:
            // E U C L I D E A N
            if ( enc4 > _enc4 )
            {
              if ( euclNum[actPatt][actRow] <= steps[actPatt][actRow] )
              {
                euclNum[actPatt][actRow]++ ;
              }
            }
            else if ( euclNum[actPatt][actRow] > 0 )
            {
              euclNum[actPatt][actRow]-- ;
            }
            euclFunct(actRow);
            break;
          case 8:
            // T E M P O
            if ( enc4 > _enc4 )
            {
              tempo++ ;
            }
            else
            {
              tempo-- ;
            }
            tempo = constrain(tempo, 10, 250);
            temp_ = 15000000 / tempo;
            // max   1500000
            // min     60000
            t32 = temp_ / 2;
            swingCalculator();
            break;
          case 9:  // edicion nota midi
            if ( enc4 > _enc4 )
            {
              if ( midiNote[actRow] < 127 )
              {
                midiNote[actRow] ++ ;
              }
            }
            else
            {
              if ( midiNote[actRow] > 0 )
              {
                midiNote[actRow] -- ;
              }
            }
            MIDI.sendNoteOn( midiNote[actRow], 120, 1);
            break;
          case 10: // V A L
            // edicion del valor q usaremos para velocidad midi
            if (multButt == -1) // no hay multiples bottones,
            {
              if ( enc4 > _enc4 )
              {
                if ( val[actPatt][actRow][actCol] < 127 )
                {
                  val[actPatt][actRow][actCol] ++ ;
                }
              }
              else
              {
                if ( val[actPatt][actRow][actCol] > 0 )
                {
                  val[actPatt][actRow][actCol] -- ;
                }
              }
            }
            else if (!zoom)// si hay pulsado! no hay zoom
            {
              byte xx;
              byte yy;
              uint8_t longitud = 127 / (1 + multButtMax - multButtMin);
              byte rampa = 0;
              if ( enc4 > _enc4 )
              {
                for (i = multButtMin; i <= multButtMax; i ++)
                {
                  xx = i / 8;
                  page[xx] = ( pos[xx] / 8 );
                  yy = (i % 8) + (page[xx] *8);
                  rampa ++;
                  val[actPatt][xx][yy] = rampa * longitud;
                }
              }
              else // enc4 < _enc4
              {
                for ( i = multButtMax; i >= multButtMin; i -- )
                {
                  xx = i / 8;
                  page[xx] = ( pos[xx] / 8 );
                  yy = (i % 8) + (page[xx] *8);
                  rampa ++;
                  val[actPatt][xx][yy] = rampa * longitud;
                }
              }
            }
            else // si hay zoom:
            {
              byte longitud = 1 + multButtMax - multButtMin;
              byte rampa = 0;
              if ( enc4 > _enc4 )
              {
                for (i = multButtMin; i <= multButtMax; i ++)
                {
                  rampa ++;
                  val[actPatt][zoomTrack][i] = rampa * (127 / longitud);
                }
              }
              else // enc4 < _enc4
              {
                for ( i = multButtMax; i >= multButtMin; i -- )
                {
                  rampa ++;
                  val[actPatt][zoomTrack][i] = rampa * (127 / longitud);
                }
              }
            }
            break;
          case 13: // S W I N G
            if ( enc4 > _enc4 )
            {
              if (swingAmount < 100)
              {
                swingAmount ++ ;
              }
            }
            else
            {
              if (swingAmount > 0)
              {
                swingAmount -- ;
              }
            }
            swingCalculator();
            break;
          case 12: // B R I G H T N E S S
            if ( enc4 > _enc4 )
            {
              BRIGHTNESS ++ ;
            }
            else
            {
              BRIGHTNESS -- ;
            }
            constrain(BRIGHTNESS, 5, 250);
            leds.setBrightness(BRIGHTNESS);
            break;
          case 14: // modulacion...de audio de momento
            if (actCol > 0)
            {
              if ( enc4 > _enc4 )
              {
                modMatrix[menuIndex][actRow][actCol - 1] ++ ; //  el -1 es por el offset de los parametrosmostrados
              }
              else
              {
                modMatrix[menuIndex][actRow][actCol - 1] -- ;
              }
              modMatrix[menuIndex][actRow][actCol - 1] = constrain(modMatrix[menuIndex][actRow][actCol - 1], -100, 100);
              break;
            }
          // no se x q esto no funciona
          case 17: //M U T E
            encPos -= (encPos % 8) ;
            break;
          case 23:
            if ( enc4 > _enc4 )
            {
              raw[actRow]++ ;
            }
            else
            {
              raw[actRow] -- ;
            }
            if (raw[actRow] > 63)
            {
              raw[actRow] = 0;
            }
            else if (raw[actRow] < 0)
            {
              raw[actRow] = 63;
            }
            break;
        }
      _enc4 = enc4;
    }

  7. #7
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,417
    Moving the global variables to local (within a function) has probably also moved the bug. It may still be clobbering memory but at the moment it is not clobbering something that is critical. It might never cause a problem again. Or, later on when you make a few changes, it'll rear its ugly head again but in a completely different way.
    At the moment, I can't see any obvious places where an array index is out of bounds. But having three very similar names for arrays can lead to confusion:
    Code:
    bool butt[8][10];    // lectura de los pads,
    bool _butt[8][10];  // comparador
    bool butt_[8][8];  // estado del boton, las dos ultimas columnas no se estanb utilizando
    especially when one of them has different size than the other two.

    But if the code is working, just keep going and hope that it stays that way
    If it dies, post your code again and I'll have a look at it.

    Pete

  8. #8
    Junior Member
    Join Date
    Sep 2019
    Location
    Sevilla, Spain
    Posts
    19
    I've moved some variables, but also reduced some of them or deleted some unused ones.
    Quote Originally Posted by el_supremo View Post
    At the moment, I can't see any obvious places where an array index is out of bounds. But having three very similar names for arrays can lead to confusion:
    Code:
    bool butt[8][10];    // lectura de los pads,
    bool _butt[8][10];  // comparador
    bool butt_[8][8];  // estado del boton, las dos ultimas columnas no se estanb utilizando
    especially when one of them has different size than the other two.
    Pete
    This part is correct, the first variable is to read the button matrix, the second to compare with the previous reading and the third to store the state. The last columns of the matrix are function buttons and that variable is not used in the code.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •