2021-08-17 19:29:10 +00:00
|
|
|
#include <Audio.h>
|
|
|
|
#include <play_fs_wav.h>
|
|
|
|
#include <Adafruit_NeoTrellisM4.h>
|
2021-08-15 13:10:17 +00:00
|
|
|
|
|
|
|
#include <Wire.h>
|
|
|
|
#include <Adafruit_Sensor.h>
|
|
|
|
#include <Adafruit_ADXL343.h>
|
|
|
|
|
2021-08-17 19:29:10 +00:00
|
|
|
#include <Adafruit_SPIFlash.h>
|
|
|
|
// #include <Adafruit_TinyUSB.h> conflicts with Adafruit_NeoTrellisM4.h due to MIDI USB
|
2021-08-15 13:10:17 +00:00
|
|
|
|
|
|
|
#define BPM 160
|
|
|
|
|
|
|
|
// GUItool: begin automatically generated code
|
2021-08-17 19:29:10 +00:00
|
|
|
AudioPlayFSWav playMem1; //xy=275,499
|
|
|
|
AudioPlayFSWav playMem2; //xy=284,532.5
|
|
|
|
AudioPlayFSWav playMem3; //xy=294,566.5
|
|
|
|
AudioPlayFSWav playMem4; //xy=302,599.5
|
2021-08-15 13:10:17 +00:00
|
|
|
AudioMixer4 mixer1; //xy=491,517
|
|
|
|
AudioSynthWaveformDc dc1; //xy=507,581
|
|
|
|
AudioFilterStateVariable filter1; //xy=649,502
|
|
|
|
AudioOutputAnalogStereo dacs1; //xy=830,510
|
|
|
|
AudioConnection patchCord1(playMem1, 0, mixer1, 0);
|
|
|
|
AudioConnection patchCord2(playMem2, 0, mixer1, 1);
|
|
|
|
AudioConnection patchCord3(playMem3, 0, mixer1, 2);
|
|
|
|
AudioConnection patchCord4(playMem4, 0, mixer1, 3);
|
|
|
|
AudioConnection patchCord5(mixer1, 0, filter1, 0);
|
|
|
|
AudioConnection patchCord6(dc1, 0, dacs1, 1);
|
|
|
|
AudioConnection patchCord7(filter1, 0, dacs1, 0);
|
|
|
|
// GUItool: end automatically generated code
|
|
|
|
|
2021-08-17 19:29:10 +00:00
|
|
|
//Flash memory stuff
|
|
|
|
Adafruit_FlashTransport_QSPI flashTransport(PIN_QSPI_SCK, PIN_QSPI_CS, PIN_QSPI_IO0, PIN_QSPI_IO1, PIN_QSPI_IO2, PIN_QSPI_IO3);
|
|
|
|
Adafruit_SPIFlash flash(&flashTransport);
|
|
|
|
FatFileSystem fatfs;
|
|
|
|
/*FatFile root; //related to USB Mass Storage
|
|
|
|
FatFile file;
|
|
|
|
Adafruit_USBD_MSC usb_msc;*/
|
2021-08-15 13:10:17 +00:00
|
|
|
|
|
|
|
Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4();
|
|
|
|
Adafruit_ADXL343 accel = Adafruit_ADXL343(50, &Wire1); //50 does not mean anything here, just a random id
|
|
|
|
|
|
|
|
int colors[] = {
|
|
|
|
0x180000,
|
|
|
|
0x100800,
|
|
|
|
0x180000,
|
|
|
|
0x100800
|
|
|
|
};
|
|
|
|
|
2021-08-17 19:29:10 +00:00
|
|
|
int timeToClick;
|
|
|
|
|
2021-08-15 13:10:17 +00:00
|
|
|
int G1[] = {0,1,8,9,16,17,24,25};
|
|
|
|
int G2[] = {2,3,10,11,18,19,26,27};
|
|
|
|
int G3[] = {4,5,12,13,20,21,28,29};
|
|
|
|
int G4[] = {6,7,14,15,22,23,30,31};
|
|
|
|
|
|
|
|
int G1Select = 7;
|
|
|
|
int G1Trigger = 0;
|
|
|
|
|
|
|
|
int G2Select = 7;
|
|
|
|
int G2Trigger = 0;
|
|
|
|
|
|
|
|
int G3Select = 7;
|
|
|
|
int G3Trigger = 0;
|
|
|
|
|
|
|
|
int G4Select = 7;
|
|
|
|
int G4Trigger = 0;
|
|
|
|
|
|
|
|
int EighthNote = 60000 / (BPM * 2);
|
|
|
|
|
|
|
|
int clickOn;
|
|
|
|
|
2021-08-17 19:29:10 +00:00
|
|
|
//bool USBFlash = false;
|
|
|
|
File sample1;
|
|
|
|
File sample2;
|
|
|
|
File sample3;
|
|
|
|
File sample4;
|
|
|
|
|
|
|
|
void setup() {
|
|
|
|
Serial.begin(115200);
|
|
|
|
|
|
|
|
trellis.begin();
|
|
|
|
trellis.setBrightness(127);
|
|
|
|
accel.begin();
|
|
|
|
|
|
|
|
AudioMemory(32);
|
|
|
|
|
|
|
|
redrawAndPlay();
|
|
|
|
|
|
|
|
filter1.resonance(2.2); //from 0.7 to 5
|
|
|
|
|
|
|
|
|
|
|
|
flash.begin();
|
|
|
|
/*if (USBFlash) { //related to USB Mass Storage
|
|
|
|
usb_msc.setID("Adafruit", "External Flash", "1.0");
|
|
|
|
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
|
|
|
|
usb_msc.setCapacity(flash.size()/512, 512);
|
|
|
|
usb_msc.setUnitReady(true);
|
|
|
|
usb_msc.begin();
|
|
|
|
}*/
|
|
|
|
fatfs.begin(&flash);
|
|
|
|
};
|
|
|
|
|
2021-08-15 13:10:17 +00:00
|
|
|
void clockTick(){
|
|
|
|
if(millis() >= timeToClick) {
|
|
|
|
timeToClick = millis() + EighthNote; //214 should be ~1/8 at 140 bpm
|
|
|
|
//Serial.println(timeToClick);
|
|
|
|
dc1.amplitude(1); //turn Korg click on
|
|
|
|
clickOn = millis();
|
|
|
|
updatePlay();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void clickOff() {
|
|
|
|
if (millis()-clickOn>15) {
|
|
|
|
dc1.amplitude(0); //turn Korg click off
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void updatePlay() {
|
2021-08-17 19:29:10 +00:00
|
|
|
|
|
|
|
|
2021-08-15 13:10:17 +00:00
|
|
|
//if there's less than 30ms until the end of the sample, retriger it to prevent gap
|
|
|
|
if (playMem1.lengthMillis() - playMem1.positionMillis() < 30) {
|
|
|
|
G1Trigger = 1;
|
|
|
|
}
|
|
|
|
if (G1Select < 7 && G1Trigger == 1) {
|
|
|
|
G1Trigger = 0;
|
|
|
|
switch (G1Select) {
|
|
|
|
case 6:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample1 = fatfs.open("G1_1.wav");
|
|
|
|
playMem1.play(sample1);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample1 = fatfs.open("G1_2.wav");
|
|
|
|
playMem1.play(sample1);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample1 = fatfs.open("G1_3.wav");
|
|
|
|
playMem1.play(sample1);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 0:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample1 = fatfs.open("G1_4.wav");
|
|
|
|
playMem1.play(sample1);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample1 = fatfs.open("G1_5.wav");
|
|
|
|
playMem1.play(sample1);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample1 = fatfs.open("G1_6.wav");
|
|
|
|
playMem1.play(sample1);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample1 = fatfs.open("G1_7.wav");
|
|
|
|
playMem1.play(sample1);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (playMem2.lengthMillis() - playMem2.positionMillis() < 30) {
|
|
|
|
G2Trigger = 1;
|
|
|
|
}
|
|
|
|
if (G2Select < 7 && G2Trigger == 1) {
|
|
|
|
G2Trigger = 0;
|
|
|
|
switch (G2Select) {
|
|
|
|
case 6:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample2 = fatfs.open("G2_1.wav");
|
|
|
|
playMem2.play(sample2);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample2 = fatfs.open("G2_2.wav");
|
|
|
|
playMem2.play(sample2);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample2 = fatfs.open("G2_3.wav");
|
|
|
|
playMem2.play(sample2);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 0:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample2 = fatfs.open("G2_4.wav");
|
|
|
|
playMem2.play(sample2);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample2 = fatfs.open("G2_5.wav");
|
|
|
|
playMem2.play(sample2);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample2 = fatfs.open("G2_6.wav");
|
|
|
|
playMem2.play(sample2);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample2 = fatfs.open("G2_7.wav");
|
|
|
|
playMem2.play(sample2);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (playMem3.lengthMillis() - playMem3.positionMillis() < 30) {
|
|
|
|
G3Trigger = 1;
|
|
|
|
}
|
|
|
|
if (G3Select < 7 && G3Trigger == 1) {
|
|
|
|
G3Trigger = 0;
|
|
|
|
switch (G3Select) {
|
|
|
|
case 6:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample3= fatfs.open("G3_1.wav");
|
|
|
|
playMem3.play(sample3);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample3= fatfs.open("G3_2.wav");
|
|
|
|
playMem3.play(sample3);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample3= fatfs.open("G3_3.wav");
|
|
|
|
playMem3.play(sample3);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 0:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample3= fatfs.open("G3_4.wav");
|
|
|
|
playMem3.play(sample3);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample3= fatfs.open("G3_5.wav");
|
|
|
|
playMem3.play(sample3);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample3= fatfs.open("G3_6.wav");
|
|
|
|
playMem3.play(sample3);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample3= fatfs.open("G3_7.wav");
|
|
|
|
playMem3.play(sample3);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (playMem4.lengthMillis() - playMem4.positionMillis() < 30) {
|
|
|
|
G4Trigger = 1;
|
|
|
|
}
|
|
|
|
if (G4Select < 7 && G4Trigger == 1) {
|
|
|
|
G4Trigger = 0;
|
|
|
|
switch (G4Select) {
|
|
|
|
case 6:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample4= fatfs.open("G4_1.wav");
|
|
|
|
playMem4.play(sample4);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample4= fatfs.open("G4_2.wav");
|
|
|
|
playMem4.play(sample4);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample4= fatfs.open("G4_3.wav");
|
|
|
|
playMem4.play(sample4);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 0:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample4= fatfs.open("G4_4.wav");
|
|
|
|
playMem4.play(sample4);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample4= fatfs.open("G4_5.wav");
|
|
|
|
playMem4.play(sample4);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample4= fatfs.open("G4_6.wav");
|
|
|
|
playMem4.play(sample4);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
2021-08-17 19:29:10 +00:00
|
|
|
sample4= fatfs.open("G4_7.wav");
|
|
|
|
playMem4.play(sample4);
|
2021-08-15 13:10:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void redrawAndPlay() {
|
|
|
|
for (int r=0; r<4; r++) {
|
|
|
|
for (int c=0; c<4; c++) {
|
|
|
|
for (int g=0; g<2; g++) {
|
|
|
|
if (r==3 && g==1) {
|
|
|
|
trellis.setPixelColor(c*2 + g + r*8, 0x000000);
|
|
|
|
} else {
|
|
|
|
trellis.setPixelColor(c*2 + g + r*8, colors[c]);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
if (G1Select != 7) {
|
|
|
|
trellis.setPixelColor(G1[G1Select], 0x333333);
|
|
|
|
} else {
|
|
|
|
playMem1.stop();
|
|
|
|
trellis.setPixelColor(G1[G1Select], 0x000000);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (G2Select != 7) {
|
|
|
|
trellis.setPixelColor(G2[G2Select], 0x333333);
|
|
|
|
} else {
|
|
|
|
playMem2.stop();
|
|
|
|
trellis.setPixelColor(G2[G2Select], 0x000000);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (G3Select != 7) {
|
|
|
|
trellis.setPixelColor(G3[G3Select], 0x333333);
|
|
|
|
} else {
|
|
|
|
playMem3.stop();
|
|
|
|
trellis.setPixelColor(G3[G3Select], 0x000000);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (G4Select != 7) {
|
|
|
|
trellis.setPixelColor(G4[G4Select], 0x333333);
|
|
|
|
} else {
|
|
|
|
playMem4.stop();
|
|
|
|
trellis.setPixelColor(G4[G4Select], 0x000000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-17 19:29:10 +00:00
|
|
|
/*Flash related functions
|
|
|
|
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
|
|
|
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
|
|
|
}
|
|
|
|
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
|
|
|
digitalWrite(LED_BUILTIN, HIGH);
|
|
|
|
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
|
|
|
|
}
|
|
|
|
void msc_flush_cb (void) {
|
|
|
|
flash.syncBlocks();
|
|
|
|
fatfs.cacheClear();
|
|
|
|
}*/
|
2021-08-15 13:10:17 +00:00
|
|
|
|
|
|
|
void loop() {
|
|
|
|
trellis.tick();
|
|
|
|
|
|
|
|
clockTick();
|
|
|
|
clickOff();
|
|
|
|
|
|
|
|
while (trellis.available()){
|
|
|
|
keypadEvent e = trellis.read();
|
|
|
|
|
|
|
|
if (e.bit.EVENT == KEY_JUST_PRESSED) {
|
|
|
|
int key = e.bit.KEY;
|
|
|
|
for (int i=0; i<8; i++) {
|
|
|
|
if (key == G1[i]) {
|
|
|
|
G1Select = i;
|
|
|
|
G1Trigger = 1;
|
|
|
|
redrawAndPlay();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (key == G2[i]) {
|
|
|
|
G2Select = i;
|
|
|
|
G2Trigger = 1;
|
|
|
|
redrawAndPlay();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (key == G3[i]) {
|
|
|
|
G3Select = i;
|
|
|
|
G3Trigger = 1;
|
|
|
|
redrawAndPlay();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (key == G4[i]) {
|
|
|
|
G4Select = i;
|
|
|
|
G4Trigger = 1;
|
|
|
|
redrawAndPlay();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Accelerometer and filter
|
|
|
|
sensors_event_t event;
|
|
|
|
accel.getEvent(&event);
|
|
|
|
|
|
|
|
if (event.acceleration.y < 0) {
|
|
|
|
filter1.frequency(1000 * (event.acceleration.y+10));
|
|
|
|
} else {
|
|
|
|
filter1.frequency(10000);
|
|
|
|
}
|
|
|
|
}
|