skizziks_53

Reddit Harpsichord Reworked v1.0

Sep 15th, 2019
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 22.30 KB | None | 0 0
  1. /*
  2.   September 15, 2019
  3.   Reddit harpis-gourd, corrected. Version 1.0
  4.  
  5.   This original sketch + header files had defines that conflicted with default Arduino IDE files.
  6.   This version is changed to get rid of those conflicts.
  7.   The header file harpsi-gourd.h is no longer needed.
  8.  
  9.   Also why does this guy call this a "harpsi-gourd"? The instrument is called a harpsichord. Unless maybe somebody originally made one with gourds as the keys I guess???
  10.  
  11. */
  12.  
  13.  
  14. /*******************************************************************************
  15.  
  16.   Lansing Makers Network
  17.   ------------------------------
  18.  
  19.   harpsi-gourd.ino - Touch Gourd Piano
  20.   Author: Michael P. Flaga
  21.  
  22.   Arduino based capacitive touch sensitive midi note player. aka piano or etc... using the MPR121 and VS1053
  23.  
  24.  
  25.   This work is licensed under a Creative Commons Attribution-ShareAlike 3.0
  26.   Unported License (CC BY-SA 3.0) http://creativecommons.org/licenses/by-sa/3.0/
  27.  
  28.   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  29.   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  30.   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  31.   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  32.   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  33.   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  34.   THE SOFTWARE.
  35.  
  36. *******************************************************************************/
  37.  
  38. // Setup of Touch Sensor
  39. #include <MPR121.h> // https://github.com/BareConductive/mpr121
  40. #include <Wire.h>
  41. #define LENGTH_OF_ARRAY(x) ((sizeof(x)/sizeof(x[0])))
  42. #define numElectrodes 12
  43. #define IDLE_TIMEOUT 30000
  44. #define IDLE_RANDOM_LOW_LIMIT 20000
  45. #define IDLE_RANDOM_HIGH_LIMIT 120000
  46. #define INSTRUMENT_CHANGE_TIMEOUT 4000
  47.  
  48. #include <SPI.h>
  49.  
  50. typedef struct // defining each Chip and its associated Touch pins, Note to play, and NeoPixel position
  51. {
  52.   // MPR121_t device; ------------------------------------------------- MPR121_t does not name a type
  53.   MPR121_type device;
  54.   uint8_t address;
  55.   unsigned char tthresh[12];
  56.   unsigned char rthresh[12];
  57.   uint32_t timeout[12];
  58.   bool noteState[12];
  59.   uint8_t key[12];
  60.   uint8_t ledPos[12];
  61. } mprs;
  62.  
  63. // reserve space for each chip that could be used.
  64. // MPR121_t MPR121A; ------------------------------------------------- MPR121_t does not name a type
  65. // MPR121_t MPR121B; ------------------------------------------------- MPR121_t does not name a type
  66.  
  67. MPR121_type MPR121A; // ------------------------------------------------- error fixed
  68. MPR121_type MPR121B; // ------------------------------------------------- error fixed
  69.  
  70. uint32_t lastAnyTouchedTimeOut;
  71. uint32_t lastAnyTouchedTimeOutInstrument;
  72. bool idle;
  73. bool idleInstrument;
  74.  
  75. // #include "harpsi-gourd.h" // Custom ordering of Key Board, LED and Notes ,,,,, ?????????
  76. // The file above includes another file (PitchToNote.h) that tries to re-define a basic Arduino default install file, and so this isn't going to work.
  77. // For me, that file is C:\Users\[user-account-name}\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.23\cores\arduino\binary.h
  78.  
  79. // I have no clue how the Indestructibles guy got his to ever work???
  80. // But anyway--we arent using his header files anymore. We will just change the necessary defines, and put them here.
  81.  
  82. // harpsi-gourd.h includes another file named PitchTonote.h that it refers to, so we need to put that here first.
  83. // Each note name now has the text "note" in front of it, so that it does not conflict with the other file.
  84. #define noteC8  108
  85.  
  86. #define noteB7  107
  87. #define noteB7b 106
  88. #define noteA7  105
  89. #define noteA7b 104
  90. #define noteG7  103
  91. #define noteG7b 102
  92. #define noteF7  101
  93. #define noteE7  100
  94. #define noteE7b 99
  95. #define noteD7  98
  96. #define noteD7b 97
  97. #define noteC7  96
  98.  
  99. #define noteB6  95
  100. #define noteB6b 94
  101. #define noteA6  93
  102. #define noteA6b 92
  103. #define noteG6  91
  104. #define noteG6b 90
  105. #define noteF6  89
  106. #define noteE6  88
  107. #define noteE6b 87
  108. #define noteD6  86
  109. #define noteD6b 85
  110. #define noteC6  84
  111.  
  112. #define noteB5  83
  113. #define noteB5b 82
  114. #define noteA5  81
  115. #define noteA5b 80
  116. #define noteG5  79
  117. #define noteG5b 78
  118. #define noteF5  77
  119. #define noteE5  76
  120. #define noteE5b 75
  121. #define noteD5  74
  122. #define noteD5b 73
  123. #define noteC5  72
  124.  
  125. #define noteB4  71
  126. #define noteB4b 70
  127. #define noteA4  69
  128. #define noteA4b 68
  129. #define noteG4  67
  130. #define noteG4b 66
  131. #define noteF4  65
  132. #define noteE4  64
  133. #define noteE4b 63
  134. #define noteD4  62
  135. #define noteD4b 61
  136. #define noteC4  60
  137.  
  138. #define noteB3  59
  139. #define noteB3b 58
  140. #define noteA3  57
  141. #define noteA3b 56
  142. #define noteG3  55
  143. #define noteG3b 54
  144. #define noteF3  53
  145. #define noteE3  52
  146. #define noteE3b 51
  147. #define noteD3  50
  148. #define noteD3b 49
  149. #define noteC3  48
  150.  
  151. #define noteB2  47
  152. #define noteB2b 46
  153. #define noteA2  45
  154. #define noteA2b 44
  155. #define noteG2  43
  156. #define noteG2b 42
  157. #define noteF2  41
  158. #define noteE2  40
  159. #define noteE2b 39
  160. #define noteD2  38
  161. #define noteD2b 37
  162. #define noteC2  36
  163.  
  164. #define noteB1  35
  165. #define noteB1b 34
  166. #define noteA1  33
  167. #define noteA1b 32
  168. #define noteG1  31
  169. #define noteG1b 30
  170. #define noteF1  29
  171. #define noteE1  28
  172. #define noteE1b 27
  173. #define noteD1  26
  174. #define noteD1b 25
  175. #define noteC1  24
  176.  
  177. #define noteB0  23
  178. #define noteB0b 22
  179. #define noteA0  21
  180.  
  181. // The header file included is named harpsi-gourd.h. In it is a couple structs, that refer to the erroneous defines.
  182. // So I coped that header file content here, and changed the references to the 'note' define terms.
  183. /*
  184.   Piano keys Left to Right
  185.   F3, G3b,  G3, A3b,  A3, B3b,  B3,  C4, D4b,  D4, E4b,  E4,  F4, G4b,  G4, A4b,  A4, B4b,  B4,  C5, D5b,  D5, E5b,  E5
  186.   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24
  187. */
  188.  
  189. mprs chips[] = {
  190.   (mprs) {
  191.     MPR121A, // pointer to above reserved memory structure
  192.     0x5A,    // ADDR tied to GND, individual address of MPR121 on I2C bus
  193.     {30,  30,  30,  30,  30,  30,  30,  30,  30,  30,  30,  30}, //tthresh
  194.     {10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10}, //rthresh
  195.     {00,  00,  00,  00,  00,  00,  00,  00,  00,  00,  00,  00}, //timeout
  196.     { 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0}, //noteState
  197.     {noteF3, noteG3b,  noteG3, noteA3b,  noteA3, noteB3b,  noteB3,  noteC4, noteD4b,  noteD4, noteE4b,  noteE4}, //key    ** Customize to fit your Build **
  198.     { 1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12}  //ledPos ** Customize to fit your Build **
  199.   },
  200.  
  201.   (mprs) {
  202.     MPR121B, // pointer to above reserved memory structure
  203.     0x5B,    // ADDR tied to 5V, individual address of MPR121 on I2C bus
  204.     {30,  30,  30,  30,  30,  30,  30,  30,  30,  30,  30,  30}, //tthresh
  205.     {10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10}, //rthresh
  206.     {00,  00,  00,  00,  00,  00,  00,  00,  00,  00,  00,  00}, //timeout
  207.     { 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0}, //noteState
  208.     {noteF4, noteG4b,  noteG4, noteA4b,  noteA4, noteB4b,  noteB4,  noteC5, noteD5b,  noteD5, noteE5b,  noteE5}, //key    ** Customize to fit your Build **
  209.     {13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24}  //ledPos ** Customize to fit your Build **
  210.   }
  211. };
  212.  
  213.  
  214.  
  215. // Setup of NeoPixel Array
  216. #include <Adafruit_NeoPixel.h>
  217. #ifdef __AVR__
  218. #include <avr/power.h>
  219. #endif
  220.  
  221. #define NEOPIXEL_PIN 5
  222. #define LED_TIMEOUT 1000
  223. Adafruit_NeoPixel strip = Adafruit_NeoPixel((LENGTH_OF_ARRAY(chips) * numElectrodes), NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
  224.  
  225. uint32_t rainbow[] = { // arbitrary number of colors
  226.   strip.Color(255, 128,   0),
  227.   strip.Color(255, 255,   0),
  228.   strip.Color(128, 255,   0),
  229.   strip.Color(  0, 255,   0),
  230.   strip.Color(  0, 255, 128),
  231.   strip.Color(  0, 255, 255),
  232.   strip.Color(  0, 128, 255),
  233.   strip.Color(  0,   0, 255),
  234.   strip.Color(128,   0, 255),
  235.   strip.Color(255,   0, 255),
  236.   strip.Color(255,   0, 128),
  237.   strip.Color(255,   0,   0)
  238. };
  239.  
  240. // Fill the dots one after the other with a color
  241. void colorWipe(uint32_t c, uint8_t wait) {
  242.   for (uint16_t i = 0; i < strip.numPixels(); i++) {
  243.     strip.setPixelColor(i, c);
  244.     strip.show();
  245.     delay(wait);
  246.   }
  247. }
  248.  
  249. // Setup of VS1053 Audio DSP
  250. #ifdef SFE
  251. #define VS_XCS    6 // Control Chip Select Pin (for accessing SPI Control/Status registers)
  252. #define VS_XDCS   7 // Data Chip Select / BSYNC Pin
  253. #define VS_DREQ   2 // Data Request Pin: Player asks for more data
  254. #define VS_RESET  8 //Reset is active low
  255. #define VS_IRQ    3
  256. #else // AdaFruit
  257. #define VS_XCS    7 // Control Chip Select Pin (for accessing SPI Control/Status registers)
  258. #define VS_XDCS   6 // Data Chip Select / BSYNC Pin
  259. #define VS_DREQ   3 // Data Request Pin: Player asks for more data
  260. #define VS_RESET  8 //Reset is active low
  261. #define VS_IRQ    2
  262. #endif
  263.  
  264. int instrument = 1; //47;
  265. uint8_t volume = 127;
  266. uint8_t idleVolume = volume / 3;
  267.  
  268. void VSWriteRegister(unsigned char addressbyte, unsigned char highbyte, unsigned char lowbyte) {
  269.   while (!digitalRead(VS_DREQ)) ; //Wait for DREQ to go high indicating IC is available
  270.   digitalWrite(VS_XCS, LOW); //Select control
  271.  
  272.   //SCI consists of instruction byte, address byte, and 16-bit data word.
  273.   SPI.transfer(0x02); //Write instruction
  274.   SPI.transfer(addressbyte);
  275.   SPI.transfer(highbyte);
  276.   SPI.transfer(lowbyte);
  277.   while (!digitalRead(VS_DREQ)) ; //Wait for DREQ to go high indicating command is complete
  278.   digitalWrite(VS_XCS, HIGH); //Deselect Control
  279. }
  280.  
  281. // Plugin to put VS10XX into realtime MIDI mode
  282. const unsigned short sVS1053b_Realtime_MIDI_Plugin[28] = { /* Compressed plugin */
  283.   0x0007, 0x0001, 0x8050, 0x0006, 0x0014, 0x0030, 0x0715, 0xb080, /*    0 */
  284.   0x3400, 0x0007, 0x9255, 0x3d00, 0x0024, 0x0030, 0x0295, 0x6890, /*    8 */
  285.   0x3400, 0x0030, 0x0495, 0x3d00, 0x0024, 0x2908, 0x4d40, 0x0030, /*   10 */
  286.   0x0200, 0x000a, 0x0001, 0x0050,
  287. };
  288.  
  289. void VSLoadUserCode(void) {
  290.   int i = 0;
  291.  
  292.   while (i < sizeof(sVS1053b_Realtime_MIDI_Plugin) / sizeof(sVS1053b_Realtime_MIDI_Plugin[0])) {
  293.     unsigned short addr, n, val;
  294.     addr = sVS1053b_Realtime_MIDI_Plugin[i++];
  295.     n = sVS1053b_Realtime_MIDI_Plugin[i++];
  296.     while (n--) {
  297.       val = sVS1053b_Realtime_MIDI_Plugin[i++];
  298.       VSWriteRegister(addr, val >> 8, val & 0xFF);
  299.     }
  300.   }
  301. }
  302.  
  303. void setup()
  304. {
  305.  
  306.   // configure interface pins to VS1053
  307.   pinMode(VS_DREQ, INPUT);
  308.   pinMode(VS_XCS, OUTPUT);
  309.   pinMode(VS_XDCS, OUTPUT);
  310.   digitalWrite(VS_XCS, HIGH); //Deselect Control
  311.   digitalWrite(VS_XDCS, HIGH); //Deselect Data
  312.   pinMode(VS_RESET, OUTPUT);
  313.  
  314.   Serial.begin(115200);
  315.   //while(!Serial);  // only needed if you want serial feedback with the
  316.   // Arduino Leonardo or Bare Touch Board
  317.   Serial.println(F("started Harpsi-Gourd"));
  318.  
  319.   // start the I2C bus to the MRP121s
  320.   Wire.begin();
  321.  
  322.   // initialize each available MPR121 and detect failures.
  323.   for (int deviceID = 0; deviceID < LENGTH_OF_ARRAY(chips); deviceID++) {
  324.     Serial.print(F("Initializing MPR #"));
  325.     Serial.print(deviceID);
  326.     Serial.println();
  327.  
  328.     if (!chips[deviceID].device.begin(chips[deviceID].address)) {
  329.       Serial.println(F("error setting up MPR121"));
  330.       switch (chips[deviceID].device.getError()) {
  331.         case NO_ERROR:
  332.           Serial.println(F("no error"));
  333.           break;
  334.         case ADDRESS_UNKNOWN:
  335.           Serial.println(F("incorrect address"));
  336.           break;
  337.         case READBACK_FAIL:
  338.           Serial.println(F("readback failure"));
  339.           break;
  340.         case OVERCURRENT_FLAG:
  341.           Serial.println(F("overcurrent on REXT pin"));
  342.           break;
  343.         case OUT_OF_RANGE:
  344.           Serial.println(F("electrode out of range"));
  345.           break;
  346.         case NOT_INITED:
  347.           Serial.println(F("not initialised"));
  348.           break;
  349.         default:
  350.           Serial.println(F("unknown error"));
  351.           break;
  352.       }
  353.       while (1);
  354.     }
  355.  
  356.     // Assign the common interrupt used by all MPR121s
  357.     chips[deviceID].device.setInterruptPin(VS_IRQ);
  358.  
  359.     // Assign the individual sensitivity of each touch pin
  360.     for (unsigned char channel = 0; channel < numElectrodes; channel++) {
  361.  
  362.       // this is the touch threshold - setting it low makes it more like a proximity trigger
  363.       // default value is 40 for touch
  364.       chips[deviceID].device.setTouchThreshold(channel, chips[deviceID].tthresh[channel]);
  365.  
  366.       // this is the release threshold - must ALWAYS be smaller than the touch threshold
  367.       // default value is 20 for touch
  368.       chips[deviceID].device.setReleaseThreshold(channel, chips[deviceID].rthresh[channel]);
  369.     }
  370.  
  371.     // initial data update
  372.     chips[deviceID].device.updateTouchData();
  373.   }
  374.  
  375.   //Initialize VS1053 chip
  376.   digitalWrite(VS_RESET, LOW); //Put VS1053 into hardware reset
  377.  
  378.   //Setup SPI for VS1053
  379.   pinMode(10, OUTPUT); //Pin 10 must be set as an output for the SPI communication to work
  380.   SPI.begin();
  381.   SPI.setBitOrder(MSBFIRST);
  382.   SPI.setDataMode(SPI_MODE0);
  383.   SPI.setClockDivider(SPI_CLOCK_DIV16); //Set SPI bus speed to 1MHz (16MHz / 16 = 1MHz)
  384.   SPI.transfer(0xFF); //Throw a dummy byte at the bus
  385.  
  386.   delayMicroseconds(1);
  387.   digitalWrite(VS_RESET, HIGH); //Bring up VS1053
  388.  
  389.   VSLoadUserCode();
  390.  
  391.   talkMIDI(0xB0, 0, 0);
  392.   Serial.print(F("Bank: "));
  393.   Serial.print(0, DEC);
  394.  
  395.   talkMIDI(0xB0, 0x07, volume); //0xB0 is channel message, set channel volume to near max (127)
  396.   Serial.print(F(", Set Volume: "));
  397.   Serial.print(volume, DEC);
  398.  
  399.  
  400.  
  401.   talkMIDI(0xC0, instrument, 0);
  402.   Serial.print(F(", Instrument: "));
  403.   Serial.println((instrument + 1), DEC);
  404.  
  405.   strip.begin();
  406.   strip.show(); // Initialize all pixels to 'off'
  407.  
  408.   colorWipe(strip.Color(255, 0, 0), 50); // Red
  409.   colorWipe(strip.Color(0, 255, 0), 50); // Green
  410.   colorWipe(strip.Color(0, 0, 255), 50); // Blue
  411.   colorWipe(strip.Color(0, 0, 0), 0); // OFF
  412.   randomSeed(analogRead(0));
  413.  
  414.   lastAnyTouchedTimeOut = millis() + (uint32_t) IDLE_TIMEOUT;
  415.   idle = 0;
  416.   lastAnyTouchedTimeOutInstrument = lastAnyTouchedTimeOut;
  417.   idleInstrument = 0;
  418.  
  419.   noteOff(0, 0, 127); // first one is ignored
  420.  
  421.   // play an initial note
  422.   noteOn(0, noteB7, 127);
  423.   delay(500);
  424.   noteOff(0, noteB7, 127);
  425.  
  426.  
  427.   Serial.println(F("end setup"));
  428. } // setup()
  429.  
  430. void sendMIDI(byte data)
  431. {
  432.   SPI.transfer(0);
  433.   SPI.transfer(data);
  434. }
  435.  
  436. //Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127
  437. void talkMIDI(byte cmd, byte data1, byte data2) {
  438.   while (!digitalRead(VS_DREQ))
  439.     ;
  440.   digitalWrite(VS_XDCS, LOW);
  441.   sendMIDI(cmd);
  442.   //Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
  443.   //(sort of: http://253.ccarh.org/handout/midiprotocol/)
  444.   if ( (cmd & 0xF0) <= 0xB0 || (cmd & 0xF0) >= 0xE0) {
  445.     sendMIDI(data1);
  446.     sendMIDI(data2);
  447.   } else {
  448.     sendMIDI(data1);
  449.   }
  450.  
  451.   digitalWrite(VS_XDCS, HIGH);
  452. } // talkMIDI()
  453.  
  454. //Send a MIDI note-on message.  Like pressing a piano key
  455. //channel ranges from 0-15
  456. void noteOn(byte channel, byte note, byte attack_velocity) {
  457.   talkMIDI( (0x90 | channel), note, attack_velocity);
  458. } // noteOn()
  459.  
  460. //Send a MIDI note-off message.  Like releasing a piano key
  461. void noteOff(byte channel, byte note, byte release_velocity) {
  462.   talkMIDI( (0x80 | channel), note, release_velocity);
  463. } // noteOff()
  464.  
  465. void loop()
  466. {
  467.   uint32_t currentMillis = millis();
  468.  
  469.   // Capacitive Touch Sensor Keyboard emulator
  470.   for (int deviceID = 0; deviceID < LENGTH_OF_ARRAY(chips); deviceID++) {
  471.     if (chips[deviceID].device.touchStatusChanged()) {
  472.       chips[deviceID].device.updateTouchData();
  473.       for (uint8_t channel = 0; channel < numElectrodes; channel++) {
  474.         if (chips[deviceID].device.isNewTouch(channel)) {
  475.           Serial.print(F("device=")); Serial.print(deviceID, DEC);
  476.           Serial.print(F(", electrode=")); Serial.print(channel, DEC);
  477.           Serial.print(F(", key=")); Serial.print(chips[deviceID].key[channel], DEC);
  478.           Serial.print(F(", led=")); Serial.print(chips[deviceID].ledPos[channel], DEC);
  479.           Serial.print(F(", rgb=0x")); Serial.print(rainbow[(chips[deviceID].ledPos[channel] - 1)], HEX);
  480.           Serial.println(F(" was just touched by me!"));
  481.           noteOn(0, chips[deviceID].key[channel], 127);
  482.           strip.setPixelColor((chips[deviceID].ledPos[channel] - 1), rainbow[(chips[deviceID].ledPos[channel] - 1)]);
  483.           strip.show();
  484.           chips[deviceID].timeout[channel] = currentMillis + LED_TIMEOUT;
  485.           chips[deviceID].noteState[channel] = 0; // ignore this during idle leave clean up. - cheat
  486.         }
  487.         else if (chips[deviceID].device.isNewRelease(channel)) {
  488.           Serial.print(F("device=")); Serial.print(deviceID, DEC);
  489.           Serial.print(F(", electrode=")); Serial.print(channel, DEC);
  490.           Serial.print(F(", key=")); Serial.print(chips[deviceID].key[channel], DEC);
  491.           Serial.print(F(", led=")); Serial.print(chips[deviceID].ledPos[channel], DEC);
  492.           Serial.println(F(" was just released."));
  493.           noteOff(0, chips[deviceID].key[channel], 127);
  494.           strip.setPixelColor((chips[deviceID].ledPos[channel] - 1), strip.Color(0, 0, 0));
  495.           strip.show();
  496.           chips[deviceID].timeout[channel] = 0x0000;
  497.           chips[deviceID].noteState[channel] = 0;
  498.         }
  499.       }
  500.  
  501.       lastAnyTouchedTimeOut = millis() + (uint32_t) IDLE_TIMEOUT;
  502.       lastAnyTouchedTimeOutInstrument = millis() + INSTRUMENT_CHANGE_TIMEOUT;
  503.       if (idle == 1) { // check if leaving idle
  504.         idle = 0;
  505.         colorWipe(strip.Color(0, 0, 0), 0); // OFF
  506.         Serial.println(F("Leaving Idle Mode."));
  507.  
  508.         // turn off any notes still on
  509.         for (int deviceID2 = 0; deviceID2 < LENGTH_OF_ARRAY(chips); deviceID2++) {
  510.           for (uint8_t channel = 0; channel < numElectrodes; channel++) {
  511.             if (chips[deviceID2].noteState[channel] == 1) {
  512.               noteOff(0, chips[deviceID2].key[channel], 127);
  513.               chips[deviceID2].noteState[channel] = 0;
  514.               Serial.print(F(", NoteOFF=")); Serial.print(chips[deviceID2].key[channel], DEC);
  515.             }
  516.           }
  517.         }
  518.         talkMIDI(0xB0, 0x07, volume); //0xB0 is channel message, set channel volume to near max (127)
  519.         Serial.print(F(", Set Volume: "));
  520.         Serial.println(volume, DEC);
  521.       }
  522.       idleInstrument = 0;
  523.     }
  524.  
  525.     // check if individual neoPixels need updating
  526.     for (uint8_t channel = 0; channel < numElectrodes; channel++) {
  527.       if (strip.getPixelColor((chips[deviceID].ledPos[channel] - 1))) { // if not OFF
  528.         if (chips[deviceID].timeout[channel] < currentMillis) { // check if it needs changing
  529.           Serial.print(F("led=")); Serial.print((chips[deviceID].ledPos[channel]), DEC);
  530.           uint32_t randomSeconds = random(IDLE_RANDOM_LOW_LIMIT, IDLE_RANDOM_HIGH_LIMIT);
  531.           Serial.print(F(", randomSeconds=")); Serial.print(randomSeconds, DEC);
  532.           uint8_t ran = random(0, LENGTH_OF_ARRAY(rainbow));
  533.           Serial.print(F(", ranRainbow=")); Serial.print(ran, DEC);
  534.           strip.setPixelColor((chips[deviceID].ledPos[channel] - 1), rainbow[ran]);
  535.           strip.show();
  536.           if (chips[deviceID].noteState[channel] == 0) {
  537.             noteOn(0, chips[deviceID].key[channel], 127);
  538.             chips[deviceID].noteState[channel] = 1;
  539.             Serial.print(F(", NoteON=")); Serial.print(chips[deviceID].key[channel], DEC);
  540.           }
  541.           else {
  542.             noteOff(0, chips[deviceID].key[channel], 127);
  543.             chips[deviceID].noteState[channel] = 0;
  544.             Serial.print(F(", NoteOFF=")); Serial.print(chips[deviceID].key[channel], DEC);
  545.           }
  546.           Serial.println(F(" idle change timeout."));
  547.           chips[deviceID].timeout[channel] = currentMillis + randomSeconds;
  548.         }
  549.       }
  550.     }
  551.   }
  552.  
  553.   if ((lastAnyTouchedTimeOut < currentMillis) && (idle == 0)) { // check if should be idle
  554.     idle = 1;
  555.     Serial.println(F("Gone to Idle Mode."));
  556.     talkMIDI(0xB0, 0x07, idleVolume); //0xB0 is channel message, set channel volume to near max (127)
  557.     Serial.print(F(", Set Volume: "));
  558.     Serial.println(idleVolume, DEC);
  559.   }
  560.  
  561.   if (lastAnyTouchedTimeOutInstrument < currentMillis) { // check if should be idle
  562.     lastAnyTouchedTimeOutInstrument = millis() + INSTRUMENT_CHANGE_TIMEOUT;
  563.     instrument = random(0, 127);
  564.     talkMIDI(0xC0, instrument, 0);
  565.     Serial.println(F("Instrument Idle Change"));
  566.     Serial.print(F(" Instrument: "));
  567.     Serial.println((instrument + 1), DEC);
  568.   }
  569.  
  570.   if (idle == 1) { // if in idle
  571.     // do something?
  572.  
  573.     for (int deviceID = 0; deviceID < LENGTH_OF_ARRAY(chips); deviceID++) {
  574.       for (uint8_t channel = 0; channel < numElectrodes; channel++) {
  575.         if (chips[deviceID].timeout[channel] < currentMillis) { // check if it needs changing
  576.           Serial.print(F("led=")); Serial.print((chips[deviceID].ledPos[channel]), DEC);
  577.           uint32_t randomSeconds = random(IDLE_RANDOM_LOW_LIMIT, IDLE_RANDOM_HIGH_LIMIT);
  578.           Serial.print(F(", randomSeconds=")); Serial.print(randomSeconds, DEC);
  579.           uint8_t ran = random(0, LENGTH_OF_ARRAY(rainbow));
  580.           Serial.print(F(", ranRainbow=")); Serial.print(ran, DEC);
  581.           strip.setPixelColor((chips[deviceID].ledPos[channel] - 1), rainbow[ran]);
  582.           strip.show();
  583.           Serial.println(F(" Idle just timed out."));
  584.           chips[deviceID].timeout[channel] = currentMillis + randomSeconds;
  585.         }
  586.       }
  587.     }
  588.  
  589.   }
  590.  
  591.   if (Serial.available()) {
  592.     parse_menu(Serial.read()); // get command from serial input
  593.   }
  594.  
  595. } // loop()
  596.  
  597. void parse_menu(byte key_command) {
  598.  
  599.   uint8_t result; // result code from some function as to be tested at later time.
  600.  
  601.   if ((0x20 <= key_command) && (key_command <= 0x7E)) { // ignore Non keyboard characters.
  602.     Serial.print(F("Received command: "));
  603.     Serial.write(key_command);
  604.     Serial.println(F(" "));
  605.  
  606.     if ((key_command == '-') || (key_command == '+')) {
  607.       if (key_command == '+') {
  608.         Serial.println(F("Increamenting"));
  609.         if (instrument < 127) {
  610.           instrument++;
  611.         }
  612.       } else if (key_command == '-') {
  613.         Serial.println(F("Decreamenting"));
  614.         if (instrument > 0) {
  615.           instrument--;
  616.         }
  617.       }
  618.       talkMIDI(0xC0, instrument, 0);
  619.       Serial.print(F(" Instrument: "));
  620.       Serial.println((instrument + 1), DEC);
  621.     } else {
  622.       Serial.println(F("Unknown Command!"));
  623.     }
  624.   }
  625. }
  626.  
  627.  
  628. // ~~~~~~~ the end ~~~~~~~~
Add Comment
Please, Sign In to add comment