Created
August 5, 2013 01:39
-
-
Save medicalwei/6152900 to your computer and use it in GitHub Desktop.
Arduino Esplora Sequencer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Esplora.h> | |
#include <TFT.h> | |
#include <SPI.h> | |
// these are the frequencies for the notes from middle C | |
// to one octave above middle C: | |
const int note[] = { | |
247, | |
262, // C | |
277, // C# | |
294, // D | |
311, // D# | |
330, // E | |
349, // F | |
370, // F# | |
392, // G | |
415, // G# | |
440, // A | |
466, // A# | |
494, // B | |
523, // C next octave | |
554 | |
}; | |
const int notes = 14; | |
char seqString[][7] = { | |
"Seq 1", | |
"Seq 2", | |
"Seq 3", | |
"Seq 4", | |
"Seq 5", | |
"Seq 6", | |
"Seq 7", | |
"Seq 8", | |
"Seq 9", | |
"Seq 10", | |
"Seq 11", | |
"Seq 12", | |
"Seq 13", | |
"Seq 14", | |
"Seq 15", | |
"Seq 16" | |
}; | |
char noteString[][6] = { | |
"pause", | |
"C", // C | |
"C#", // C# | |
"D", // D | |
"D#", // D# | |
"E", // E | |
"F", // F | |
"F#", // F# | |
"G", // G | |
"G#", // G# | |
"A", // A | |
"A#", // A# | |
"B", // B | |
"C+" // C next octave | |
}; | |
// time | |
unsigned long prevTime; | |
// sequencer properties | |
int seqPos = 15; | |
int seqMax = 16; | |
int seqArray[16] = {0}; | |
// BPM and delay time | |
int bpm; unsigned long delayTime; | |
int writtenBpm = 0; | |
char bpmPrintout[4]; | |
// Attack time | |
unsigned long attack = 100000; | |
// cursor | |
int curPos = 0; | |
// button statuses | |
int btnPrevStat[4] = {HIGH, HIGH, HIGH, HIGH}; | |
// button events | |
void btnDownClick(){ | |
setNote(curPos, -1); | |
printStatus(seqString[curPos], noteString[seqArray[curPos]]); | |
} | |
void btnUpClick(){ | |
setNote(curPos, 1); | |
printStatus(seqString[curPos], noteString[seqArray[curPos]]); | |
} | |
void btnLeftClick(){ | |
setCursor_(-1); | |
printStatus(seqString[curPos], noteString[seqArray[curPos]]); | |
} | |
void btnRightClick(){ | |
setCursor_(1); | |
printStatus(seqString[curPos], noteString[seqArray[curPos]]); | |
} | |
// handle buttons | |
void buttonHandlers(){ | |
int btnStat[4]; | |
btnStat[0] = Esplora.readButton(SWITCH_DOWN); | |
btnStat[1] = Esplora.readButton(SWITCH_LEFT); | |
btnStat[2] = Esplora.readButton(SWITCH_UP); | |
btnStat[3] = Esplora.readButton(SWITCH_RIGHT); | |
if (btnStat[0] != btnPrevStat[0] && btnStat[0] == LOW){ | |
btnDownClick(); | |
} | |
if (btnStat[1] != btnPrevStat[1] && btnStat[1] == LOW){ | |
btnLeftClick(); | |
} | |
if (btnStat[2] != btnPrevStat[2] && btnStat[2] == LOW){ | |
btnUpClick(); | |
} | |
if (btnStat[3] != btnPrevStat[3] && btnStat[3] == LOW){ | |
btnRightClick(); | |
} | |
btnPrevStat[0] = btnStat[0]; | |
btnPrevStat[1] = btnStat[1]; | |
btnPrevStat[2] = btnStat[2]; | |
btnPrevStat[3] = btnStat[3]; | |
} | |
void readSliderAndSetDelayTime(){ | |
bpm = map(Esplora.readSlider(), 0, 1023, 255, 0); | |
if (bpm != 0) { | |
delayTime = 60000000 / bpm / 4; | |
if (abs(bpm - writtenBpm) > 1) { | |
String(bpm).toCharArray(bpmPrintout, 4); | |
printStatus("BPM", bpmPrintout); | |
writtenBpm = bpm; | |
} | |
} else if (bpm != writtenBpm) { | |
printStatus("Music", "STOP"); | |
writtenBpm = bpm; | |
} | |
} | |
inline void drawNote(unsigned int target){ | |
int maxHeight = EsploraTFT.height() - 10; | |
if (seqArray[target]) { | |
EsploraTFT.rect(target*10, maxHeight - seqArray[target]*5, 10, 5); | |
} | |
} | |
void drawSequence(){ | |
for(int i=0; i<16; i++){ | |
setNote(i, 0); | |
} | |
} | |
void setNote(int target, int delta){ | |
EsploraTFT.fill(0, 0, 0); | |
drawNote(curPos); | |
seqArray[curPos] = (seqArray[target] + delta) % notes; | |
if (seqArray[target] < 0) { | |
seqArray[target] += notes; | |
} | |
EsploraTFT.fill(0, 255, 255); | |
drawNote(target); | |
} | |
inline void drawCursor(){ | |
int maxHeight = EsploraTFT.height(); | |
EsploraTFT.rect(curPos*10, maxHeight - 10, 10, 10); | |
} | |
void setCursor_(int delta){ | |
EsploraTFT.fill(0, 0, 0); | |
drawCursor(); | |
curPos = (curPos + delta) % 16; | |
if (curPos < 0) { | |
curPos += 16; | |
} | |
EsploraTFT.fill(255, 0, 255); | |
drawCursor(); | |
} | |
void sequenceChanged(){ | |
// Clean sequencer position | |
EsploraTFT.fill(0, 0, 0); | |
EsploraTFT.rect(seqPos*10, 0, 10, 10); | |
seqPos = seqPos + 1; | |
if (seqPos >= seqMax){ | |
seqPos = 0; | |
} | |
EsploraTFT.fill(255, 127, 0); | |
EsploraTFT.rect(seqPos*10, 0, 10, 10); | |
if (seqArray[seqPos]) { | |
int pitch = Esplora.readJoystickY(); | |
int diff; | |
if (pitch>0){ | |
diff = abs(note[seqArray[seqPos]-1] - note[seqArray[seqPos]]); | |
} else { | |
diff = abs(note[seqArray[seqPos]+1] - note[seqArray[seqPos]]); | |
} | |
pitch = map(pitch, -512, 512, diff, -diff); | |
Esplora.tone(note[seqArray[seqPos]]+pitch); | |
} else { | |
Esplora.noTone(); | |
} | |
} | |
void printStatus(char* string1, char* string2){ | |
EsploraTFT.fill(0, 0, 0); | |
EsploraTFT.stroke(0, 0, 0); | |
EsploraTFT.rect(0, 11, EsploraTFT.width(), 25); | |
EsploraTFT.stroke(255, 255, 255); | |
EsploraTFT.setTextSize(1); | |
EsploraTFT.text(string1, 0, 11); | |
EsploraTFT.setTextSize(2); | |
EsploraTFT.text(string2, 0, 20); | |
EsploraTFT.stroke(63, 63, 63); | |
} | |
void loop() { | |
readSliderAndSetDelayTime(); | |
buttonHandlers(); | |
unsigned long time = micros(); | |
if (time-prevTime > attack){ | |
Esplora.noTone(); | |
} | |
if (bpm != 0 && time-prevTime >= delayTime){ | |
sequenceChanged(); | |
prevTime = time; | |
} | |
} | |
void drawGrid(){ | |
EsploraTFT.stroke(63, 63, 63); | |
EsploraTFT.fill(0, 0, 0); | |
for(int i=0; i<16; i++){ | |
EsploraTFT.rect(i*10, 0, 10, 10); | |
EsploraTFT.rect(i*10, EsploraTFT.height() - 10, 10, 10); | |
for (int j=0; j < notes - 1; j++) { | |
EsploraTFT.rect(i*10, EsploraTFT.height() - 15 - j*5, 10, 5); | |
} | |
} | |
} | |
void setup() { | |
// Draw black screen | |
EsploraTFT.begin(); | |
EsploraTFT.background(0, 0, 0); | |
EsploraTFT.stroke(63, 63, 63); | |
// set time | |
prevTime = micros(); | |
// paint initialize things | |
drawGrid(); | |
drawSequence(); | |
// first trigger | |
setCursor_(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Copyright (c) 2013, Yao Wei
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.