about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicholas Fox <nicholas.k.fox@gmail.com>2024-04-02 17:51:20 -0400
committerZach DeCook <zachdecook@librem.one>2024-04-02 18:08:40 -0400
commitb56e149abf9031607b080d659fb8a98fe5a33e06 (patch)
treef933c738be092a1a52dc88ce0f96524418667e3f
parent852cf4723dc9f51a910491cc4039dec569cea491 (diff)
downloadHexBoard-b56e149abf9031607b080d659fb8a98fe5a33e06.tar.gz
Fixup lines broken by email client
-rw-r--r--HexBoard_V1.1.ino409
1 files changed, 136 insertions, 273 deletions
diff --git a/HexBoard_V1.1.ino b/HexBoard_V1.1.ino
index fb03d9a..d75c2f7 100644
--- a/HexBoard_V1.1.ino
+++ b/HexBoard_V1.1.ino
@@ -10,8 +10,7 @@
   // list of things remaining to do:
   // -- program the wheel -- OK!
   // -- put back the animations -- OK!
-  // -- test MPE working on iPad garageband -- works on pianoteq
-without MPE; need to get powered connection to iOS.
+  // -- test MPE working on iPad garageband -- works on pianoteq without MPE; need to get powered connection to iOS.
   // -- volume control test on buzzer
   // -- save and load presets
   // -- sequencer restore
@@ -20,17 +19,13 @@ without MPE; need to get powered connection to iOS.
   #include <Arduino.h>
   #include <Wire.h>
   #include <LittleFS.h>
-  #include <queue>              // std::queue construct to store open
-channels in microtonal mode
+  #include <queue>              // std::queue construct to store open channels in microtonal mode
   const byte diagnostics = 1;
 // ====== initialize timers
 
-  uint32_t runTime = 0;                 // Program loop consistent
-variable for time in milliseconds since power on
-  uint32_t lapTime = 0;                 // Used to keep track of how
-long each loop takes. Useful for rate-limiting.
-  uint32_t loopTime = 0;               // Used to check speed of the
-loop in diagnostics mode 4
+  uint32_t runTime = 0;                 // Program loop consistent variable for time in milliseconds since power on
+  uint32_t lapTime = 0;                 // Used to keep track of how long each loop takes. Useful for rate-limiting.
+  uint32_t loopTime = 0;               // Used to check speed of the loop in diagnostics mode 4
 
 // ====== initialize SDA and SCL pins for hardware I/O
 
@@ -44,14 +39,10 @@ loop in diagnostics mode 4
   Adafruit_USBD_MIDI usb_midi;
   MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI);
   float concertA = 440.0;               // tuning of A4 in Hz
-  byte MPE = 0; // microtonal mode. if zero then attempt to
-self-manage multiple channels.
-              // if one then on certain synths that are MPE compatible
-will send in that mode.
-  int16_t channelBend[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0 };  // what's the current note bend on this channel
-  byte channelPoly[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0 };      // how many notes are playing on this channel
+  byte MPE = 0; // microtonal mode. if zero then attempt to self-manage multiple channels.
+              // if one then on certain synths that are MPE compatible will send in that mode.
+  int16_t channelBend[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };  // what's the current note bend on this channel
+  byte channelPoly[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };      // how many notes are playing on this channel
   std::queue<byte> openChannelQueue;
   const byte defaultPBRange = 2;
 
@@ -59,19 +50,15 @@ will send in that mode.
 
   #include <Adafruit_NeoPixel.h>
   const byte multiplexPins[] = { 4, 5, 2, 3 };  // m1p, m2p, m4p, m8p
-  const byte rowCount = 14;                     // The number of rows
-in the matrix
+  const byte rowCount = 14;                     // The number of rows in the matrix
   const byte columnPins[] = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
-  const byte colCount = sizeof(columnPins);  // The number of columns
-in the matrix
-  const byte hexCount = colCount * rowCount;  // The number of
-elements in the matrix
+  const byte colCount = sizeof(columnPins);  // The number of columns in the matrix
+  const byte hexCount = colCount * rowCount;  // The number of elements in the matrix
   const byte LEDPin = 22;
   Adafruit_NeoPixel strip(hexCount, LEDPin, NEO_GRB + NEO_KHZ800);
   enum { NoAnim, StarAnim, SplashAnim, OrbitAnim, OctaveAnim, NoteAnim };
   byte animationType = 0;
-  byte animationFPS = 32; // actually frames per 2^10 seconds. close
-enough to 30fps
+  byte animationFPS = 32; // actually frames per 2^10 seconds. close enough to 30fps
   int16_t rainbowDegreeTime = 64; // ms to go through 1/360 of rainbow.
 // ====== initialize hex state object
 
@@ -81,26 +68,19 @@ enough to 30fps
     int8_t col;
   } coordinates;
   typedef struct {
-    byte keyState = 0;          // binary 00 = off, 01 = just pressed,
-10 = just released, 11 = held
+    byte keyState = 0;          // binary 00 = off, 01 = just pressed, 10 = just released, 11 = held
     coordinates coords = {0,0};
     uint32_t timePressed = 0;   // timecode of last press
     uint32_t LEDcolorAnim = 0;      //
     uint32_t LEDcolorPlay = 0;      //
     uint32_t LEDcolorOn = 0;   //
     uint32_t LEDcolorOff = 0;  //
-    bool animate = 0;           // hex is flagged as part of the
-animation in this frame
-    int16_t steps = 0;          // number of steps from key center
-(semitones in 12EDO; microtones if >12EDO)
-    bool isCmd = 0;             // 0 if it's a MIDI note; 1 if it's a
-MIDI control cmd
-    bool inScale = 0;           // 0 if it's not in the selected
-scale; 1 if it is
-    byte note = 255;            // MIDI note or control parameter
-corresponding to this hex
-    int16_t bend;               // in microtonal mode, the pitch bend
-for this note needed to be tuned correctly
+    bool animate = 0;           // hex is flagged as part of the animation in this frame
+    int16_t steps = 0;          // number of steps from key center (semitones in 12EDO; microtones if >12EDO)
+    bool isCmd = 0;             // 0 if it's a MIDI note; 1 if it's a MIDI control cmd
+    bool inScale = 0;           // 0 if it's not in the selected scale; 1 if it is
+    byte note = 255;            // MIDI note or control parameter corresponding to this hex
+    int16_t bend;               // in microtonal mode, the pitch bend for this note needed to be tuned correctly
     byte channel;               // what MIDI channel this note is playing on
     float frequency;            // what frequency to ring on the buzzer
     void updateKeyState(bool keyPressed) {
@@ -212,12 +192,10 @@ for this note needed to be tuned correctly
   #define GEM_DISABLE_GLCD
   U8G2_SH1107_SEEED_128X128_F_HW_I2C u8g2(U8G2_R2, U8X8_PIN_NONE);
   GEM_u8g2 menu(u8g2, GEM_POINTER_ROW, GEM_ITEMS_COUNT_AUTO, 10, 10,
-78); // menu item height; page screen top offset; menu values left
-offset
+78); // menu item height; page screen top offset; menu values left offset
   const byte defaultContrast = 63;           // GFX default contrast
   bool screenSaverOn = 0;                    //
-  uint32_t screenTime = 0;                   // GFX timer to count if
-screensaver should go on
+  uint32_t screenTime = 0;                   // GFX timer to count if screensaver should go on
   const uint32_t screenSaverMillis = 10000; //
 
 // ====== initialize piezo buzzer
@@ -227,8 +205,7 @@ screensaver should go on
   //RP2040_Volume piezoBuzzer(tonePin, tonePin);
   byte buzzer = 0;                      // buzzer state
   byte currentBuzzNote = 255;           // need to work on this
-  uint32_t currentBuzzTime = 0;         // Used to keep track of when
-this note started buzzin
+  uint32_t currentBuzzTime = 0;         // Used to keep track of when this note started buzzin
   uint32_t arpeggiateLength = 10;       //
 
 // ====== initialize tuning (microtonal) presets
@@ -245,8 +222,7 @@ this note started buzzin
     CarlosA, CarlosB, CarlosG
   };
   tuningDef tuningOptions[] = {
-    // replaces the idea of const byte EDO[] = { 12, 17, 19, 22, 24,
-31, 41, 53, 72 };
+    // replaces the idea of const byte EDO[] = { 12, 17, 19, 22, 24, 31, 41, 53, 72 };
     { (char*)"12 EDO",           12,  100.0 },
     { (char*)"17 EDO",           17, 1200.0 / 17 },
     { (char*)"19 EDO",           19, 1200.0 / 19 },
@@ -291,12 +267,9 @@ this note started buzzin
     { (char*)"Full Layout",       1, 65,  -1,  -9, TwentyFour },
     { (char*)"Bosanquet, 31",     0, 65,  -2,  -3, ThirtyOne  },
     { (char*)"Full Layout",       1, 65,  -1,  -9, ThirtyOne  },
-    { (char*)"Bosanquet, 41",     0, 65,  -4,  -3, FortyOne   },  //
-forty-one #1
-    { (char*)"Gerhard, 41",       0, 65,   3, -10, FortyOne   },  //
-forty-one #2
-    { (char*)"Full Layout, 41",   0, 65,  -1,  -8, FortyOne   },  //
-forty-one #3
+    { (char*)"Bosanquet, 41",     0, 65,  -4,  -3, FortyOne   },  // forty-one #1
+    { (char*)"Gerhard, 41",       0, 65,   3, -10, FortyOne   },  // forty-one #2
+    { (char*)"Full Layout, 41",   0, 65,  -1,  -8, FortyOne   },  // forty-one #3
     { (char*)"Wicki-Hayden, 53",  1, 64,   9, -31, FiftyThree },
     { (char*)"Harmonic Tbl, 53",  0, 75, -31,  14, FiftyThree },
     { (char*)"Bosanquet, 53",     0, 65,  -5,  -4, FiftyThree },
@@ -319,66 +292,40 @@ forty-one #3
   scaleDef scaleOptions[] = {
     { (char*)"None",              255,        { 255,        255,
   255,255,255,255,255,255,255,255,255,255,255,255,255,255} },
-    { (char*)"Major",             Twelve,     { 0b10101101,
-0b0101'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Minor, natural",    Twelve,     { 0b10110101,
-0b1010'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Minor, melodic",    Twelve,     { 0b10110101,
-0b0101'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Minor, harmonic",   Twelve,     { 0b10110101,
-0b1001'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Pentatonic, major", Twelve,     { 0b10101001,
-0b0100'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Pentatonic, minor", Twelve,     { 0b10010101,
-0b0010'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Blues",             Twelve,     { 0b10010111,
-0b0010'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Double Harmonic",   Twelve,     { 0b11001101,
-0b1001'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Phrygian",          Twelve,     { 0b11010101,
-0b1010'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Phrygian Dominant", Twelve,     { 0b11001101,
-0b1010'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Dorian",            Twelve,     { 0b10110101,
-0b0110'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Lydian",            Twelve,     { 0b10101011,
-0b0101'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Lydian Dominant",   Twelve,     { 0b10101011,
-0b0110'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Mixolydian",        Twelve,     { 0b10101101,
-0b0110'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Locrian",           Twelve,     { 0b11010110,
-0b1010'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Whole tone",        Twelve,     { 0b10101010,
-0b1010'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Octatonic",         Twelve,     { 0b10110110,
-0b1101'0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Rast maqam",        TwentyFour, { 0b10001001,
-0b00100010, 0b00101100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
-    { (char*)"Rast makam",        FiftyThree, { 0b10000000,
-0b01000000, 0b01000010, 0b00000001,
-                                                0b00000000,
-0b10001000, 0b10000'000, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Major",             Twelve,     { 0b10101101, 0b01010000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Minor, natural",    Twelve,     { 0b10110101, 0b10100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Minor, melodic",    Twelve,     { 0b10110101, 0b01010000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Minor, harmonic",   Twelve,     { 0b10110101, 0b10010000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Pentatonic, major", Twelve,     { 0b10101001, 0b01000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Pentatonic, minor", Twelve,     { 0b10010101, 0b00100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Blues",             Twelve,     { 0b10010111, 0b00100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Double Harmonic",   Twelve,     { 0b11001101, 0b10010000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Phrygian",          Twelve,     { 0b11010101, 0b10100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Phrygian Dominant", Twelve,     { 0b11001101, 0b10100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Dorian",            Twelve,     { 0b10110101, 0b01100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Lydian",            Twelve,     { 0b10101011, 0b01010000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Lydian Dominant",   Twelve,     { 0b10101011, 0b01100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Mixolydian",        Twelve,     { 0b10101101, 0b01100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Locrian",           Twelve,     { 0b11010110, 0b10100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Whole tone",        Twelve,     { 0b10101010, 0b10100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Octatonic",         Twelve,     { 0b10110110, 0b11010000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Rast maqam",        TwentyFour, { 0b10001001, 0b00100010, 0b00101100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+    { (char*)"Rast makam",        FiftyThree, { 0b10000000, 0b01000000, 0b01000010, 0b00000001,
+                                                0b00000000, 0b10001000, 0b10000000, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
   };
   const byte scaleCount = sizeof(scaleOptions) / sizeof(scaleDef);
   byte scaleLock = 0;    // menu wants this to be an int, not a bool
 
 // ====== initialize key coloring routines
 
-  enum colors      { W,    R,    O,    Y,    L,    G,    C,    B,
-I,    P,    M,
-                          r,    o,    y,    l,    g,    c,    b,    i,
-   p,    m     };
+  enum colors      { W,    R,    O,    Y,    L,    G,    C,    B,    I,    P,    M,
+                          r,    o,    y,    l,    g,    c,    b,    i,   p,    m     };
   enum { DARK = 0, VeryDIM = 1, DIM = 32, BRIGHT = 127, VeryBRIGHT = 255 };
   enum { GRAY = 0, DULL = 127, VIVID = 255 };
-  float hueCode[] = { 0.0, 0.0, 36.0, 72.0, 108.0, 144.0, 180.0,
-216.0, 252.0, 288.0, 324.0,
-                           0.0, 36.0, 72.0, 108.0, 144.0, 180.0,
-216.0, 252.0, 288.0, 324.0  };
-  byte satCode[] = { GRAY,
-VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,
-                          DULL, DULL, DULL, DULL, DULL, DULL, DULL,
-DULL, DULL, DULL  };
+  float hueCode[] = { 0.0, 0.0, 36.0, 72.0, 108.0, 144.0, 180.0, 216.0, 252.0, 288.0, 324.0,
+                           0.0, 36.0, 72.0, 108.0, 144.0, 180.0, 216.0, 252.0, 288.0, 324.0  };
+  byte satCode[] = { GRAY, VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,VIVID,
+                          DULL, DULL, DULL, DULL, DULL, DULL, DULL, DULL, DULL, DULL  };
   byte colorMode = 0;
   byte perceptual = 1;
   enum {assignDefault = -1}; // auto-determine this component of color
@@ -754,12 +701,9 @@ DULL, DULL, DULL  };
   const int keyCount = sizeof(keyOptions) / sizeof(keyDef);
 // ====== initialize structure to store and recall user preferences
 
-  typedef struct { // put all user-selectable options into a class so
-that down the line these can be saved and loaded.
+  typedef struct { // put all user-selectable options into a class so that down the line these can be saved and loaded.
     char* presetName;
-    int tuningIndex;     // instead of using pointers, i chose to
-store index value of each option, to be saved to a .pref or .ini or
-something
+    int tuningIndex;     // instead of using pointers, i chose to store index value of each option, to be saved to a .pref or .ini or something
     int layoutIndex;
     int scaleIndex;
     int keyIndex;
@@ -856,17 +800,14 @@ something
     temp.col = destination.col - origin.col;
     return temp;
   }
-  float freqToMIDI(float Hz) {             // formula to convert from
-Hz to MIDI note
+  float freqToMIDI(float Hz) {             // formula to convert from Hz to MIDI note
     return 69.0 + 12.0 * log2f(Hz / 440.0);
   }
-  float MIDItoFreq(float MIDI) {           // formula to convert from
-MIDI note to Hz
+  float MIDItoFreq(float MIDI) {           // formula to convert from MIDI note to Hz
     return 440.0 * exp2((MIDI - 69.0) / 12.0);
   }
   float stepsToMIDI(int16_t stepsFromA) {  // return the MIDI pitch associated
-    return freqToMIDI(concertA) + ((float)stepsFromA *
-(float)current.tuning().stepSize / 100.0);
+    return freqToMIDI(concertA) + ((float)stepsFromA * (float)current.tuning().stepSize / 100.0);
   }
 
 // ====== diagnostic wrapper
@@ -883,32 +824,25 @@ MIDI note to Hz
     if ((!perceptual) || (D > 360.0)) {
       return 65536 * (D / 360.0);
     } else {
-      //                red             yellow                 green
-            blue
-      int hueIn[] =  {    0,    9,   18,   90,  108,  126,  135,  150,
- 198,  243,  252,  261,  306,  333,  360};
-      //          #ff0000            #ffff00           #00ff00
-#00ffff     #0000ff     #ff00ff
-      int hueOut[] = {    0, 3640,
-5461,10922,12743,16384,21845,27306,32768,38229,43690,49152,54613,58254,65535};
+      //                red             yellow                 green            blue
+      int hueIn[] =  {    0,    9,   18,   90,  108,  126,  135,  150,  198,  243,  252,  261,  306,  333,  360};
+      //          #ff0000            #ffff00           #00ff00 #00ffff     #0000ff     #ff00ff
+      int hueOut[] = {    0, 3640, 5461,10922,12743,16384,21845,27306,32768,38229,43690,49152,54613,58254,65535};
       byte B = 0;
       while (D - hueIn[B] > 0) {
         B++;
       };
-      return hueOut[B - 1] + (hueOut[B] - hueOut[B - 1]) * ((D -
-(float)hueIn[B - 1])/(float)(hueIn[B] - hueIn[B - 1]));
+      return hueOut[B - 1] + (hueOut[B] - hueOut[B - 1]) * ((D - (float)hueIn[B - 1])/(float)(hueIn[B] - hueIn[B - 1]));
     };
   }
-  void resetHexLEDs() { // calculate color codes for each hex, store
-for playback
+  void resetHexLEDs() { // calculate color codes for each hex, store for playback
     int16_t hue;
     float hueDegrees;
     byte sat;
     colors c;
     for (byte i = 0; i < hexCount; i++) {
       if (!(h[i].isCmd)) {
-        byte scaleDegree = positiveMod(h[i].steps +
-current.key().offset - current.findC(),current.tuning().cycleLength);
+        byte scaleDegree = positiveMod(h[i].steps + current.key().offset - current.findC(),current.tuning().cycleLength);
         switch (colorMode) {
           case 1:
             c = keyOptions[current.keysBegin() + scaleDegree].tierColor;
@@ -916,8 +850,7 @@ current.key().offset - current.findC(),current.tuning().cycleLength);
             sat = satCode[c];
             break;
           default:
-            hueDegrees = 360.0 * ((float)scaleDegree /
-(float)current.tuning().cycleLength);
+            hueDegrees = 360.0 * ((float)scaleDegree / (float)current.tuning().cycleLength);
             sat = 255;
             break;
         };
@@ -934,13 +867,11 @@ current.key().offset - current.findC(),current.tuning().cycleLength);
 
 // ====== layout routines
 
-  void assignPitches() {     // run this if the layout, key, or
-transposition changes, but not if color or scale changes
+  void assignPitches() {     // run this if the layout, key, or transposition changes, but not if color or scale changes
     sendToLog("assignPitch was called:");
     for (byte i = 0; i < hexCount; i++) {
       if (!(h[i].isCmd)) {
-        float N = stepsToMIDI(h[i].steps + current.key().offset +
-current.transpose);
+        float N = stepsToMIDI(h[i].steps + current.key().offset + current.transpose);
         if (N < 0 || N >= 128) {
           h[i].note = 255;
           h[i].bend = 0;
@@ -989,8 +920,7 @@ current.transpose);
     sendToLog("buildLayout was called:");
     for (byte i = 0; i < hexCount; i++) {
       if (!(h[i].isCmd)) {
-        coordinates dist =
-hexDistance(h[current.layout().rootHex].coords, h[i].coords);
+        coordinates dist = hexDistance(h[current.layout().rootHex].coords, h[i].coords);
         h[i].steps = (
           (dist.col * current.layout().acrossSteps) +
           (dist.row * (
@@ -1004,11 +934,9 @@ hexDistance(h[current.layout().rootHex].coords, h[i].coords);
         ));
       };
     };
-    applyScale();        // when layout changes, have to re-apply
-scale and re-apply LEDs
+    applyScale();        // when layout changes, have to re-apply scale and re-apply LEDs
     assignPitches();     // same with pitches
-    u8g2.setDisplayRotation(current.layout().isPortrait ? U8G2_R2 :
-U8G2_R1);     // and landscape / portrait rotation
+    u8g2.setDisplayRotation(current.layout().isPortrait ? U8G2_R2 : U8G2_R1);     // and landscape / portrait rotation
     sendToLog("buildLayout complete.");
   }
 // ====== buzzer routines
@@ -1027,10 +955,8 @@ U8G2_R1);     // and landscape / portrait rotation
   void buzz(byte x) {        // send 128 or larger to turn off tone
     currentBuzzNote = x;
     if ((!(h[x].isCmd)) && (h[x].note < 128) && (h[x].frequency < 32767)) {
-      //piezoBuzzer.tone(h[x].frequency, (float)velWheel.curValue *
-(100.0 / 128.0), 16384, TIME_MS);
-      tone(tonePin, h[x].frequency);     // stock TONE library, but
-frequency changed to float
+      //piezoBuzzer.tone(h[x].frequency, (float)velWheel.curValue * (100.0 / 128.0), 16384, TIME_MS);
+      tone(tonePin, h[x].frequency);     // stock TONE library, but frequency changed to float
     } else {
       //piezoBuzzer.stop_tone();
       noTone(tonePin);                     // stock TONE library
@@ -1057,23 +983,17 @@ frequency changed to float
     ));
   }
   void prepMIDIforMicrotones() {
-    bool makeZone = (MPE && (current.tuningIndex != Twelve)); // if
-MPE flag is on and tuning <> 12EDO
-    setMPEzone(1, (8 * makeZone));   // MPE zone 1 = ch 2 thru 9 (or
-reset if not using MPE)
+    bool makeZone = (MPE && (current.tuningIndex != Twelve)); // if MPE flag is on and tuning <> 12EDO
+    setMPEzone(1, (8 * makeZone));   // MPE zone 1 = ch 2 thru 9 (or reset if not using MPE)
     delay(ccMsgCoolDown);
-    setMPEzone(16, (5 * makeZone));  // MPE zone 16 = ch 11 thru 15
-(or reset if not using MPE)
+    setMPEzone(16, (5 * makeZone));  // MPE zone 16 = ch 11 thru 15 (or reset if not using MPE)
     delay(ccMsgCoolDown);
     for (byte i = 1; i <= 16; i++) {
-      setPitchBendRange(i, defaultPBRange);  // some synths try to set
-PB range to 48 semitones.
-      delay(ccMsgCoolDown);                  // this forces it back to
-the expected range of 2 semitones.
+      setPitchBendRange(i, defaultPBRange);  // some synths try to set PB range to 48 semitones.
+      delay(ccMsgCoolDown);                  // this forces it back to the expected range of 2 semitones.
       if ((i != 10) && ((!makeZone) || ((i > 1) && (i < 16)))) {
         openChannelQueue.push(i);
-        sendToLog(String("pushed ch " + String(i) + " to the open
-channel queue"));
+        sendToLog(String("pushed ch " + String(i) + " to the open channel queue"));
       };
       channelBend[i - 1] = 0;
       channelPoly[i - 1] = 0;
@@ -1082,40 +1002,32 @@ channel queue"));
   void chgModulation() {
   if (current.tuningIndex == Twelve) {
       MIDI.sendControlChange(1, modWheel.curValue, 1);
-      sendToLog(String("sent mod value " + String(modWheel.curValue) +
-" to ch 1"));
+      sendToLog(String("sent mod value " + String(modWheel.curValue) + " to ch 1"));
     } else if (MPE) {
       MIDI.sendControlChange(1, modWheel.curValue, 1);
-      sendToLog(String("sent mod value " + String(modWheel.curValue) +
-" to ch 1"));
+      sendToLog(String("sent mod value " + String(modWheel.curValue) + " to ch 1"));
       MIDI.sendControlChange(1, modWheel.curValue, 16);
-      sendToLog(String("sent mod value " + String(modWheel.curValue) +
-" to ch 16"));
+      sendToLog(String("sent mod value " + String(modWheel.curValue) + " to ch 16"));
     } else {
       for (byte i = 0; i < 16; i++) {
         MIDI.sendControlChange(1, modWheel.curValue, i + 1);
-        sendToLog(String("sent mod value " + String(modWheel.curValue)
-+ " to ch " + String(i+1)));
+        sendToLog(String("sent mod value " + String(modWheel.curValue) + " to ch " + String(i+1)));
       };
     };
   };
   void chgUniversalPB() {
     if (current.tuningIndex == Twelve) {
       MIDI.sendPitchBend(pbWheel.curValue, 1);
-      sendToLog(String("sent pb value " + String(pbWheel.curValue) + "
-to ch 1"));
+      sendToLog(String("sent pb value " + String(pbWheel.curValue) + " to ch 1"));
     } else if (MPE) {
       MIDI.sendPitchBend(pbWheel.curValue, 1);
-      sendToLog(String("sent pb value " + String(pbWheel.curValue) + "
-to ch 1"));
+      sendToLog(String("sent pb value " + String(pbWheel.curValue) + " to ch 1"));
       MIDI.sendPitchBend(pbWheel.curValue, 16);
-      sendToLog(String("sent pb value " + String(pbWheel.curValue) + "
-to ch 16"));
+      sendToLog(String("sent pb value " + String(pbWheel.curValue) + " to ch 16"));
     } else {
       for (byte i = 0; i < 16; i++) {
         MIDI.sendPitchBend(channelBend[i] + pbWheel.curValue, i + 1);
-        sendToLog(String("sent pb value " + String(channelBend[i] +
-pbWheel.curValue) + " to ch " + String(i+1)));
+        sendToLog(String("sent pb value " + String(channelBend[i] + pbWheel.curValue) + " to ch " + String(i+1)));
       };
     };
   }
@@ -1125,20 +1037,16 @@ pbWheel.curValue) + " to ch " + String(i+1)));
       return 1;
     } else {
       byte temp = 17;
-      for (byte c = MPE; c < (16 - MPE); c++) {  // MPE - look at ch 2
-thru 15 [c 1-14]; otherwise ch 1 thru 16 [c 0-15]
-        if ((c + 1 != 10) && (h[x].bend == channelBend[c])) {  // not
-using drum channel ch 10 in either case
+      for (byte c = MPE; c < (16 - MPE); c++) {  // MPE - look at ch 2 thru 15 [c 1-14]; otherwise ch 1 thru 16 [c 0-15]
+        if ((c + 1 != 10) && (h[x].bend == channelBend[c])) {  // not using drum channel ch 10 in either case
           temp = c + 1;
-          sendToLog(String("found a matching channel: ch " +
-String(temp) + " has pitch bend " + String(channelBend[c])));
+          sendToLog(String("found a matching channel: ch " + String(temp) + " has pitch bend " + String(channelBend[c])));
           break;
         };
       };
       if (temp = 17) {
         if (openChannelQueue.empty()) {
-          sendToLog(String("channel queue was empty so we didn't send
-a note on"));
+          sendToLog(String("channel queue was empty so we didn't send a note on"));
         } else {
           temp = openChannelQueue.front();
           openChannelQueue.pop();
@@ -1226,20 +1134,14 @@ a note on"));
   }
   void animateMirror() {
     for (byte i = 0; i < hexCount; i++) {                   // check every hex
-      if ((!(h[i].isCmd)) && (h[i].channel)) {              // that is
-a held note
-        for (byte j = 0; j < hexCount; j++) {               // compare
-to every hex
-          if ((!(h[j].isCmd)) && (!(h[j].channel))) {       // that is
-a note not being played
-            int16_t temp = h[i].steps - h[j].steps;         // look at
-difference between notes
-            if (animationType == OctaveAnim) {              // set
-octave diff to zero if need be
+      if ((!(h[i].isCmd)) && (h[i].channel)) {              // that is a held note
+        for (byte j = 0; j < hexCount; j++) {               // compare to every hex
+          if ((!(h[j].isCmd)) && (!(h[j].channel))) {       // that is a note not being played
+            int16_t temp = h[i].steps - h[j].steps;         // look at difference between notes
+            if (animationType == OctaveAnim) {              // set octave diff to zero if need be
               temp = positiveMod(temp, current.tuning().cycleLength);
             };
-            if (temp == 0) {                                //
-highlight if diff is zero
+            if (temp == 0) {                                // highlight if diff is zero
               h[j].animate = 1;
             };
           };
@@ -1248,12 +1150,9 @@ highlight if diff is zero
     };
   }
   void animateOrbit() {
-    for (byte i = 0; i < hexCount; i++) {
- // check every hex
-      if ((!(h[i].isCmd)) && (h[i].channel)) {
- // that is a held note
-        flagToAnimate(hexOffset(h[i].coords,hexVector((h[i].animFrame()
-% 6),1)));       // different neighbor each frame
+    for (byte i = 0; i < hexCount; i++) { // check every hex
+      if ((!(h[i].isCmd)) && (h[i].channel)) { // that is a held note
+        flagToAnimate(hexOffset(h[i].coords,hexVector((h[i].animFrame() % 6),1))); // different neighbor each frame
       };
     };
   }
@@ -1268,8 +1167,7 @@ highlight if diff is zero
           byte steps = ((animationType == SplashAnim) ? radius : 1);
  // star = 1 step to next corner; ring = 1 step per hex
           coordinates temp =
-hexOffset(h[i].coords,hexVector(DnLeft,radius));  // start at one
-corner of the ring
+hexOffset(h[i].coords,hexVector(DnLeft,radius));  // start at one corner of the ring
           for (byte dir = 0; dir < 6; dir++) {
  // walk along the ring in each of the 6 hex directions
             for (byte i = 0; i < steps; i++) {
@@ -1304,36 +1202,28 @@ corner of the ring
                                            { "Splash" , SplashAnim},
                                            { "Orbit"  , OrbitAnim} };
 
-  GEMSelect selectYesOrNo(sizeof(optionByteYesOrNo) /
-sizeof(SelectOptionByte), optionByteYesOrNo);
-  GEMSelect selectBuzzer( sizeof(optionByteBuzzer)  /
-sizeof(SelectOptionByte), optionByteBuzzer);
-  GEMSelect selectColor(  sizeof(optionByteColor)   /
-sizeof(SelectOptionByte), optionByteColor);
-  GEMSelect selectAnimate(sizeof(optionByteAnimate) /
-sizeof(SelectOptionByte), optionByteAnimate);
+  GEMSelect selectYesOrNo(sizeof(optionByteYesOrNo) / sizeof(SelectOptionByte), optionByteYesOrNo);
+  GEMSelect selectBuzzer( sizeof(optionByteBuzzer)  / sizeof(SelectOptionByte), optionByteBuzzer);
+  GEMSelect selectColor(  sizeof(optionByteColor)   / sizeof(SelectOptionByte), optionByteColor);
+  GEMSelect selectAnimate(sizeof(optionByteAnimate) / sizeof(SelectOptionByte), optionByteAnimate);
 
   GEMPage  menuPageMain("HexBoard MIDI Controller");
 
   GEMPage  menuPageTuning("Tuning");
   GEMItem  menuGotoTuning("Tuning", menuPageTuning);
-  GEMItem* menuItemTuning[tuningCount]; // dynamically generate item
-based on tunings
+  GEMItem* menuItemTuning[tuningCount]; // dynamically generate item based on tunings
 
   GEMPage  menuPageLayout("Layout");
   GEMItem  menuGotoLayout("Layout", menuPageLayout);
-  GEMItem* menuItemLayout[layoutCount]; // dynamically generate item
-based on presets
+  GEMItem* menuItemLayout[layoutCount]; // dynamically generate item based on presets
 
   GEMPage  menuPageScales("Scales");
   GEMItem  menuGotoScales("Scales", menuPageScales);
-  GEMItem* menuItemScales[scaleCount];  // dynamically generate item
-based on presets and if allowed in given EDO tuning
+  GEMItem* menuItemScales[scaleCount];  // dynamically generate item based on presets and if allowed in given EDO tuning
 
   GEMPage  menuPageKeys("Keys");
   GEMItem  menuGotoKeys("Keys",     menuPageKeys);
-  GEMItem* menuItemKeys[keyCount];   // dynamically generate item
-based on presets
+  GEMItem* menuItemKeys[keyCount];   // dynamically generate item based on presets
 
   GEMItem  menuItemScaleLock( "Scale lock?",   scaleLock,     selectYesOrNo);
   GEMItem  menuItemMPE(       "MPE Mode:",     MPE,
@@ -1349,30 +1239,25 @@ selectYesOrNo, resetHexLEDs);
     menu.setMenuPageCurrent(menuPageMain);
     menu.drawMenu();
   }
-  void showOnlyValidLayoutChoices() { // re-run at setup and whenever
-tuning changes
+  void showOnlyValidLayoutChoices() { // re-run at setup and whenever tuning changes
     for (byte L = 0; L < layoutCount; L++) {
       menuItemLayout[L]->hide((layoutOptions[L].tuning != current.tuningIndex));
     };
     sendToLog(String("menu: Layout choices were updated."));
   }
-  void showOnlyValidScaleChoices() { // re-run at setup and whenever
-tuning changes
+  void showOnlyValidScaleChoices() { // re-run at setup and whenever tuning changes
     for (int S = 0; S < scaleCount; S++) {
-      menuItemScales[S]->hide((scaleOptions[S].tuning !=
-current.tuningIndex) && (scaleOptions[S].tuning != 255));
+      menuItemScales[S]->hide((scaleOptions[S].tuning != current.tuningIndex) && (scaleOptions[S].tuning != 255));
     };
     sendToLog(String("menu: Scale choices were updated."));
   }
-  void showOnlyValidKeyChoices() { // re-run at setup and whenever
-tuning changes
+  void showOnlyValidKeyChoices() { // re-run at setup and whenever tuning changes
     for (int K = 0; K < keyCount; K++) {
       menuItemKeys[K]->hide((keyOptions[K].tuning != current.tuningIndex));
     };
     sendToLog(String("menu: Key choices were updated."));
   }
-  void changeLayout(GEMCallbackData callbackData) {  // when you
-change the layout via the menu
+  void changeLayout(GEMCallbackData callbackData) {  // when you change the layout via the menu
     byte selection = callbackData.valByte;
     if (selection != current.layoutIndex) {
       current.layoutIndex = selection;
@@ -1380,8 +1265,7 @@ change the layout via the menu
     };
     menuHome();
   }
-  void changeScale(GEMCallbackData callbackData) {   // when you
-change the scale via the menu
+  void changeScale(GEMCallbackData callbackData) {   // when you change the scale via the menu
     int selection = callbackData.valInt;
     if (selection != current.scaleIndex) {
       current.scaleIndex = selection;
@@ -1389,8 +1273,7 @@ change the scale via the menu
     };
     menuHome();
   }
-  void changeKey(GEMCallbackData callbackData) {     // when you
-change the key via the menu
+  void changeKey(GEMCallbackData callbackData) {     // when you change the key via the menu
     int selection = callbackData.valInt;
     if (selection != current.keyIndex) {
       current.keyIndex = selection;
@@ -1415,8 +1298,7 @@ change the key via the menu
   }
   void buildMenu() {
     menuPageMain.addMenuItem(menuGotoTuning);
-    for (byte T = 0; T < tuningCount; T++) { // create pointers to all
-tuning choices
+    for (byte T = 0; T < tuningCount; T++) { // create pointers to all tuning choices
       menuItemTuning[T] = new GEMItem(tuningOptions[T].name, changeTuning, T);
       menuPageTuning.addMenuItem(*menuItemTuning[T]);
     };
@@ -1429,8 +1311,7 @@ tuning choices
     showOnlyValidLayoutChoices();
 
     menuPageMain.addMenuItem(menuGotoScales);
-    for (int S = 0; S < scaleCount; S++) {  // create pointers to all
-scale items, filter them as you go
+    for (int S = 0; S < scaleCount; S++) {  // create pointers to all scale items, filter them as you go
       menuItemScales[S] = new GEMItem(scaleOptions[S].name, changeScale, S);
       menuPageScales.addMenuItem(*menuItemScales[S]);
     };
@@ -1457,14 +1338,11 @@ scale items, filter them as you go
 // ====== setup routines
 
   void setupMIDI() {
-    usb_midi.setStringDescriptor("HexBoard MIDI");  // Initialize
-MIDI, and listen to all MIDI channels
-    MIDI.begin(MIDI_CHANNEL_OMNI);                  // This will also
-call usb_midi's begin()
+    usb_midi.setStringDescriptor("HexBoard MIDI");  // Initialize MIDI, and listen to all MIDI channels
+    MIDI.begin(MIDI_CHANNEL_OMNI);                  // This will also call usb_midi's begin()
   }
   void setupFileSystem() {
-    Serial.begin(115200);     // Set serial to make uploads work
-without bootsel button
+    Serial.begin(115200);     // Set serial to make uploads work without bootsel button
     LittleFSConfig cfg;       // Configure file system defaults
     cfg.setAutoFormat(true);  // Formats file system if it cannot be mounted.
     LittleFS.setConfig(cfg);
@@ -1476,13 +1354,11 @@ without bootsel button
   void setupPins() {
     for (byte p = 0; p < sizeof(columnPins); p++)  // For each column pin...
     {
-      pinMode(columnPins[p], INPUT_PULLUP);  // set the pinMode to
-INPUT_PULLUP (+3.3V / HIGH).
+      pinMode(columnPins[p], INPUT_PULLUP);  // set the pinMode to INPUT_PULLUP (+3.3V / HIGH).
     }
     for (byte p = 0; p < sizeof(multiplexPins); p++)  // For each column pin...
     {
-      pinMode(multiplexPins[p], OUTPUT);  // Setting the row
-multiplexer pins to output.
+      pinMode(multiplexPins[p], OUTPUT);  // Setting the row multiplexer pins to output.
     }
     Wire.setSDA(lightPinSDA);
     Wire.setSCL(lightPinSCL);
@@ -1526,12 +1402,9 @@ multiplexer pins to output.
 
   void timeTracker() {
     lapTime = runTime - loopTime;
-    // sendToLog(String(lapTime));  // Print out the time it takes to
-run each loop
-    loopTime = runTime;  // Update previousTime variable to give us a
-reference point for next loop
-    runTime = millis();   // Store the current time in a uniform
-variable for this program loop
+    // sendToLog(String(lapTime));  // Print out the time it takes to run each loop
+    loopTime = runTime;  // Update previousTime variable to give us a reference point for next loop
+    runTime = millis();   // Store the current time in a uniform variable for this program loop
   }
   void screenSaver() {
     if (screenTime <= screenSaverMillis) {
@@ -1548,24 +1421,17 @@ variable for this program loop
     }
   }
   void readHexes() {
-    for (byte r = 0; r < rowCount; r++) {  // Iterate through each of
-the row pins on the multiplexing chip.
+    for (byte r = 0; r < rowCount; r++) {  // Iterate through each of the row pins on the multiplexing chip.
       for (byte d = 0; d < 4; d++) {
         digitalWrite(multiplexPins[d], (r >> d) & 1);
       }
-      for (byte c = 0; c < colCount; c++) {   // Now iterate through
-each of the column pins that are connected to the current row pin.
-        byte p = columnPins[c];               // Hold the currently
-selected column pin in a variable.
-        pinMode(p, INPUT_PULLUP);             // Set that row pin to
-INPUT_PULLUP mode (+3.3V / HIGH).
-        delayMicroseconds(10);                // Delay to give the pin
-modes time to change state (false readings are caused otherwise).
-        bool didYouPressHex = (digitalRead(p) == LOW);  // hex is
-pressed if it returns LOW. else not pressed
+      for (byte c = 0; c < colCount; c++) {   // Now iterate through each of the column pins that are connected to the current row pin.
+        byte p = columnPins[c];               // Hold the currently selected column pin in a variable.
+        pinMode(p, INPUT_PULLUP);             // Set that row pin to INPUT_PULLUP mode (+3.3V / HIGH).
+        delayMicroseconds(10);                // Delay to give the pin modes time to change state (false readings are caused otherwise).
+        bool didYouPressHex = (digitalRead(p) == LOW);  // hex is pressed if it returns LOW. else not pressed
         h[c + (r * colCount)].updateKeyState(didYouPressHex);
-        pinMode(p, INPUT);  // Set the selected column pin back to
-INPUT mode (0V / LOW).
+        pinMode(p, INPUT);  // Set the selected column pin back to INPUT mode (0V / LOW).
        }
     }
   }
@@ -1606,8 +1472,7 @@ INPUT mode (0V / LOW).
   }
   void updateWheels() {
     velWheel.setTargetValue();
-    bool upd = velWheel.updateValue(); // this function returns a
-boolean, gotta put it somewhere even if it isn't being used
+    bool upd = velWheel.updateValue(); // this function returns a boolean, gotta put it somewhere even if it isn't being used
     if (upd) {
       sendToLog(String("vel became " + String(velWheel.curValue)));
     }
@@ -1754,8 +1619,7 @@ without built-in support for TinyUSB such as mbed rp2040
     setupMIDI();
     setupFileSystem();
     setupPins();
-    testDiagnostics();  // Print diagnostic troubleshooting
-information to serial monitor
+    testDiagnostics();  // Print diagnostic troubleshooting information to serial monitor
     setupGrid();
     setupLEDs();
     setupGFX();
@@ -1770,8 +1634,7 @@ information to serial monitor
   void loop() {   // run on first core
     timeTracker();  // Time tracking functions
     screenSaver();  // Reduces wear-and-tear on OLED panel
-    readHexes();       // Read and store the digital button states of
-the scanning matrix
+    readHexes();       // Read and store the digital button states of the scanning matrix
     actionHexes();       // actions on hexes
     arpeggiate();      // arpeggiate the buzzer
     updateWheels();   // deal with the pitch/mod wheel