// Includes
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <MIDI.h>
// Used for Sample Management
File root;
const int MAX_SAMPLES = 256;
unsigned short veloMap[ MAX_SAMPLES ];
unsigned short keyMap[ MAX_SAMPLES ];
int samplenum;
unsigned short veloCount;
unsigned short oldnoteval;
size_t count = 0;
const size_t MAX_CHARS = 64;
char newfile[ MAX_CHARS ];
unsigned short veloadd;
int drumset=1;
// Midi-Instance
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
// GUItool: begin automatically generated code
AudioPlaySdWav Kick; //xy=55,48
AudioPlaySdWav HiTom; //xy=55,209
AudioPlaySdWav MidTom; //xy=55,261
AudioPlaySdWav SD_Rim; //xy=56,162
AudioPlaySdWav LowTom; //xy=58,313
AudioPlaySdWav SD_Head; //xy=60.5,110
AudioPlaySdWav Crash_L; //xy=59,578
AudioPlaySdWav Ride_Bell; //xy=62,538
AudioPlaySdWav HiHat_Foot; //xy=66,457
AudioPlaySdWav HiHat_Open; //xy=69,364
AudioPlaySdWav Ride_Edge; //xy=69,499
AudioPlaySdWav HiHat_Closed; //xy=73.5,413
AudioPlaySdWav Crash_R; //xy=76,616
AudioMixer4 Mono_L1; //xy=324,39
AudioMixer4 Mono_L2; //xy=324,112
AudioMixer4 Mono_R2; //xy=323,395
AudioMixer4 Mono_L3; //xy=325,184
AudioMixer4 Mono_R3; //xy=324,465
AudioMixer4 Mono_L4; //xy=325,254
AudioMixer4 Mono_R1; //xy=325,326
AudioMixer4 Mono_R4; //xy=325,537
AudioMixer4 Stereo_L; //xy=509,184
AudioMixer4 Stereo_R; //xy=512,325
AudioOutputI2S i2s1; //xy=690,250
AudioConnection patchCord1(Kick, 0, Mono_L1, 0);
AudioConnection patchCord2(Kick, 1, Mono_R1, 0);
AudioConnection patchCord3(HiTom, 0, Mono_L1, 3);
AudioConnection patchCord4(HiTom, 1, Mono_R1, 3);
AudioConnection patchCord5(MidTom, 0, Mono_L2, 0);
AudioConnection patchCord6(MidTom, 1, Mono_R2, 0);
AudioConnection patchCord7(SD_Rim, 0, Mono_L1, 2);
AudioConnection patchCord8(SD_Rim, 1, Mono_R1, 2);
AudioConnection patchCord9(LowTom, 0, Mono_L2, 1);
AudioConnection patchCord10(LowTom, 1, Mono_R2, 1);
AudioConnection patchCord11(SD_Head, 0, Mono_L1, 1);
AudioConnection patchCord12(SD_Head, 1, Mono_R1, 1);
AudioConnection patchCord13(Crash_L, 0, Mono_L3, 3);
AudioConnection patchCord14(Crash_L, 1, Mono_R3, 3);
AudioConnection patchCord15(Ride_Bell, 0, Mono_L3, 2);
AudioConnection patchCord16(Ride_Bell, 1, Mono_R3, 2);
AudioConnection patchCord17(HiHat_Foot, 0, Mono_L3, 0);
AudioConnection patchCord18(HiHat_Foot, 1, Mono_R3, 0);
AudioConnection patchCord19(HiHat_Open, 0, Mono_L2, 2);
AudioConnection patchCord20(HiHat_Open, 1, Mono_R2, 2);
AudioConnection patchCord21(Ride_Edge, 0, Mono_L3, 1);
AudioConnection patchCord22(Ride_Edge, 1, Mono_R3, 1);
AudioConnection patchCord23(HiHat_Closed, 0, Mono_L2, 3);
AudioConnection patchCord24(HiHat_Closed, 1, Mono_R2, 3);
AudioConnection patchCord25(Crash_R, 0, Mono_L4, 0);
AudioConnection patchCord26(Crash_R, 1, Mono_R4, 0);
AudioConnection patchCord27(Mono_L1, 0, Stereo_L, 0);
AudioConnection patchCord28(Mono_L2, 0, Stereo_L, 1);
AudioConnection patchCord29(Mono_R2, 0, Stereo_R, 1);
AudioConnection patchCord30(Mono_L3, 0, Stereo_L, 2);
AudioConnection patchCord31(Mono_R3, 0, Stereo_R, 2);
AudioConnection patchCord32(Mono_L4, 0, Stereo_L, 3);
AudioConnection patchCord33(Mono_R1, 0, Stereo_R, 0);
AudioConnection patchCord34(Mono_R4, 0, Stereo_R, 3);
AudioConnection patchCord35(Stereo_L, 0, i2s1, 0);
AudioConnection patchCord36(Stereo_R, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=631,492
// GUItool: end automatically generated code
// SD-Card connection
#define SDCARD_CS_PIN BUILTIN_SDCARD
#define SDCARD_MOSI_PIN 11 // not actually used
#define SDCARD_SCK_PIN 13 // not actually used
void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(57600);
AudioMemory(50); // First question: How to determine, which setting is required??
sgtl5000_1.enable();
sgtl5000_1.volume(0.5);
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
if (!(SD.begin(SDCARD_CS_PIN))) {
while (1) {
//Serial.println("Unable to access the SD card");
delay(500);
}
}
// Gain Settings, to be adjustable in future by sliders/potis
Mono_L1.gain(0, 0.5); // Kick L
Mono_R1.gain(0, 0.5); // Kick R
Mono_L1.gain(1, 0.5); // Snare Head L
Mono_R1.gain(1, 0.5); // Snare Head R
Mono_L1.gain(2, 0.5); // Snare Rim L
Mono_R1.gain(2, 0.5); // Snare Rim R
Mono_L1.gain(3, 0.5); // HiTom L
Mono_R1.gain(3, 0); // HiTom R
Mono_L2.gain(0, 0.5); // MidTom L
Mono_R2.gain(0, 0.5); // MidTom R
Mono_L2.gain(1, 0); // LowTom L
Mono_R2.gain(1, 0.5); // LowTom R
Mono_L2.gain(2, 0.5); // HiHat_Open L
Mono_R2.gain(2, 0); // HiHat_Open R
Mono_L2.gain(3, 0.5); // HiHat_Closed L
Mono_R2.gain(3, 0); // HiHat_Closed R
Mono_L3.gain(0, 0.5); // HiHat Foot L
Mono_R3.gain(0, 0); // HiHat Foot R
Mono_L3.gain(1, 0); // Ride Edge L
Mono_R3.gain(1, 0.5); // Ride Edge R
Mono_L3.gain(2, 0); // Ride Bell L
Mono_R3.gain(2, 0.5); // Ride Bell R
Mono_L3.gain(3, 0.5); // Crash_L L
Mono_R3.gain(3, 0); // Crash_L R
Mono_L4.gain(0, 0); // Crash_R L
Mono_R4.gain(0, 0.5); // Crash_R L
Stereo_L.gain(0, 1.5);
Stereo_L.gain(1, 1.5);
Stereo_R.gain(0, 1.5);
Stereo_R.gain(1, 1.5);
delay(1000);
// Check number of samples of each note (used for velocity control later)
char dirname[16] = {'\0'}; //16 characters in the filename (or however long you want to make it)
sprintf(dirname,"/%d/",drumset);
Serial.println(dirname);
root = SD.open(dirname);
loadSamples(root);
}
unsigned long t=0;
void loop() {
int type, note, velocity, channel, d1, d2;
if (MIDI.read()) { // Is there a MIDI message incoming ?
byte type = MIDI.getType();
switch (type) {
case midi::NoteOn:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
if (velocity > 0) {
// Map Velocity depending on the number of available samples
short velomapped=map(velocity, 0, 127, 0, veloMap[note]);
velomapped=veloMap[note]-velomapped+1;
char filename[24];
size_t maxChars = sizeof(filename);
formatFilename( filename, maxChars, drumset, velomapped, note );
Serial.println(filename);
switch(note){
case 33:
HiHat_Open.play(filename);
break;
case 36:
Kick.play(filename);
break;
case 38:
SD_Head.play(filename);
break;
case 40:
SD_Rim.play(filename);
break;
case 43:
LowTom.play(filename);
break;
case 44:
HiHat_Foot.play(filename);
break;
case 45:
MidTom.play(filename);
break;
case 47:
HiTom.play(filename);
break;
case 48:
HiHat_Closed.play(filename);
break;
case 51:
Ride_Edge.play(filename);
break;
case 54:
Ride_Bell.play(filename);
break;
case 55:
Crash_L.play(filename);
break;
case 57:
Crash_R.play(filename);
break;
}
} else {
// Velocity is zero --> Nothing to do
}
break;
case midi::NoteOff:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
break;
default:
d1 = MIDI.getData1();
d2 = MIDI.getData2();
}
t = millis();
}
if (millis() - t > 10000) {
t += 10000;
}
}
void loadSamples(File dir) {
while(true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
char *newfile = entry.name();
unsigned short noteval;
unsigned short velocity;
if (parseFilename( newfile, noteval, velocity )) {
// Now we have noteval and velocity. Update the veloMap.
if (oldnoteval != noteval) {
oldnoteval = noteval;
veloCount = 1;
// Don't write past the end of the array
if (samplenum < MAX_SAMPLES-1) {
veloMap[noteval]=veloCount;
}
} else {
veloCount=veloCount+1;
// Don't write past the end of the array
if (samplenum < MAX_SAMPLES-1) {
veloMap[noteval]=veloCount;
}
}
}
entry.close();
}
}
bool parseFilename( char *newfile, unsigned short & noteval, unsigned short & velocity )
{
bool okFilename = false;
noteval = atoi( newfile ); // uses consecutive digits, up to the '_'
if (noteval > 0) {
char *ptr = strstr( newfile, "_V" ); // find the separator
if (ptr != nullptr) {
// ptr now "points at" the underscore character
ptr += 2; // step over the "_V" characters
velocity = atoi( ptr ); // use consecutive digits, up to the '.'
okFilename = true;
}
}
return okFilename;
} // parseFilename
void formatFilename
(
char *filename,
size_t maxChars,
unsigned int drumset,
unsigned int velocity,
unsigned int note
)
{
// Write a filename of the form "/123/12_V09.WAV"
char *ptr = filename; // start writing at the beginning
*ptr++ = '/'; // set element 0 and advance ptr to element 1
utoa( drumset, ptr, 10 ); // write drumset digits starting at element 1
size_t len = strlen( ptr ); // see how many digits were written (max 5)
ptr += len; // step past digits
*ptr++ = '/'; // append the next slash (overwrites NUL byte) and advance to next element
utoa( note, ptr, 10 ); // write velocity digits
len = strlen( ptr ); // see how many digits were written (max 5)
ptr += len; // step past digits
*ptr++ = '_'; // append "_V" while
*ptr++ = 'V'; // advancing pointer to next element(s)
if (velocity < 10)
*ptr++ = '0'; // append leading zero if necessary
utoa( velocity, ptr, 10 ); // write note digits
len = strlen( ptr ); // see how many digits were written (max 5)
ptr += len; // step past digits
strcpy_P( ptr, PSTR(".wav") ); // append extension and NUL terminator byte
} // formatFilename