/*
* Demonstration of interrupt-based triggering of prebuffered
* playback object, using the TeensyVariablePlayback library
*
* Uses samples converted from https://www.indiedrums.com/2012/10/10/free-drums-samples-rock-kit/
*/
#include <Audio.h>
#include <TeensyVariablePlayback.h>
#include "simple.h"
// GUItool: begin automatically generated code
AudioPlayWAVstereo playWAVstereo1A; //xy=170,66
AudioPlayWAVstereo playWAVstereo1B; //xy=174,108
AudioPlayWAVstereo playWAVstereo2A; //xy=190,240
AudioPlayWAVstereo playWAVstereo2B; //xy=194,282
AudioPlayWAVstereo playWAVstereo3A; //xy=202,409
AudioPlayWAVstereo playWAVstereo3B; //xy=206,451
AudioPlayWAVstereo playWAVstereo4A; //xy=213,567
AudioPlayWAVstereo playWAVstereo4B; //xy=217,609
AudioMixer4 mixer1L; //xy=400,70
AudioMixer4 mixer1R; //xy=406,137
AudioMixer4 mixer2L; //xy=420,244
AudioMixer4 mixer2R; //xy=426,311
AudioMixer4 mixer3L; //xy=432,413
AudioMixer4 mixer3R; //xy=438,480
AudioMixer4 mixer4L; //xy=441,566
AudioMixer4 mixer4R; //xy=449,638
AudioMixer4 mixerL; //xy=693,341
AudioMixer4 mixerR; //xy=702,414
AudioOutputI2S i2sOut; //xy=854,349
AudioConnection patchCord1(playWAVstereo1A, 0, mixer1L, 0);
AudioConnection patchCord2(playWAVstereo1A, 1, mixer1R, 0);
AudioConnection patchCord3(playWAVstereo1B, 0, mixer1L, 1);
AudioConnection patchCord4(playWAVstereo1B, 1, mixer1R, 1);
AudioConnection patchCord5(playWAVstereo2A, 0, mixer2L, 0);
AudioConnection patchCord6(playWAVstereo2A, 1, mixer2R, 0);
AudioConnection patchCord7(playWAVstereo2B, 0, mixer2L, 1);
AudioConnection patchCord8(playWAVstereo2B, 1, mixer2R, 1);
AudioConnection patchCord9(playWAVstereo3A, 0, mixer3L, 0);
AudioConnection patchCord10(playWAVstereo3A, 1, mixer3R, 0);
AudioConnection patchCord11(playWAVstereo3B, 0, mixer3L, 1);
AudioConnection patchCord12(playWAVstereo3B, 1, mixer3R, 1);
AudioConnection patchCord13(playWAVstereo4A, 0, mixer4L, 0);
AudioConnection patchCord14(playWAVstereo4A, 1, mixer4R, 0);
AudioConnection patchCord15(playWAVstereo4B, 0, mixer4L, 1);
AudioConnection patchCord16(playWAVstereo4B, 1, mixer4R, 1);
AudioConnection patchCord17(mixer1L, 0, mixerL, 0);
AudioConnection patchCord18(mixer1R, 0, mixerR, 0);
AudioConnection patchCord19(mixer2L, 0, mixerL, 1);
AudioConnection patchCord20(mixer2R, 0, mixerR, 1);
AudioConnection patchCord21(mixer3L, 0, mixerL, 2);
AudioConnection patchCord22(mixer3R, 0, mixerR, 2);
AudioConnection patchCord23(mixer4L, 0, mixerL, 3);
AudioConnection patchCord24(mixer4R, 0, mixerR, 3);
AudioConnection patchCord25(mixerL, 0, i2sOut, 0);
AudioConnection patchCord26(mixerR, 0, i2sOut, 1);
AudioControlSGTL5000 sgtl5000; //xy=842,409
// GUItool: end automatically generated code
#define COUNT_OF(a) ((int)(sizeof a / sizeof a[0]))
//==================================================================
SampleVoice sampleVoices[] = {
{{{playWAVstereo1A}, {playWAVstereo1B}}, mixer1L, mixer1R, -1},
{{{playWAVstereo2A}, {playWAVstereo2B}}, mixer2L, mixer2R, -1},
{{{playWAVstereo3A}, {playWAVstereo3B}}, mixer3L, mixer3R, -1},
{{{playWAVstereo4A}, {playWAVstereo4B}}, mixer4L, mixer4R, -1}
};
/*
* Cue up a voice ready to be triggered by IntervalTimer. Can take a
* while to pre-load the buffers, but it's not time-critical so long
* as it's ready when the step is triggered.
*/
char cueVoice(SampleVoice& voice, const char* file, float rate)
{
char result = ' ';
if (voice.cued < 0) // not cued, valid to cue up
{
int toCue = -1;
// pick a player to use
if (!voice.players[0].player.isPlaying()) // pick player A if it's idle...
toCue = 0;
else if (!voice.players[1].player.isPlaying()) // ...or player B if that's idle...
toCue = 1;
else if (voice.players[0].started < voice.players[1].started) // ... or A if it started longer ago...
toCue = 0;
else // ... or B
toCue = 1;
result=toCue?'B':'A';
// we have a player: cue it up
voice.players[toCue].player.setPlaybackRate(0.0f); // don't output yet
voice.players[toCue].player.playWav(file); // get it pre-loaded
voice.players[toCue].started = millis(); // it was ready at this time
voice.rate = rate; // rate to start at when triggered
voice.cued = toCue; // signal it's ready
}
return result; // which sample player got used, A or B, or space if neither
}
/*
* Called from IntervalTimer callback to start voice
* playing at a precise instant.
*/
void startVoice(SampleVoice& voice)
{
if (voice.cued >= 0) // safety check
{
voice.players[voice.cued].player.setPlaybackRate(voice.rate);
voice.cued = -1; // no longer cued
}
}
void initVoices(void)
{
for (int i=0;i<COUNT_OF(sampleVoices);i++)
{
for (int j=0;j<COUNT_OF(sampleVoices[i].players);j++)
sampleVoices[i].players[j].player.setBufferInPSRAM(true);
mixerL.gain(i,0.2f + 0.2f*i);
mixerR.gain(i,0.8f - 0.2f*i);
}
}
//==================================================================
IntervalTimer intvl;
volatile int stepNum;
void intvlFn(void)
{
digitalToggleFast(LED_BUILTIN);
// start all cued samples
for (int i=0;i<COUNT_OF(sampleVoices);i++)
if (sampleVoices[i].cued >= 0)
startVoice(sampleVoices[i]);
// signal foreground that next step can be cued up
stepNum++;
if (stepNum >= 16)
stepNum = 0;
}
//==================================================================
void setup()
{
AudioMemory(40);
while (!Serial)
;
pinMode(LED_BUILTIN, OUTPUT);
// initialise output hardware
sgtl5000.enable();
sgtl5000.volume(0.15);
// initialise SD card
while (!(SD.begin(BUILTIN_SDCARD)))
{
// print a message repeatedly until begin() succeeds
Serial.println("Unable to access the SD card");
delay(500);
}
initVoices();
Serial.println("Running");
intvl.begin(intvlFn, 125000); // trigger at 125ms interval
}
int lastStepNum = -1;
void loop()
{
if (lastStepNum != stepNum)
{
char cued = ' ';
lastStepNum = stepNum;
switch (lastStepNum)
{
case 0:
case 7:
case 8:
cued = cueVoice(sampleVoices[0], "/drums/44k-Kick-ff-2.wav", 1.0f);
break;
case 2:
case 6:
case 11:
case 14:
cued = cueVoice(sampleVoices[3], "/drums/44k-HiHat-Tip-2.wav", 1.0f);
break;
case 4:
case 12:
cued = cueVoice(sampleVoices[1], "/drums/44k-Snare-ff-1.wav", 1.0f);
break;
case 10:
cued = cueVoice(sampleVoices[3], "/drums/44k-HiHat-Open.wav", 1.0f);
break;
}
if (' ' != cued)
Serial.printf("%lu: Cue step %d: voice %c\n", millis(), lastStepNum, cued);
}
}