// Play back sounds from SD card and LittleFS
// Tested on Teensy 4.1, changes may be needed for 3.x
#include <SD.h>
#include <Bounce.h>
#include <Audio.h>
#include <LittleFS.h>
SDClass sd1; // actually an SD card
// Use a LittleFS RAM disc, as I don't have a QSPI Flash:
EXTMEM char litlPSRAM[1024 * 1024]; // allocate 1MB of PSRAM for LittleFS
LittleFS_RAM sd2; // actually LittleFS - leave the name to minimise changes to code
// GUItool: begin automatically generated code
AudioInputI2S i2s2; //xy=103,82
AudioAnalyzePeak peak1; //xy=276,127
AudioRecordQueue queue1; //xy=279,82
AudioPlayWAVstereo playRaw1; //xy=296,179
AudioPlayWAVstereo playRaw2; //xy=305,222
AudioAmplifier amp1; //xy=476,173
AudioAmplifier amp2; //xy=481,218
AudioOutputI2S i2s1; //xy=661,194
AudioConnection patchCord1(i2s2, 0, queue1, 0);
AudioConnection patchCord2(i2s2, 0, peak1, 0);
AudioConnection patchCord3(playRaw1, 0, amp1, 0);
AudioConnection patchCord4(playRaw2, 0, amp2, 0);
AudioConnection patchCord5(amp1, 0, i2s1, 0);
AudioConnection patchCord6(amp2, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=279,306
// GUItool: end automatically generated code
// Bounce objects to easily and reliably read the buttons
Bounce buttonPlay1 = Bounce(30, 8);
Bounce buttonPlay2 = Bounce(31, 8);
//==================================================================
bool FileCopy(FS& fsSrc,const char* fnSrc, FS& fsDst, const char* fnDst)
{
File src,dst;
bool success = false;
src = fsSrc.open(fnSrc,FILE_READ);
if (src)
{
fsDst.remove(fnDst);
dst = fsDst.open(fnDst,FILE_WRITE);
if (dst)
{
char buf[1024];
int got;
do
{
got = src.read(buf, sizeof buf);
if (got > 0)
dst.write(buf,got);
} while (got > 0);
dst.close();
success = true;
}
src.close();
}
return success;
}
//==================================================================
const char* copiedFile = "sine330.wav";
void setup() {
// Configure the pushbutton pins
pinMode(30, INPUT_PULLUP);
pinMode(31, INPUT_PULLUP);
// Audio connections require memory
AudioMemory(10);
while (!Serial)
;
Serial.println("Started!");
// Enable the audio shield, select input, and enable output
sgtl5000_1.setAddress(HIGH);
sgtl5000_1.enable();
sgtl5000_1.volume(0.2);
playRaw1.createBuffer(2048,AudioBuffer::inHeap);
playRaw2.createBuffer(4096,AudioBuffer::inHeap);
amp1.gain(0.5f);
amp2.gain(0.5f);
// initialize the internal Teensy 4.1 SD card
if (!sd1.begin(BUILTIN_SDCARD))
Serial.println("error sd1.begin");
// initialize the LittleFS filesystem
if (!sd2.begin(litlPSRAM, sizeof litlPSRAM ))
Serial.println("error sd2.begin");
// copy an audio file from SD to LittleFS
if (FileCopy(sd1,"sine330.wav", sd2,copiedFile))
Serial.printf("%s copied OK\n", copiedFile);
else
Serial.printf("Couldn't copy %s\n", copiedFile);
queue1.begin();
}
//==================================================================
volatile uint32_t audio_update_count;
void audio_timer_early_hook(void)
{
audio_update_count++;
}
//==================================================================
void printInstrument(AudioPlayWAVstereo& o, const char* nam)
{
Serial.printf("%s: low-water: %u; worst read time: %uus; updates: %u; update count %lu\n",
nam,
o.bufferAvail.getLowest(),
o.readMicros.getHighest(),
o.bufferAvail.getUpdates(),
audio_update_count);
o.bufferAvail.reset();
o.readMicros.reset();
}
//==================================================================
void loop() {
buttonPlay1.update();
buttonPlay2.update();
if (buttonPlay1.fallingEdge()) {
Serial.println("Play 1");
playRaw1.play("sine220.wav", sd1);
}
if (buttonPlay2.fallingEdge()) {
Serial.println("Play 2");
playRaw2.play(copiedFile, sd2);
}
static uint32_t next = 0;
if (millis() >= next)
{
next = millis() + 250;
if (playRaw1.isPlaying())
printInstrument(playRaw1,"playRaw1");
if (playRaw2.isPlaying())
printInstrument(playRaw2,"playRaw2");
}
// ideally this would be supported by the Audio library,
// but for now we hack our own audio update count
if (queue1.available())
{
queue1.readBuffer();
queue1.freeBuffer();
audio_timer_early_hook();
}
}