// Solder closed jumper on bottom! #define LED_PIN 13 #define CPU_HZ 48000000 #define TIMER_PRESCALER_DIV 1024 void startTimer(int frequencyHz); void setTimerFrequency(int frequencyHz); void TC3_Handler(); bool isLEDOn = false; bool playFlag = false; bool gestFlag = false; bool noteFlag = false; uint16_t noteNum = 64; uint16_t vNum = 0; uint16_t noteCnt = 8; uint16_t noteLength = 50; uint16_t duration = 50; uint16_t volume = 127; uint16_t ledcount = 0; #include #define PIXEL_PIN 19 // Digital IO pin connected to the NeoPixels. #define VBATPIN A7 #define PIXEL_COUNT 16. #include #include #include #include Adafruit_FeatherOLED oled = Adafruit_FeatherOLED(); // See http://www.vlsi.fi/fileadmin/datasheets/vs1053.pdf Pg 31 #define VS1053_BANK_DEFAULT 0x00 #define VS1053_BANK_DRUMS1 0x78 #define VS1053_BANK_DRUMS2 0x7F #define VS1053_BANK_MELODY 0x79 // See http://www.vlsi.fi/fileadmin/datasheets/vs1053.pdf Pg 32 for more! #define VS1053_GM1_OCARINA 80 #define MIDI_NOTE_ON 0x90 #define MIDI_NOTE_OFF 0x80 #define MIDI_CHAN_MSG 0xB0 #define MIDI_CHAN_BANK 0x00 #define MIDI_CHAN_VOLUME 0x07 #define MIDI_CHAN_PROGRAM 0xC0 #define VS1053_MIDI Serial1 byte voice[] = { 7,9,10,12,15,47,105,99,113,114,115,116,118,124 }; Adafruit_NeoPixel_ZeroDMA strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRBW); void setup() { delay(100); pinMode(LED_PIN, OUTPUT); oled.init(); oled.setBatteryVisible(true); strip.begin(); strip.setBrightness(24); strip.show(); // Initialize all pixels to 'off' // colorWipe(strip.Color(55, 99, 22), 5); // Black/off colorWipe(strip.Color(0, 0, 0), 5); // Black/off Serial.begin(115200); delay(100); // while (!Serial) { delay(1); } // wait until serial console is open, remove if not tethered to computer Serial.println("VS1053 MIDI test"); VS1053_MIDI.begin(31250); // MIDI uses a 'strange baud rate' // delay(200); midiSetChannelBank(0, VS1053_BANK_MELODY); midiSetChannelVolume(0, 127); // midiSetInstrument(0, VS1053_GM1_OCARINA); midiSetInstrument(0, 12); rainbowCycle(1); float measuredvbat = analogRead(VBATPIN); startTimer(100); } void loop() { // clear the current count oled.clearDisplay(); // get the current voltage of the battery from // one of the platform specific functions below float battery = getBatteryVoltage(); // update the battery icon oled.setBattery(battery); oled.renderBattery(); // update the display with the new count oled.display(); if (!playFlag) { noInterrupts(); // critical, time-sensitive code here playFlag = true; // set voice 0-14 //set Gesture 0-15 //set Volume 1-127 //set Tempo?? 1-10 // duration = 100; interrupts(); } // other code here rainbowCycle(1); } void midiSetInstrument(uint8_t chan, uint8_t inst) { if (chan > 15) return; inst --; // page 32 has instruments starting with 1 not 0 :( if (inst > 127) return; VS1053_MIDI.write(MIDI_CHAN_PROGRAM | chan); delay(10); VS1053_MIDI.write(inst); delay(10); } void midiSetChannelVolume(uint8_t chan, uint8_t vol) { if (chan > 15) return; if (vol > 127) return; VS1053_MIDI.write(MIDI_CHAN_MSG | chan); VS1053_MIDI.write(MIDI_CHAN_VOLUME); VS1053_MIDI.write(vol); } void midiSetChannelBank(uint8_t chan, uint8_t bank) { if (chan > 15) return; if (bank > 127) return; VS1053_MIDI.write(MIDI_CHAN_MSG | chan); VS1053_MIDI.write((uint8_t)MIDI_CHAN_BANK); VS1053_MIDI.write(bank); } void midiNoteOn(uint8_t chan, uint8_t n, uint8_t vel) { if (chan > 15) return; if (n > 127) return; if (vel > 127) return; VS1053_MIDI.write(MIDI_NOTE_ON | chan); VS1053_MIDI.write(n); VS1053_MIDI.write(vel); } void midiNoteOff(uint8_t chan, uint8_t n, uint8_t vel) { if (chan > 15) return; if (n > 127) return; if (vel > 127) return; VS1053_MIDI.write(MIDI_NOTE_OFF | chan); VS1053_MIDI.write(n); VS1053_MIDI.write(vel); } // Fill the dots one after the other with a color void colorWipe(uint32_t c, uint8_t wait) { for (uint16_t i = 0; i < strip.numPixels(); i++) { strip.setPixelColor(i, c); strip.show(); delay(wait); } } void rainbow(uint8_t wait) { uint16_t i, j; for (j = 0; j < 256; j++) { for (i = 0; i < strip.numPixels(); i++) { strip.setPixelColor(i, Wheel((i + j) & 255)); } strip.show(); delay(wait); } } // Slightly different, this makes the rainbow equally distributed throughout void rainbowCycle(uint8_t wait) { uint16_t i, j; for (j = 0; j < 256 * 4; j++) { // n cycles of all colors on wheel for (i = 0; i < strip.numPixels(); i++) { strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); } strip.show(); delay(wait); } } // Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if (WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } if (WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } float getBatteryVoltage() { float measuredvbat = analogRead(VBATPIN); measuredvbat *= 2; // we divided by 2, so multiply back measuredvbat *= 3.3; // Multiply by 3.3V, our reference voltage measuredvbat /= 1024; // convert to voltage return measuredvbat; } void setTimerFrequency(int frequencyHz) { int compareValue = (CPU_HZ / (TIMER_PRESCALER_DIV * frequencyHz)) - 1; TcCount16* TC = (TcCount16*) TC3; // Make sure the count is in a proportional position to where it was // to prevent any jitter or disconnect when changing the compare value. TC->COUNT.reg = map(TC->COUNT.reg, 0, TC->CC[0].reg, 0, compareValue); TC->CC[0].reg = compareValue; Serial.println(TC->COUNT.reg); Serial.println(TC->CC[0].reg); while (TC->STATUS.bit.SYNCBUSY == 1); } void startTimer(int frequencyHz) { REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_TCC2_TC3) ; while ( GCLK->STATUS.bit.SYNCBUSY == 1 ); // wait for sync TcCount16* TC = (TcCount16*) TC3; TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync // Use the 16-bit timer TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16; while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync // Use match mode so that the timer counter resets when the count matches the compare register TC->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync // Set prescaler to 1024 TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024; while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync setTimerFrequency(frequencyHz); // Enable the compare interrupt TC->INTENSET.reg = 0; TC->INTENSET.bit.MC0 = 1; NVIC_EnableIRQ(TC3_IRQn); TC->CTRLA.reg |= TC_CTRLA_ENABLE; while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync } void TC3_Handler() { TcCount16* TC = (TcCount16*) TC3; // If this interrupt is due to the compare register matching the timer count // we toggle the LED. if (TC->INTFLAG.bit.MC0 == 1) { TC->INTFLAG.bit.MC0 = 1; // Write callback here!!! if(playFlag){ if(!gestFlag){ // start Gesture //set Voice //set pointer to noteList //set notecnt gestFlag = true; } if(!noteFlag){ //set volume //set noteNum //set duration duration = noteLength; //start note midiNoteOn(0, noteNum, volume); noteFlag = true; } duration -= 1; if(duration==0){ noteCnt -= 1; if(noteCnt==0){ //clear all flags playFlag = false; gestFlag = false; digitalWrite(LED_PIN, isLEDOn); isLEDOn = !isLEDOn; }else { noteNum +=2; if(noteNum > 77) noteNum = 64; } noteFlag = false; } } } }