Teensy 4.0 - based Audio Guestbook

Hi,

Thank you so much for taking your time to help.

So I am new to this and have followed the instructions and alterations to my best abilities, This is the error I have followed by the coding.


Error:

Arduino: 1.8.19 (Windows 10), TD: 1.58, Board: "Teensy 4.0, Serial, 150 MHz, Faster, US English"

C:\Users\02dim\Documents\Arduino\phone_book\phone_book.ino:24:10: fatal error: MTP_Teensy.h: No such file or directory

Multiple libraries were found for "SD.h"

24 | #include <MTP_Teensy.h>

Used: C:\Program Files (x86)\Arduino\hardware\Teensy\avr\libraries\SD

| ^~~~~~~~~~~~~~

Not used: C:\Program Files (x86)\Arduino\libraries\SD

compilation terminated.

Error compiling for board Teensy 4.0.



This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.]








The Code I have used:

/**

Audio Guestbook, Copyright (c) 2022 Playful Technology
Tested using a Teensy 4.0 with Teensy Audio Shield, although should work
with minor modifications on other similar hardware
When handset is lifted, a pre-recorded greeting message is played, followed by a tone.
Then, recording starts, and continues until the handset is replaced.
Playback button allows all messages currently saved on SD card through earpiece
Files are saved on SD card as 44.1kHz, 16-bit, mono signed integer RAW audio format
--> changed this to WAV recording, DD4WH 2022_07_31
--> added MTP support, which enables copying WAV files from the SD card via the USB connection, DD4WH 2022_08_01
Frank DD4WH, August 1st 2022
for a DBP 611 telephone (closed contact when handheld is lifted) & with recording to WAV file
contact for switch button 0 is closed when handheld is lifted
GNU GPL v3.0 license
*/

#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <TimeLib.h>
#include <MTP_Teensy.h>
#include "play_sd_wav.h" // local copy with fixes

// DEFINES
// Define pins used by Teensy Audio Shield
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 7
#define SDCARD_SCK_PIN 14
// And those used for inputs
#define HOOK_PIN 0
#define PLAYBACK_BUTTON_PIN 1

#define noINSTRUMENT_SD_WRITE

// GLOBALS
// Audio initialisation code can be generated using the GUI interface at https://www.pjrc.com/teensy/gui/
// Inputs
AudioSynthWaveform waveform1; // To create the "beep" sfx
AudioInputI2S i2s2; // I2S input from microphone on audio shield
AudioPlaySdWav playWav1; // Play 44.1kHz 16-bit PCM greeting WAV file
AudioRecordQueue queue1; // Creating an audio buffer in memory before saving to SD
AudioMixer4 mixer; // Allows merging several inputs to same output
AudioOutputI2S i2s1; // I2S interface to Speaker/Line Out on Audio shield
AudioConnection patchCord1(waveform1, 0, mixer, 0); // wave to mixer
AudioConnection patchCord3(playWav1, 0, mixer, 1); // wav file playback mixer
AudioConnection patchCord4(mixer, 0, i2s1, 0); // mixer output to speaker (L)
AudioConnection patchCord6(mixer, 0, i2s1, 1); // mixer output to speaker (R)
AudioConnection patchCord5(i2s2, 0, queue1, 0); // mic input to queue (L)
AudioControlSGTL5000 sgtl5000_1;

// Filename to save audio recording on SD card
char filename[15];
// The file object itself
File frec;

// Use long 40ms debounce time on both switches
Bounce buttonRecord = Bounce(HOOK_PIN, 40);
Bounce buttonPlay = Bounce(PLAYBACK_BUTTON_PIN, 40);

// Keep track of current state of the device
enum Mode {Initialising, Ready, Prompting, Recording, Playing};
Mode mode = Mode::Initialising;

float beep_volume = 0.04f; // not too loud :)

uint32_t MTPcheckInterval; // default value of device check interval [ms]

// variables for writing to WAV file
unsigned long ChunkSize = 0L;
unsigned long Subchunk1Size = 16;
unsigned int AudioFormat = 1;
unsigned int numChannels = 1;
unsigned long sampleRate = 44100;
unsigned int bitsPerSample = 16;
unsigned long byteRate = sampleRatenumChannels(bitsPerSample/8);// samplerate x channels x (bitspersample / 8)
unsigned int blockAlign = numChannels*bitsPerSample/8;
unsigned long Subchunk2Size = 0L;
unsigned long recByteSaved = 0L;
unsigned long NumSamples = 0L;
byte byte1, byte2, byte3, byte4;

void setup() {

Serial.begin(9600);
while (!Serial && millis() < 5000) {
// wait for serial port to connect.
}
Serial.println("Serial set up correctly");
Serial.printf("Audio block set to %d samples\n",AUDIO_BLOCK_SAMPLES);
print_mode();
// Configure the input pins
pinMode(HOOK_PIN, INPUT_PULLUP);
pinMode(PLAYBACK_BUTTON_PIN, INPUT_PULLUP);

// Audio connections require memory, and the record queue
// uses this memory to buffer incoming audio.
AudioMemory(60);

// Enable the audio shield, select input, and enable output
sgtl5000_1.enable();
// Define which input on the audio shield to use (AUDIO_INPUT_LINEIN / AUDIO_INPUT_MIC)
sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
//sgtl5000_1.adcHighPassFilterDisable(); //
sgtl5000_1.volume(0.95);

mixer.gain(0, 1.0f);
mixer.gain(1, 1.0f);

// Play a beep to indicate system is online
waveform1.begin(beep_volume, 440, WAVEFORM_SINE);
wait(1000);
waveform1.amplitude(0);
delay(1000);

// Initialize the SD card
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
if (!(SD.begin(SDCARD_CS_PIN)))
{
// stop here if no SD card, but print a message
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
else Serial.println("SD card correctly initialized");

// mandatory to begin the MTP session.
MTP.begin();

// Add SD Card
// MTP.addFilesystem(SD, "SD Card");
MTP.addFilesystem(SD, "Kais Audio guestbook"); // choose a nice name for the SD card volume to appear in your file explorer
Serial.println("Added SD card via MTP");
MTPcheckInterval = MTP.storage()->get_DeltaDeviceCheckTimeMS();

// Value in dB
// sgtl5000_1.micGain(15);
sgtl5000_1.micGain(5); // much lower gain is required for the AOM5024 electret capsule

// Synchronise the Time object used in the program code with the RTC time provider.
// See https://github.com/PaulStoffregen/Time
setSyncProvider(getTeensy3Time);

// Define a callback that will assign the correct datetime for any file system operations
// (i.e. saving a new audio recording onto the SD card)
FsDateTime::setCallback(dateTime);

mode = Mode::Ready; print_mode();
}

void loop() {
// First, read the buttons
buttonRecord.update();
buttonPlay.update();

switch(mode){
case Mode::Ready:
// Falling edge occurs when the handset is lifted --> 611 telephone
if (buttonRecord.fallingEdge()) {
Serial.println("Handset lifted");
mode = Mode::prompting; print_mode();
}
else if(buttonPlay.fallingEdge()) {
//playAllRecordings();
playLastRecording();
}
break;

case Mode::prompting:
// Wait a second for users to put the handset to their ear
wait(1000);
// Play the greeting inviting them to record their message
playWav1.play("greeting.wav");
// Wait until the message has finished playing
// while (playWav1.isPlaying()) {
while (!playWav1.isStopped()) {
// Check whether the handset is replaced
buttonRecord.update();
buttonPlay.update();
// Handset is replaced
if(buttonRecord.risingEdge()) {
playWav1.stop();
mode = Mode::Ready; print_mode();
return;
}
if(buttonPlay.fallingEdge()) {
playWav1.stop();
//playAllRecordings();
playLastRecording();
return;
}

}
// Debug message
Serial.println("Starting Recording");
// Play the tone sound effect
waveform1.begin(beep_volume, 440, WAVEFORM_SINE);
wait(1250);
waveform1.amplitude(0);
// Start the recording function
startRecording();
break;

case Mode::Recording:
// Handset is replaced
if(buttonRecord.risingEdge()){
// Debug log
Serial.println("Stopping Recording");
// Stop recording
stopRecording();
// Play audio tone to confirm recording has ended
end_Beep();
}
else {
continueRecording();
}
break;

case Mode::playing: // to make compiler happy
break;

case Mode::Initialising: // to make compiler happy
break;
}

MTP.loop(); // This is mandatory to be placed in the loop code.
}

void setMTPdeviceChecks(bool nable)
{
if (nable)
{
MTP.storage()->set_DeltaDeviceCheckTimeMS(MTPcheckInterval);
Serial.print("En");
}
else
{
MTP.storage()->set_DeltaDeviceCheckTimeMS((uint32_t) -1);
Serial.print("Dis");
}
Serial.println("abled MTP storage device checks");
}

#if defined(INSTRUMENT_SD_WRITE)
static uint32_t worstSDwrite, printNext;
#endif // defined(INSTRUMENT_SD_WRITE)

void startRecording() {
setMTPdeviceChecks(false); // disable MTP device checks while recording
#if defined(INSTRUMENT_SD_WRITE)
worstSDwrite = 0;
printNext = 0;
#endif // defined(INSTRUMENT_SD_WRITE)
// Find the first available file number
// for (uint8_t i=0; i<9999; i++) { // BUGFIX uint8_t overflows if it reaches 255
for (uint16_t i=0; i<9999; i++) {
// Format the counter as a five-digit number with leading zeroes, followed by file extension
snprintf(filename, 11, " %05d.wav", i);
// Create if does not exist, do not open existing, write, sync after write
if (!SD.exists(filename)) {
break;
}
}
frec = SD.open(filename, FILE_WRITE);
Serial.println("Opened file !");
if(frec) {
Serial.print("Recording to ");
Serial.println(filename);
queue1.begin();
mode = Mode::Recording; print_mode();
recByteSaved = 0L;
}
else {
Serial.println("Couldn't open file to record!");
}
}

void continueRecording() {
#if defined(INSTRUMENT_SD_WRITE)
uint32_t started = micros();
#endif // defined(INSTRUMENT_SD_WRITE)
#define NBLOX 16
// Check if there is data in the queue
if (queue1.available() >= NBLOX) {
byte buffer[NBLOXAUDIO_BLOCK_SAMPLESsizeof(int16_t)];
// Fetch 2 blocks from the audio library and copy
// into a 512 byte buffer. The Arduino SD library
// is most efficient when full 512 byte sector size
// writes are used.
for (int i=0;i<NBLOX;i++)
{
memcpy(buffer+iAUDIO_BLOCK_SAMPLESsizeof(int16_t), queue1.readBuffer(), AUDIO_BLOCK_SAMPLES*sizeof(int16_t));
queue1.freeBuffer();
}
// Write all 512 bytes to the SD card
frec.write(buffer, sizeof buffer);
recByteSaved += sizeof buffer;
}

#if defined(INSTRUMENT_SD_WRITE)
started = micros() - started;
if (started > worstSDwrite)
worstSDwrite = started;

if (millis() >= printNext)
{
Serial.printf("Worst write took %luus\n",worstSDwrite);
worstSDwrite = 0;
printNext = millis()+250;
}
#endif // defined(INSTRUMENT_SD_WRITE)
}

void stopRecording() {
// Stop adding any new data to the queue
queue1.end();
// Flush all existing remaining data from the queue
while (queue1.available() > 0) {
// Save to open file
frec.write((byte*)queue1.readBuffer(), AUDIO_BLOCK_SAMPLESsizeof(int16_t));
queue1.freeBuffer();
recByteSaved += AUDIO_BLOCK_SAMPLESsizeof(int16_t);
}
writeOutHeader();
// Close the file
frec.close();
Serial.println("Closed file");
mode = Mode::Ready; print_mode();
setMTPdeviceChecks(true); // enable MTP device checks, recording is finished
}

void playAllRecordings() {
// Recording files are saved in the root directory
File dir = SD.open("/");

while (true) {
File entry = dir.openNextFile();
if (strstr(entry.name(), "greeting"))
{
entry = dir.openNextFile();
}
if (!entry) {
// no more files
entry.close();
end_Beep();
break;
}
//int8_t len = strlen(entry.name()) - 4;
// if (strstr(strlwr(entry.name() + (len - 4)), ".raw")) {
// if (strstr(strlwr(entry.name() + (len - 4)), ".wav")) {
// the lines above throw a warning, so I replace them with this (which is also easier to read):
if (strstr(entry.name(), ".wav") || strstr(entry.name(), ".WAV")) {
Serial.print("Now playing ");
Serial.println(entry.name());
// Play a short beep before each message
waveform1.amplitude(beep_volume);
wait(750);
waveform1.amplitude(0);
// Play the file
playWav1.play(entry.name());
mode = Mode::playing; print_mode();
}
entry.close();

// while (playWav1.isPlaying()) { // strangely enough, this works for playRaw, but it does not work properly for playWav
while (!playWav1.isStopped()) { // this works for playWav
buttonPlay.update();
buttonRecord.update();
// Button is pressed again
// if(buttonPlay.risingEdge() || buttonRecord.risingEdge()) { // FIX
if(buttonPlay.fallingEdge() || buttonRecord.risingEdge()) {
playWav1.stop();
mode = Mode::Ready; print_mode();
return;
}
}
}
// All files have been played
mode = Mode::Ready; print_mode();
}

void playLastRecording() {
// Find the first available file number
uint16_t idx = 0;
for (uint16_t i=0; i<9999; i++) {
// Format the counter as a five-digit number with leading zeroes, followed by file extension
snprintf(filename, 11, " %05d.wav", i);
// check, if file with index i exists
if (!SD.exists(filename)) {
idx = i - 1;
break;
}
}
// now play file with index idx == last recorded file
snprintf(filename, 11, " %05d.wav", idx);
Serial.println(filename);
playWav1.play(filename);
mode = Mode::playing; print_mode();
while (!playWav1.isStopped()) { // this works for playWav
buttonPlay.update();
buttonRecord.update();
// Button is pressed again
// if(buttonPlay.risingEdge() || buttonRecord.risingEdge()) { // FIX
if(buttonPlay.fallingEdge() || buttonRecord.risingEdge()) {
playWav1.stop();
mode = Mode::Ready; print_mode();
return;
}
}
// file has been played
mode = Mode::Ready; print_mode();
end_Beep();
}

// Retrieve the current time from Teensy built-in RTC
time_t getTeensy3Time(){
return Teensy3Clock.get();
}

// Callback to assign timestamps for file system operations
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {

// Return date using FS_DATE macro to format fields.
*date = FS_DATE(year(), month(), day());

// Return time using FS_TIME macro to format fields.
*time = FS_TIME(hour(), minute(), second());

// Return low time bits in units of 10 ms.
*ms10 = second() & 1 ? 100 : 0;
}

// Non-blocking delay, which pauses execution of main program logic,
// but while still listening for input
void wait(unsigned int milliseconds) {
elapsedMillis msec=0;

while (msec <= milliseconds) {
buttonRecord.update();
buttonPlay.update();
if (buttonRecord.fallingEdge()) Serial.println("Button (pin 0) Press");
if (buttonPlay.fallingEdge()) Serial.println("Button (pin 1) Press");
if (buttonRecord.risingEdge()) Serial.println("Button (pin 0) Release");
if (buttonPlay.risingEdge()) Serial.println("Button (pin 1) Release");
}
}

void writeOutHeader() { // update WAV header with final filesize/datasize

// NumSamples = (recByteSaved8)/bitsPerSample/numChannels;
// Subchunk2Size = NumSamplesnumChannels*bitsPerSample/8; // number of samples x number of channels x number of bytes per sample
Subchunk2Size = recByteSaved - 42; // because we didn't make space for the header to start with! Lose 21 samples...
ChunkSize = Subchunk2Size + 34; // was 36;
frec.seek(0);
frec.write("RIFF");
byte1 = ChunkSize & 0xff;
byte2 = (ChunkSize >> 8) & 0xff;
byte3 = (ChunkSize >> 16) & 0xff;
byte4 = (ChunkSize >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
frec.write("WAVE");
frec.write("fmt ");
byte1 = Subchunk1Size & 0xff;
byte2 = (Subchunk1Size >> 8) & 0xff;
byte3 = (Subchunk1Size >> 16) & 0xff;
byte4 = (Subchunk1Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = AudioFormat & 0xff;
byte2 = (AudioFormat >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = numChannels & 0xff;
byte2 = (numChannels >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = sampleRate & 0xff;
byte2 = (sampleRate >> 8) & 0xff;
byte3 = (sampleRate >> 16) & 0xff;
byte4 = (sampleRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = byteRate & 0xff;
byte2 = (byteRate >> 8) & 0xff;
byte3 = (byteRate >> 16) & 0xff;
byte4 = (byteRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = blockAlign & 0xff;
byte2 = (blockAlign >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = bitsPerSample & 0xff;
byte2 = (bitsPerSample >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
frec.write("data");
byte1 = Subchunk2Size & 0xff;
byte2 = (Subchunk2Size >> 8) & 0xff;
byte3 = (Subchunk2Size >> 16) & 0xff;
byte4 = (Subchunk2Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
frec.close();
Serial.println("header written");
Serial.print("Subchunk2: ");
Serial.println(Subchunk2Size);
}

void end_Beep(void) {
waveform1.frequency(523.25);
waveform1.amplitude(beep_volume);
wait(250);
waveform1.amplitude(0);
wait(250);
waveform1.amplitude(beep_volume);
wait(250);
waveform1.amplitude(0);
wait(250);
waveform1.amplitude(beep_volume);
wait(250);
waveform1.amplitude(0);
wait(250);
waveform1.amplitude(beep_volume);
wait(250);
waveform1.amplitude(0);
}

void print_mode(void) { // only for debugging
Serial.print("Mode switched to: ");
// Initialising, Ready, Prompting, Recording, Playing
if(mode == Mode::Ready) Serial.println(" Ready");
else if(mode == Mode::prompting) Serial.println(" Prompting");
else if(mode == Mode::Recording) Serial.println(" Recording");
else if(mode == Mode::playing) Serial.println(" Playing");
else if(mode == Mode::Initialising) Serial.println(" Initialising");
else Serial.println(" Undefined");
}
 
I just wanted to write here that the suggestion h4yn0nnym0u5e of using the built in teensy sd card solves the motorboarding issue with the audio. Just had to comment the following lines and replace them with the ones below them:

Code:
  // Initialize the SD card
//  SPI.setMOSI(SDCARD_MOSI_PIN);
//  SPI.setSCK(SDCARD_SCK_PIN);
//  if (!(SD.begin(SDCARD_CS_PIN))) 
//  {
//    // stop here if no SD card, but print a message
//    while (1) {
//      Serial.println("Unable to access the SD card");
//      delay(500);
//    }
//  }
//    else Serial.println("SD card correctly initialized");


  const int chipSelect = BUILTIN_SDCARD; 
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

With this (and obviously changing the sd card from the audio shield to the teensy board). The audio is great now.

Something weird, that needs further testing from my end, is that, when powered with a powerbank, the audio is completely clean. However, when powered via a usb port from the pc, I can hear a distinct high freqency buzz. I can not say exactly where this is coming from, but it doesn't really matter, as the final prodcut will be powered with a powerbank.



Thank you so much for this comment. I can confirm this worked for me as well. I've had the same issue with Teensy 4.0. I replaced it with a 4.1 and now I'm not having any motorboarding sound anymore. I used the code mentioned here.

One thing I've noticed. If I set sgtl5000_1.micGain(40) I will have a bit of white noise. If I lower the gain to 32 it is sound great. I also replaced the mic with a cheap one from Amazon.

Thanks again Cocoman, I owe you a drink!

Cheers!
 
The modified & created timestamp is always starting on 01-01-2019 00:00 when I plug the telephone into a usb power supply. Is there a way to set the proper date?
 
hi all,

been through a lot of the documentation and still got a few issues.

Im running IDE 2.2.1, but unable to set the number of blocks to 256. The option is not displayed in the tools menu, and I have added the boards.local.txt to the teensy location (confirmed using properties of the program).

I am also finding on 2 of the same phones, one audio recorded message is much quieter than the other. The wiring has been done the same - one sounds like its been recorded under water, but loud, the other sounds like its been recorded far away from the mic. I can repair the audio in audacity to a decent level, but would be nice to make this change at a hardware level. Also, on the quiet recording, I am getting the "ticks". From previous posts it appears to be an SD card write issue. I am using a Teensy 4.0, changing SD cards makes no difference - would the jump to 4.1 eliminate the issue?

any help greatly appreciated.

Code:
/**
 * Audio Guestbook, Copyright (c) 2022 Playful Technology
 * 
 * Tested using a Teensy 4.0 with Teensy Audio Shield, although should work 
 * with minor modifications on other similar hardware
 * 
 * When handset is lifted, a pre-recorded greeting message is played, followed by a tone.
 * Then, recording starts, and continues until the handset is replaced.
 * Playback button allows all messages currently saved on SD card through earpiece 
 * 
 * Files are saved on SD card as 44.1kHz, 16-bit, mono signed integer RAW audio format 
 * --> changed this to WAV recording, DD4WH 2022_07_31
 * --> added MTP support, which enables copying WAV files from the SD card via the USB connection, DD4WH 2022_08_01
 * 
 * 
 * Frank DD4WH, August 1st 2022 
 * for a DBP 611 telephone (closed contact when handheld is lifted) & with recording to WAV file
 * contact for switch button 0 is closed when handheld is lifted
 * 
 * GNU GPL v3.0 license
 * 
 */

#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <TimeLib.h>
#include <MTP_Teensy.h>
#include "play_sd_wav.h" // local copy with fixes

// DEFINES
// Define pins used by Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14
// And those used for inputs
#define HOOK_PIN 0
#define PLAYBACK_BUTTON_PIN 1

#define noINSTRUMENT_SD_WRITE

// GLOBALS
// Audio initialisation code can be generated using the GUI interface at https://www.pjrc.com/teensy/gui/
// Inputs
AudioSynthWaveform          waveform1; // To create the "beep" sfx
AudioInputI2S               i2s2; // I2S input from microphone on audio shield
AudioPlaySdWavX              playWav1; // Play 44.1kHz 16-bit PCM greeting WAV file
AudioRecordQueue            queue1; // Creating an audio buffer in memory before saving to SD
AudioMixer4                 mixer; // Allows merging several inputs to same output
AudioOutputI2S              i2s1; // I2S interface to Speaker/Line Out on Audio shield
AudioConnection patchCord1(waveform1, 0, mixer, 0); // wave to mixer 
AudioConnection patchCord3(playWav1, 0, mixer, 1); // wav file playback mixer
AudioConnection patchCord4(mixer, 0, i2s1, 0); // mixer output to speaker (L)
AudioConnection patchCord6(mixer, 0, i2s1, 1); // mixer output to speaker (R)
AudioConnection patchCord5(i2s2, 0, queue1, 0); // mic input to queue (L)
AudioControlSGTL5000      sgtl5000_1;

// Filename to save audio recording on SD card
char filename[15];
// The file object itself
File frec;

// Use long 40ms debounce time on both switches
Bounce buttonRecord = Bounce(HOOK_PIN, 40);
Bounce buttonPlay = Bounce(PLAYBACK_BUTTON_PIN, 40);

// Keep track of current state of the device
enum Mode {Initialising, Ready, Prompting, Recording, Playing};
Mode mode = Mode::Initialising;

float beep_volume = 0.04f; // not too loud :-)

uint32_t MTPcheckInterval; // default value of device check interval [ms]

// variables for writing to WAV file
unsigned long ChunkSize = 0L;
unsigned long Subchunk1Size = 16;
unsigned int AudioFormat = 1;
unsigned int numChannels = 1;
unsigned long sampleRate = 44100;
unsigned int bitsPerSample = 16;
unsigned long byteRate = sampleRate*numChannels*(bitsPerSample/8);// samplerate x channels x (bitspersample / 8)
unsigned int blockAlign = numChannels*bitsPerSample/8;
unsigned long Subchunk2Size = 0L;
unsigned long recByteSaved = 0L;
unsigned long NumSamples = 0L;
byte byte1, byte2, byte3, byte4;


void setup() {

  Serial.begin(9600);
  while (!Serial && millis() < 5000) {
    // wait for serial port to connect.
  }
  Serial.println("Serial set up correctly");
  Serial.printf("Audio block set to %d samples\n",AUDIO_BLOCK_SAMPLES);
  print_mode();
  // Configure the input pins
  pinMode(HOOK_PIN, INPUT_PULLUP);
  pinMode(PLAYBACK_BUTTON_PIN, INPUT_PULLUP);

  // Audio connections require memory, and the record queue
  // uses this memory to buffer incoming audio.
  AudioMemory(60);

  // Enable the audio shield, select input, and enable output
  sgtl5000_1.enable();
  // Define which input on the audio shield to use (AUDIO_INPUT_LINEIN / AUDIO_INPUT_MIC)
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  //sgtl5000_1.adcHighPassFilterDisable(); //
  sgtl5000_1.volume(0.95);

  mixer.gain(0, 1.0f);
  mixer.gain(1, 1.0f);

  // Play a beep to indicate system is online
  waveform1.begin(beep_volume, 440, WAVEFORM_SINE);
  wait(1000);
  waveform1.amplitude(0);
  delay(1000);

  // Initialize the SD card
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) 
  {
    // stop here if no SD card, but print a message
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
    else Serial.println("SD card correctly initialized");


  // mandatory to begin the MTP session.
    MTP.begin();

  // Add SD Card
//    MTP.addFilesystem(SD, "SD Card");
    MTP.addFilesystem(SD, "my SD card name"); // choose a nice name for the SD card volume to appear in your file explorer
    Serial.println("Added SD card via MTP");
    MTPcheckInterval = MTP.storage()->get_DeltaDeviceCheckTimeMS();
    
    // Value in dB
//  sgtl5000_1.micGain(15);
  sgtl5000_1.micGain(5); // much lower gain is required for the AOM5024 electret capsule

  // Synchronise the Time object used in the program code with the RTC time provider.
  // See https://github.com/PaulStoffregen/Time
  setSyncProvider(getTeensy3Time);
  
  // Define a callback that will assign the correct datetime for any file system operations
  // (i.e. saving a new audio recording onto the SD card)
  FsDateTime::setCallback(dateTime);

  mode = Mode::Ready; print_mode();
}

void loop() {
  // First, read the buttons
  buttonRecord.update();
  buttonPlay.update();

  switch(mode){
    case Mode::Ready:
      // Falling edge occurs when the handset is lifted --> 611 telephone
      if (buttonRecord.fallingEdge()) {
        Serial.println("Handset lifted");
        mode = Mode::Prompting; print_mode();
      }
      else if(buttonPlay.fallingEdge()) {
        //playAllRecordings();
        playLastRecording();
      }
      break;

    case Mode::Prompting:
      // Wait a second for users to put the handset to their ear
      wait(1000);
      // Play the greeting inviting them to record their message
      playWav1.play("greeting.wav");    
      // Wait until the  message has finished playing
//      while (playWav1.isPlaying()) {
      while (!playWav1.isStopped()) {
        // Check whether the handset is replaced
        buttonRecord.update();
        buttonPlay.update();
        // Handset is replaced
        if(buttonRecord.risingEdge()) {
          playWav1.stop();
          mode = Mode::Ready; print_mode();
          return;
        }
        if(buttonPlay.fallingEdge()) {
          playWav1.stop();
          //playAllRecordings();
          playLastRecording();
          return;
        }
        
      }
      // Debug message
      Serial.println("Starting Recording");
      // Play the tone sound effect
      waveform1.begin(beep_volume, 440, WAVEFORM_SINE);
      wait(1250);
      waveform1.amplitude(0);
      // Start the recording function
      startRecording();
      break;

    case Mode::Recording:
      // Handset is replaced
      if(buttonRecord.risingEdge()){
        // Debug log
        Serial.println("Stopping Recording");
        // Stop recording
        stopRecording();
        // Play audio tone to confirm recording has ended
        end_Beep();
      }
      else {
        continueRecording();
      }
      break;

    case Mode::Playing: // to make compiler happy
      break;  

    case Mode::Initialising: // to make compiler happy
      break;  
  }   
  
  MTP.loop();  // This is mandatory to be placed in the loop code.
}

void setMTPdeviceChecks(bool nable)
{
  if (nable)
  {
    MTP.storage()->set_DeltaDeviceCheckTimeMS(MTPcheckInterval);
    Serial.print("En");
  }
  else
  {
    MTP.storage()->set_DeltaDeviceCheckTimeMS((uint32_t) -1);
    Serial.print("Dis");
  }
  Serial.println("abled MTP storage device checks");
}
  

#if defined(INSTRUMENT_SD_WRITE)
static uint32_t worstSDwrite, printNext;
#endif // defined(INSTRUMENT_SD_WRITE)

void startRecording() {
  setMTPdeviceChecks(false); // disable MTP device checks while recording
#if defined(INSTRUMENT_SD_WRITE)
  worstSDwrite = 0;
  printNext = 0;
#endif // defined(INSTRUMENT_SD_WRITE)
  // Find the first available file number
//  for (uint8_t i=0; i<9999; i++) { // BUGFIX uint8_t overflows if it reaches 255  
  for (uint16_t i=0; i<9999; i++) {   
    // Format the counter as a five-digit number with leading zeroes, followed by file extension
    snprintf(filename, 11, " %05d.wav", i);
    // Create if does not exist, do not open existing, write, sync after write
    if (!SD.exists(filename)) {
      break;
    }
  }
  frec = SD.open(filename, FILE_WRITE);
  Serial.println("Opened file !");
  if(frec) {
    Serial.print("Recording to ");
    Serial.println(filename);
    queue1.begin();
    mode = Mode::Recording; print_mode();
    recByteSaved = 0L;
  }
  else {
    Serial.println("Couldn't open file to record!");
  }
}

void continueRecording() {
#if defined(INSTRUMENT_SD_WRITE)
  uint32_t started = micros();
#endif // defined(INSTRUMENT_SD_WRITE)
#define NBLOX 16  
  // Check if there is data in the queue
  if (queue1.available() >= NBLOX) {
    byte buffer[NBLOX*AUDIO_BLOCK_SAMPLES*sizeof(int16_t)];
    // Fetch 2 blocks from the audio library and copy
    // into a 512 byte buffer.  The Arduino SD library
    // is most efficient when full 512 byte sector size
    // writes are used.
    for (int i=0;i<NBLOX;i++)
    {
      memcpy(buffer+i*AUDIO_BLOCK_SAMPLES*sizeof(int16_t), queue1.readBuffer(), AUDIO_BLOCK_SAMPLES*sizeof(int16_t));
      queue1.freeBuffer();
    }
    // Write all 512 bytes to the SD card
    frec.write(buffer, sizeof buffer);
    recByteSaved += sizeof buffer;
  }
  
#if defined(INSTRUMENT_SD_WRITE)
  started = micros() - started;
  if (started > worstSDwrite)
    worstSDwrite = started;

  if (millis() >= printNext)
  {
    Serial.printf("Worst write took %luus\n",worstSDwrite);
    worstSDwrite = 0;
    printNext = millis()+250;
  }
#endif // defined(INSTRUMENT_SD_WRITE)
}

void stopRecording() {
  // Stop adding any new data to the queue
  queue1.end();
  // Flush all existing remaining data from the queue
  while (queue1.available() > 0) {
    // Save to open file
    frec.write((byte*)queue1.readBuffer(), AUDIO_BLOCK_SAMPLES*sizeof(int16_t));
    queue1.freeBuffer();
    recByteSaved += AUDIO_BLOCK_SAMPLES*sizeof(int16_t);
  }
  writeOutHeader();
  // Close the file
  frec.close();
  Serial.println("Closed file");
  mode = Mode::Ready; print_mode();
  setMTPdeviceChecks(true); // enable MTP device checks, recording is finished
}


void playAllRecordings() {
  // Recording files are saved in the root directory
  File dir = SD.open("/");
  
  while (true) {
    File entry =  dir.openNextFile();
    if (strstr(entry.name(), "greeting"))
    {
       entry =  dir.openNextFile();
    }
    if (!entry) {
      // no more files
      entry.close();
      end_Beep();
      break;
    }
    //int8_t len = strlen(entry.name()) - 4;
//    if (strstr(strlwr(entry.name() + (len - 4)), ".raw")) {
//    if (strstr(strlwr(entry.name() + (len - 4)), ".wav")) {
    // the lines above throw a warning, so I replace them with this (which is also easier to read):
    if (strstr(entry.name(), ".wav") || strstr(entry.name(), ".WAV")) {
      Serial.print("Now playing ");
      Serial.println(entry.name());
      // Play a short beep before each message
      waveform1.amplitude(beep_volume);
      wait(750);
      waveform1.amplitude(0);
      // Play the file
      playWav1.play(entry.name());
      mode = Mode::Playing; print_mode();
    }
    entry.close();

//    while (playWav1.isPlaying()) { // strangely enough, this works for playRaw, but it does not work properly for playWav
    while (!playWav1.isStopped()) { // this works for playWav
      buttonPlay.update();
      buttonRecord.update();
      // Button is pressed again
//      if(buttonPlay.risingEdge() || buttonRecord.risingEdge()) { // FIX
      if(buttonPlay.fallingEdge() || buttonRecord.risingEdge()) { 
        playWav1.stop();
        mode = Mode::Ready; print_mode();
        return;
      }   
    }
  }
  // All files have been played
  mode = Mode::Ready; print_mode();
}

void playLastRecording() {
  // Find the first available file number
  uint16_t idx = 0; 
  for (uint16_t i=0; i<9999; i++) {
    // Format the counter as a five-digit number with leading zeroes, followed by file extension
    snprintf(filename, 11, " %05d.wav", i);
    // check, if file with index i exists
    if (!SD.exists(filename)) {
     idx = i - 1;
     break;
      }
  }
      // now play file with index idx == last recorded file
      snprintf(filename, 11, " %05d.wav", idx);
      Serial.println(filename);
      playWav1.play(filename);
      mode = Mode::Playing; print_mode();
      while (!playWav1.isStopped()) { // this works for playWav
      buttonPlay.update();
      buttonRecord.update();
      // Button is pressed again
//      if(buttonPlay.risingEdge() || buttonRecord.risingEdge()) { // FIX
      if(buttonPlay.fallingEdge() || buttonRecord.risingEdge()) {
        playWav1.stop();
        mode = Mode::Ready; print_mode();
        return;
      }   
    }
      // file has been played
  mode = Mode::Ready; print_mode();  
  end_Beep();
}


// Retrieve the current time from Teensy built-in RTC
time_t getTeensy3Time(){
  return Teensy3Clock.get();
}

// Callback to assign timestamps for file system operations
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {

  // Return date using FS_DATE macro to format fields.
  *date = FS_DATE(year(), month(), day());

  // Return time using FS_TIME macro to format fields.
  *time = FS_TIME(hour(), minute(), second());

  // Return low time bits in units of 10 ms.
  *ms10 = second() & 1 ? 100 : 0;
}

// Non-blocking delay, which pauses execution of main program logic,
// but while still listening for input 
void wait(unsigned int milliseconds) {
  elapsedMillis msec=0;

  while (msec <= milliseconds) {
    buttonRecord.update();
    buttonPlay.update();
    if (buttonRecord.fallingEdge()) Serial.println("Button (pin 0) Press");
    if (buttonPlay.fallingEdge()) Serial.println("Button (pin 1) Press");
    if (buttonRecord.risingEdge()) Serial.println("Button (pin 0) Release");
    if (buttonPlay.risingEdge()) Serial.println("Button (pin 1) Release");
  }
}


void writeOutHeader() { // update WAV header with final filesize/datasize

//  NumSamples = (recByteSaved*8)/bitsPerSample/numChannels;
//  Subchunk2Size = NumSamples*numChannels*bitsPerSample/8; // number of samples x number of channels x number of bytes per sample
  Subchunk2Size = recByteSaved - 42; // because we didn't make space for the header to start with! Lose 21 samples...
  ChunkSize = Subchunk2Size + 34; // was 36;
  frec.seek(0);
  frec.write("RIFF");
  byte1 = ChunkSize & 0xff;
  byte2 = (ChunkSize >> 8) & 0xff;
  byte3 = (ChunkSize >> 16) & 0xff;
  byte4 = (ChunkSize >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  frec.write("WAVE");
  frec.write("fmt ");
  byte1 = Subchunk1Size & 0xff;
  byte2 = (Subchunk1Size >> 8) & 0xff;
  byte3 = (Subchunk1Size >> 16) & 0xff;
  byte4 = (Subchunk1Size >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = AudioFormat & 0xff;
  byte2 = (AudioFormat >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = numChannels & 0xff;
  byte2 = (numChannels >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = sampleRate & 0xff;
  byte2 = (sampleRate >> 8) & 0xff;
  byte3 = (sampleRate >> 16) & 0xff;
  byte4 = (sampleRate >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = byteRate & 0xff;
  byte2 = (byteRate >> 8) & 0xff;
  byte3 = (byteRate >> 16) & 0xff;
  byte4 = (byteRate >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = blockAlign & 0xff;
  byte2 = (blockAlign >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = bitsPerSample & 0xff;
  byte2 = (bitsPerSample >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  frec.write("data");
  byte1 = Subchunk2Size & 0xff;
  byte2 = (Subchunk2Size >> 8) & 0xff;
  byte3 = (Subchunk2Size >> 16) & 0xff;
  byte4 = (Subchunk2Size >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  frec.close();
  Serial.println("header written"); 
  Serial.print("Subchunk2: "); 
  Serial.println(Subchunk2Size); 
}

void end_Beep(void) {
          waveform1.frequency(523.25);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
        wait(250);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
        wait(250);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
        wait(250);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
}

void print_mode(void) { // only for debugging
  Serial.print("Mode switched to: ");
  // Initialising, Ready, Prompting, Recording, Playing
  if(mode == Mode::Ready)           Serial.println(" Ready");
  else if(mode == Mode::Prompting)  Serial.println(" Prompting");
  else if(mode == Mode::Recording)  Serial.println(" Recording");
  else if(mode == Mode::Playing)    Serial.println(" Playing");
  else if(mode == Mode::Initialising)  Serial.println(" Initialising");
  else Serial.println(" Undefined");
}
 
Doesn't look like you have quite the latest source code, though it might be the latest from playful(-but-we-don't-bother-with-ongoing-support-for-our-)technology ... I wrote that out loud, didn't I? Oops... Try this: https://github.com/h4yn0nnym0u5e/audio-guestbook/tree/feature/doc-01; it has slightly easier to find volume settings, e.g. for microphone gain. Having said that, if you're getting different performance on two supposedly identical pieces of hardware, I'd be looking for an assembly error, or maybe a faulty microphone.

I don't use Arduino 2 routinely, and having just given it a try, that can's getting kicked further down the road. For me, the additional menu option is only working for Teensy 4.0... Try Arduino 1.8.19 - you can do a "portable" installation if you want to keep stuff entirely separate from your main installation.

Yes, the "ticking" should be much reduced if you use the Teensy 4.1's built-in SD card slot. The ticks are probably there on the louder phone, but you don't hear them because you don't have to boost the resulting file as much.
 
Doesn't look like you have quite the latest source code, though it might be the latest from playful(-but-we-don't-bother-with-ongoing-support-for-our-)technology ... I wrote that out loud, didn't I? Oops... Try this: https://github.com/h4yn0nnym0u5e/audio-guestbook/tree/feature/doc-01; it has slightly easier to find volume settings, e.g. for microphone gain. Having said that, if you're getting different performance on two supposedly identical pieces of hardware, I'd be looking for an assembly error, or maybe a faulty microphone.

I don't use Arduino 2 routinely, and having just given it a try, that can's getting kicked further down the road. For me, the additional menu option is only working for Teensy 4.0... Try Arduino 1.8.19 - you can do a "portable" installation if you want to keep stuff entirely separate from your main installation.

Yes, the "ticking" should be much reduced if you use the Teensy 4.1's built-in SD card slot. The ticks are probably there on the louder phone, but you don't hear them because you don't have to boost the resulting file as much.
Amazing. Thanks for the advice and suggestions.
Also, the previous version I used (from about a year ago(?)) was great, this latest firmware code is astounding. I’m so impressed with the improvements that have been made - it’s incredible! Thank you for all the hard work.
 
Doesn't look like you have quite the latest source code, though it might be the latest from playful(-but-we-don't-bother-with-ongoing-support-for-our-)technology ... I wrote that out loud, didn't I? Oops... Try this: https://github.com/h4yn0nnym0u5e/audio-guestbook/tree/feature/doc-01; it has slightly easier to find volume settings, e.g. for microphone gain. Having said that, if you're getting different performance on two supposedly identical pieces of hardware, I'd be looking for an assembly error, or maybe a faulty microphone.

I don't use Arduino 2 routinely, and having just given it a try, that can's getting kicked further down the road. For me, the additional menu option is only working for Teensy 4.0... Try Arduino 1.8.19 - you can do a "portable" installation if you want to keep stuff entirely separate from your main installation.

Yes, the "ticking" should be much reduced if you use the Teensy 4.1's built-in SD card slot. The ticks are probably there on the louder phone, but you don't hear them because you don't have to boost the resulting file as much.

Sorry to bother. But any idea why the greetings might not be playing?
They’re called greeting.wav and 16bit pcm signed?
 
Usually it’s caused by the WAV file not being quite to the specification the AudioPlaySdWav object expects. It’s more picky than most PCs… If you zip it up and attach it to a post we can probably figure out what’s wrong. Or just record your greeting on the phone, play it back to check, then rename it - obviously you’ll need to delete or rename the duff one first!
 
Usually it’s caused by the WAV file not being quite to the specification the AudioPlaySdWav object expects. It’s more picky than most PCs… If you zip it up and attach it to a post we can probably figure out what’s wrong. Or just record your greeting on the phone, play it back to check, then rename it - obviously you’ll need to delete or rename the duff one first!

Thanks. I’ll try and get something. I’ll try the renaming first. It’s very odd… not sure why it’s not working suddenly. Previously used audacity to edit .raw to .wav now I’m going from .mp3 to .wav and it’s not working. Weird.

What is PCs? Personal computer? Or a package?
 
What is PCs? Personal computer? Or a package?

Personal computers. There were various duff WAV files earlier in this thread, and it was quite interesting (if you’re interested in that sort of thing…) how most applications would play them without complaining. Goldwave would complain, but could usually still play them anyway.
 
Personal computers. There were various duff WAV files earlier in this thread, and it was quite interesting (if you’re interested in that sort of thing…) how most applications would play them without complaining. Goldwave would complain, but could usually still play them anyway.
So the best thing to rectify is to keep trying different files? Audacity still a good program to do this with?
 
Trying a bunch of different stuff until you find something that works is rarely the best way of solving a problem.

Truly the best is to get a hex editor, open the offending file, compare it to what a WAV file should look like (lots of resources on the web, e.g. http://soundfile.sapp.org/doc/WaveFormat/), and persuade Audacity not to do that. Audacity is good, but in a way it's too powerful - it can do the right thing, and a huge number of things that are also right, but wrong in your specific situation.
 
Wiring diagram - mic and speaker sharing ground. I'd like to use the original cord from my phone to headset. There are only three wires. Mic, speaker, ground (shared).
The audio shield has a warning:
"Caution: do not short VGND to GND"

Any tips on wiring into audio shield so ground can be shared?
 
And it is a warning that must be heeded. IMHO Freescale / NXP did no-one any favours by including the letter sequence "GND" in the pin name. It isn't a ground, it's a mid-rail power supply acting as a common connection to floating drivers such as headphones, with the drive signals then swinging to voltages above and below it. But a ground it ain't.

As you only have the three wires, you'll need a small power amplifier which can use the system ground as its ground, and use an audio line-out as its input. The amplifier doesn't need much power, it only takes a few milliwatts to get enough signal for an earpiece: the SGTL headphone driver can manage 22mW, according to the datasheet. You may also need to tweak the software, as it only sets the headphone volume, not the line out level. Look for the lineOutLevel() command for the AudioControlSGTL5000 object in the Design Tool. If you can't get the level low enough, you may need a resistive divider network to lower the level further. Unless your selected amplifier has a way to do it, of course.

Do check the specification of your selected amplifier carefully, to make sure it doesn't have the same gotcha that the audio adaptor headphones output has...
 
IMHO Freescale / NXP did no-one any favours by including the letter sequence "GND" in the pin name. It isn't a ground,

Its a virtual ground called HP_VGND and "headphone virtual ground" in the datasheet and there's a very stark warning about not connecting it to GND ever.
How much more clear could they have been?
 
I just started the software portion of the Guestbook today and have had a hard time figuring out the correct steps for downloading the various IDEs, libraries. Etc. I was hoping to start with the November 4th Guestbook.ino file at https://github.com/playfultechnology/audio-guestbook. I note thatt most of you are using the older *.ino files and previous revs of the IDE.

Wedding is in 2 weeks. My phone is built and I started downloading software today and have worked through a lot of "Verify" errors. Here is as far as I have gotten with 2.2.2 and the November 4th *.ino file.

MWG_WV Audio Guestbook3 Verify Errors – unaltered Guestbook.ino – tweaked MTP_Teensy.h for Serial and change of MTP to CDC per compiler
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `usb_serial_class::write(unsigned char const*,
unsigned int)':
C:\Users\15712\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\cores\teensy4/usb_serial.h:116: undefined reference to `MTP'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `setup':
C:\Users\15712\Documents\Arduino\Day2_Guestbook2\Day2_Guestbook2/Day2_Guestbook2.ino:140: undefined reference to `MTP_class::begin()'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `MTP_class::addFilesystem(SDClass&, char
const*)':
C:\Users\15712\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\libraries\MTP_Teensy\src/MTP_Teensy.h:80: undefined reference to `MTP_class::addFilesystem(FS&, char const*,
mtp_fstype_t)'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `setup':
C:\Users\15712\Documents\Arduino\Day2_Guestbook2\Day2_Guestbook2/Day2_Guestbook2.ino:160: undefined reference to `MTP'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\Documents\Arduino\Day2_Guestbook2\Day2_Guestbook2/Day2_Guestbook2.ino:160: undefined reference to `MTP_class::printStream_'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `File::dec_refcount()':
C:\Users\15712\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\cores\teensy4/FS.h:260: undefined reference to `MTP'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `AudioSynthWaveform::amplitude(float)':
C:\Users\15712\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\libraries\Audio/synth_waveform.h:131: undefined reference to `MTP'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `loop':
C:\Users\15712\Documents\Arduino\Day2_Guestbook2\Day2_Guestbook2/Day2_Guestbook2.ino:238: undefined reference to `MTP_class::loop()'
MWG_WV Audio Guestbook3 Verify Errors – unaltered Guestbook.ino – tweaked MTP_Teensy.h for Serial and change of MTP to CDC per compiler
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `usb_serial_class::write(unsigned char const*,
unsigned int)':
C:\Users\15712\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\cores\teensy4/usb_serial.h:116: undefined reference to `MTP'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `setup':
C:\Users\15712\Documents\Arduino\Day2_Guestbook2\Day2_Guestbook2/Day2_Guestbook2.ino:140: undefined reference to `MTP_class::begin()'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `MTP_class::addFilesystem(SDClass&, char
const*)':
C:\Users\15712\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\libraries\MTP_Teensy\src/MTP_Teensy.h:80: undefined reference to `MTP_class::addFilesystem(FS&, char const*,
mtp_fstype_t)'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `setup':
C:\Users\15712\Documents\Arduino\Day2_Guestbook2\Day2_Guestbook2/Day2_Guestbook2.ino:160: undefined reference to `MTP'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\Documents\Arduino\Day2_Guestbook2\Day2_Guestbook2/Day2_Guestbook2.ino:160: undefined reference to `MTP_class::printStream_'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `File::dec_refcount()':
C:\Users\15712\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\cores\teensy4/FS.h:260: undefined reference to `MTP'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `AudioSynthWaveform::amplitude(float)':
C:\Users\15712\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.58.1\libraries\Audio/synth_waveform.h:131: undefined reference to `MTP'
c:/users/15712/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe:
C:\Users\15712\AppData\Local\Temp\arduino\sketches\BF883229AF80E8B9F4E70E550D5E309D\sketch\Day2_Guestbook2.ino.cpp.o: in func0on `loop':
C:\Users\15712\Documents\Arduino\Day2_Guestbook2\Day2_Guestbook2/Day2_Guestbook2.ino:238: undefined reference to `MTP_class::loop()'
 
This line worries me:
Code:
MWG_WV Audio Guestbook3 Verify Errors – unaltered Guestbook.ino – [B]tweaked MTP_Teensy.h for Serial and change of MTP to CDC per compiler[/B]
You shouldn't have to tweak anything, if you installed MTP_Teensy correctly and have Serial + MTP Disk (experimental) selected on the Tools menu. It appears you do have MTP_Teensy visible because it's showing up in the error messages (please learn to use the code tag for this sort of thing, though, i.e. the # button above the message edit box). So it looks like your tweaking has caused a link error.

I'd recommend using Arduino 1.8.19 for this project (not sure where you got 2.2.2, at time of writing 2.2.1 seems to be the latest Arduino IDE), there have been a few gremlins noted in previous posts, and things like " in func0on `setup'" don't fill me with confidence that you have an uncorrupted installation anyway. You can do a "portable" install of 1.8.19 to prevent it polluting any other projects you may have.
 
Will reload all and try again.

This line worries me:
Code:
MWG_WV Audio Guestbook3 Verify Errors – unaltered Guestbook.ino – [B]tweaked MTP_Teensy.h for Serial and change of MTP to CDC per compiler[/B]
You shouldn't have to tweak anything, if you installed MTP_Teensy correctly and have Serial + MTP Disk (experimental) selected on the Tools menu. It appears you do have MTP_Teensy visible because it's showing up in the error messages (please learn to use the code tag for this sort of thing, though, i.e. the # button above the message edit box). So it looks like your tweaking has caused a link error.

I'd recommend using Arduino 1.8.19 for this project (not sure where you got 2.2.2, at time of writing 2.2.1 seems to be the latest Arduino IDE), there have been a few gremlins noted in previous posts, and things like " in func0on `setup'" don't fill me with confidence that you have an uncorrupted installation anyway. You can do a "portable" install of 1.8.19 to prevent it polluting any other projects you may have.

I stand corrected, it is 2.2.1 Thanks for the suggestions. I will save some of my files and uninstall everything and reinstall 1.8.19 only. I am not sure how I did not get MTP_Teensy in any of the "main" downloads and Board Manager URL updates. If I run into the same problem again tonight I will post more specific questions and, likely, my tweaks of MTP_Teensy.h for QA/QC of my changes.
 
You have to download MTP_Teensy as a separate library - various posts on this thread should help you do this. It’s not part of either the Arduino IDE or standard Teensyduino.
 
Thanks for the links and lesson in structure for the various folders. As mentioned above I deleted everything and started over by downloading the 1.8.x zip files.

The IDE program is now in C:/Arduino/.arduino-1.8.19.
Guestbooks are in Documents/Arduino/Audio-Guestbooks folder.
MTP_Teensy is unpackaged in Documents/Arduino/libraries folder (it is the only subfolder there).

Arduino and Teensy uploaded automatically files (8,895 of them) are all in a User/AppData/Local/Arduino15 folder with a packages/teensy/hardware/avr/1.58.1 folder
Boards.local.txt and Platform.txt files are in both the C:/Aurduino/Arduino-1.8.19/hardware/arduino and User/AppData/Local/Arduino15/packages/teensy/hardare/avr folders.

I opened the unaltered version of the most recently posted audio-guestbook.ino dated 8/9/23 8:34 AM. play_sd_wav.cpp and play_sd_wav.h came up with it automatically.
In the "Tools" menu I set the board to my Teensy 4.0 and USB Type to: Serial + MTP (Experimental) and set CPU Speed to 150 as suggested per a post to preserve battery.

My dropdown in Tools did not include the menu item for Audio Blocks mentioned in the Readme for the 8/9/23 version of the file.

I ran the "Verify" and Immediately got the error below.

Arduino: 1.8.19 (Windows 10), Board: "Teensy 4.0, Serial + MTP Disk (Experimental), 150 MHz, Faster, US English"

Error resolving FQBN: getting

Error compiling for board Teensy 4.0.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Any guidance would be appreciated. I thought I did everything correctly and made no changes to the *.ino file .
Code:
/**
 * Audio Guestbook, Copyright (c) 2022 Playful Technology
 * 
 * Tested using a Teensy 4.0 with Teensy Audio Shield, although should work 
 * with minor modifications on other similar hardware
 * 
 * When handset is lifted, a pre-recorded greeting message is played, followed by a tone.
 * Then, recording starts, and continues until the handset is replaced.
 * Playback button allows all messages currently saved on SD card through earpiece 
 * 
 * Files are saved on SD card as 44.1kHz, 16-bit, mono signed integer RAW audio format 
 * --> changed this to WAV recording, DD4WH 2022_07_31
 * --> added MTP support, which enables copying WAV files from the SD card via the USB connection, DD4WH 2022_08_01
 * 
 * 
 * Frank DD4WH, August 1st 2022 
 * for a DBP 611 telephone (closed contact when handheld is lifted) & with recording to WAV file
 * contact for switch button 0 is closed when handheld is lifted
 * 
 * GNU GPL v3.0 license
 * 
 */

#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <TimeLib.h>
#include <MTP_Teensy.h>
#include "play_sd_wav.h" // local copy with fixes

// DEFINES
// Define pins used by Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

// And those used for inputs
#define HOOK_PIN 0
#define PLAYBACK_BUTTON_PIN 1

#define MAX_RECORDING_TIME_MS 120'000 // limit recordings to this long (milliseconds)

#define noINSTRUMENT_SD_WRITE

// GLOBALS
// Audio initialisation code can be generated using the GUI interface at https://www.pjrc.com/teensy/gui/
// Inputs
AudioSynthWaveform          waveform1; // To create the "beep" sfx
AudioInputI2S               i2s2; // I2S input from microphone on audio shield
AudioPlaySdWavX              playGreeting; // Play 44.1kHz 16-bit PCM greeting WAV file
AudioPlaySdWavX              playMessage;  // Play 44.1kHz 16-bit PCM message WAV file
AudioRecordQueue            queue1; // Creating an audio buffer in memory before saving to SD
AudioMixer4                 mixer; // Allows merging several inputs to same output
AudioOutputI2S              i2s1; // I2S interface to Speaker/Line Out on Audio shield
AudioConnection patchCord1(waveform1, 0, mixer, 0); // wave to mixer 
AudioConnection patchCord2(playGreeting, 0, mixer, 1); // greeting file playback mixer
AudioConnection patchCord3(playMessage, 0, mixer, 2); // message file playback mixer
AudioConnection patchCord4(mixer, 0, i2s1, 0); // mixer output to speaker (L)
AudioConnection patchCord6(mixer, 0, i2s1, 1); // mixer output to speaker (R)
AudioConnection patchCord5(i2s2, 0, queue1, 0); // mic input to queue (L)
AudioControlSGTL5000      sgtl5000_1;

// Filename to save audio recording on SD card
char filename[15];
// The file object itself
File frec;

// Use long 40ms debounce time on both switches
Bounce buttonRecord = Bounce(HOOK_PIN, 40);
Bounce buttonPlay = Bounce(PLAYBACK_BUTTON_PIN, 40);

// Keep track of current state of the device
enum Mode {Initialising, Ready, Prompting, Recording, Playing};
Mode mode = Mode::Initialising;
elapsedMillis theTimer; // used to time out long messages

float beep_volume = 0.4f; // not too loud :-)

uint32_t MTPcheckInterval; // default value of device check interval [ms]

// variables for writing to WAV file
unsigned long ChunkSize = 0L;
unsigned long Subchunk1Size = 16;
unsigned int AudioFormat = 1;
unsigned int numChannels = 1;
unsigned long sampleRate = 44100;
unsigned int bitsPerSample = 16;
unsigned long byteRate = sampleRate*numChannels*(bitsPerSample/8);// samplerate x channels x (bitspersample / 8)
unsigned int blockAlign = numChannels*bitsPerSample/8;
unsigned long Subchunk2Size = 0L;
unsigned long recByteSaved = 0L;
unsigned long NumSamples = 0L;
byte byte1, byte2, byte3, byte4;


void setup() {

  Serial.begin(9600);
  while (!Serial && millis() < 5000) {
    // wait for serial port to connect.
  }
  Serial.println("Serial set up correctly");
  Serial.printf("Audio block set to %d samples\n",AUDIO_BLOCK_SAMPLES);
  print_mode();
  // Configure the input pins
  pinMode(HOOK_PIN, INPUT_PULLUP);
  pinMode(PLAYBACK_BUTTON_PIN, INPUT_PULLUP);

  // Audio connections require memory, and the record queue
  // uses this memory to buffer incoming audio.
  AudioMemory(60);

  // Enable the audio shield, select input, and enable output
  sgtl5000_1.enable();
  // Define which input on the audio shield to use (AUDIO_INPUT_LINEIN / AUDIO_INPUT_MIC)
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  //sgtl5000_1.adcHighPassFilterDisable(); //

  // ----- Level settings -----
  sgtl5000_1.micGain(39); // set to suit your microphone
  sgtl5000_1.audioPreProcessorEnable(); // optional: could be a good plan...
  sgtl5000_1.autoVolumeEnable();        // ...to prevent shouty people overloading the file
  sgtl5000_1.volume(0.5); // overall speaker volume

  mixer.gain(0, 0.1f); // beeps
  mixer.gain(1, 0.5f); // greeting
  mixer.gain(2, 1.0f); // message playback
  // --------------------------

  // Play a beep to indicate system is online
  waveform1.begin(beep_volume, 440, WAVEFORM_SINE);
  wait(1000);
  waveform1.amplitude(0);
  delay(1000);

  // Initialize the SD card
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) 
  {
    // stop here if no SD card, but print a message
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
    else Serial.println("SD card correctly initialized");


  // mandatory to begin the MTP session.
    MTP.begin();

  // Add SD Card
//    MTP.addFilesystem(SD, "SD Card");
    MTP.addFilesystem(SD, "Kais Audio guestbook"); // choose a nice name for the SD card volume to appear in your file explorer
    Serial.println("Added SD card via MTP");
    MTPcheckInterval = MTP.storage()->get_DeltaDeviceCheckTimeMS();
    
    // Value in dB
//  sgtl5000_1.micGain(15);
//  sgtl5000_1.micGain(5); // much lower gain is required for the AOM5024 electret capsule

  // Synchronise the Time object used in the program code with the RTC time provider.
  // See https://github.com/PaulStoffregen/Time
  setSyncProvider(getTeensy3Time);
  
  // Define a callback that will assign the correct datetime for any file system operations
  // (i.e. saving a new audio recording onto the SD card)
  FsDateTime::setCallback(dateTime);

  mode = Mode::Ready; print_mode();
}

void loop() {
  // First, read the buttons
  buttonRecord.update();
  buttonPlay.update();

  switch(mode){
    case Mode::Ready:
      // Falling edge occurs when the handset is lifted --> 611 telephone
      if (buttonRecord.fallingEdge()) {
        Serial.println("Handset lifted");
        mode = Mode::Prompting; print_mode();
      }
      else if(buttonPlay.fallingEdge()) {
        //playAllRecordings();
        playLastRecording();
      }
      break;

    case Mode::Prompting:
      // Wait a second for users to put the handset to their ear
      wait(1000);
      // Play the greeting inviting them to record their message
      playGreeting.play("greeting.wav");    
      // Wait until the  message has finished playing
//      while (playGreeting.isPlaying()) {
      while (!playGreeting.isStopped()) {
        // Check whether the handset is replaced
        buttonRecord.update();
        buttonPlay.update();
        // Handset is replaced
        if (buttonRecord.read()) { // wait() may have lost edge - use the level instead
          playGreeting.stop();
          mode = Mode::Ready; print_mode();
          return;
        }
        if(buttonPlay.fallingEdge()) {
          playGreeting.stop();
          //playAllRecordings();
          playLastRecording();
          return;
        }
        
      }
      // Debug message
      Serial.println("Starting Recording");
      // Play the tone sound effect
      waveform1.begin(beep_volume, 440, WAVEFORM_SINE);
      wait(1250);
      waveform1.amplitude(0);
      // Start the recording function
      startRecording();
      theTimer = 0;
      break;

    case Mode::Recording:
      // Handset is replaced
      if ( buttonRecord.risingEdge()
        || theTimer >= MAX_RECORDING_TIME_MS) // ...or has been off-hook too long)
      {
        // Debug log
        Serial.println("Stopping Recording");
        // Stop recording
        stopRecording();
        // Play audio tone to confirm recording has ended
        end_Beep();
      }
      else {
        continueRecording();
      }
      break;

    case Mode::Playing: // to make compiler happy
      break;  

    case Mode::Initialising: // to make compiler happy
      break;  
  }   
  
  MTP.loop();  // This is mandatory to be placed in the loop code.
}

void setMTPdeviceChecks(bool nable)
{
  if (nable)
  {
    MTP.storage()->set_DeltaDeviceCheckTimeMS(MTPcheckInterval);
    Serial.print("En");
  }
  else
  {
    MTP.storage()->set_DeltaDeviceCheckTimeMS((uint32_t) -1);
    Serial.print("Dis");
  }
  Serial.println("abled MTP storage device checks");
}
  

#if defined(INSTRUMENT_SD_WRITE)
static uint32_t worstSDwrite, printNext;
#endif // defined(INSTRUMENT_SD_WRITE)

void startRecording() {
  setMTPdeviceChecks(false); // disable MTP device checks while recording
#if defined(INSTRUMENT_SD_WRITE)
  worstSDwrite = 0;
  printNext = 0;
#endif // defined(INSTRUMENT_SD_WRITE)
  // Find the first available file number
//  for (uint8_t i=0; i<9999; i++) { // BUGFIX uint8_t overflows if it reaches 255  
  for (uint16_t i=0; i<9999; i++) {   
    // Format the counter as a five-digit number with leading zeroes, followed by file extension
    snprintf(filename, 11, " %05d.wav", i);
    // Create if does not exist, do not open existing, write, sync after write
    if (!SD.exists(filename)) {
      break;
    }
  }
  frec = SD.open(filename, FILE_WRITE);
  Serial.println("Opened file !");
  if(frec) {
    Serial.print("Recording to ");
    Serial.println(filename);
    queue1.begin();
    mode = Mode::Recording; print_mode();
    recByteSaved = 0L;
  }
  else {
    Serial.println("Couldn't open file to record!");
  }
}

void continueRecording() {
#if defined(INSTRUMENT_SD_WRITE)
  uint32_t started = micros();
#endif // defined(INSTRUMENT_SD_WRITE)
#define NBLOX 16  
  // Check if there is data in the queue
  if (queue1.available() >= NBLOX) {
    byte buffer[NBLOX*AUDIO_BLOCK_SAMPLES*sizeof(int16_t)];
    // Fetch 2 blocks from the audio library and copy
    // into a 512 byte buffer.  The Arduino SD library
    // is most efficient when full 512 byte sector size
    // writes are used.
    for (int i=0;i<NBLOX;i++)
    {
      memcpy(buffer+i*AUDIO_BLOCK_SAMPLES*sizeof(int16_t), queue1.readBuffer(), AUDIO_BLOCK_SAMPLES*sizeof(int16_t));
      queue1.freeBuffer();
    }
    // Write all 512 bytes to the SD card
    frec.write(buffer, sizeof buffer);
    recByteSaved += sizeof buffer;
  }
  
#if defined(INSTRUMENT_SD_WRITE)
  started = micros() - started;
  if (started > worstSDwrite)
    worstSDwrite = started;

  if (millis() >= printNext)
  {
    Serial.printf("Worst write took %luus\n",worstSDwrite);
    worstSDwrite = 0;
    printNext = millis()+250;
  }
#endif // defined(INSTRUMENT_SD_WRITE)
}

void stopRecording() {
  // Stop adding any new data to the queue
  queue1.end();
  // Flush all existing remaining data from the queue
  while (queue1.available() > 0) {
    // Save to open file
    frec.write((byte*)queue1.readBuffer(), AUDIO_BLOCK_SAMPLES*sizeof(int16_t));
    queue1.freeBuffer();
    recByteSaved += AUDIO_BLOCK_SAMPLES*sizeof(int16_t);
  }
  writeOutHeader();
  // Close the file
  frec.close();
  Serial.println("Closed file");
  mode = Mode::Ready; print_mode();
  setMTPdeviceChecks(true); // enable MTP device checks, recording is finished
}


void playAllRecordings() {
  // Recording files are saved in the root directory
  File dir = SD.open("/");
  
  while (true) {
    File entry =  dir.openNextFile();
    if (strstr(entry.name(), "greeting"))
    {
       entry =  dir.openNextFile();
    }
    if (!entry) {
      // no more files
      entry.close();
      end_Beep();
      break;
    }
    //int8_t len = strlen(entry.name()) - 4;
//    if (strstr(strlwr(entry.name() + (len - 4)), ".raw")) {
//    if (strstr(strlwr(entry.name() + (len - 4)), ".wav")) {
    // the lines above throw a warning, so I replace them with this (which is also easier to read):
    if (strstr(entry.name(), ".wav") || strstr(entry.name(), ".WAV")) {
      Serial.print("Now playing ");
      Serial.println(entry.name());
      // Play a short beep before each message
      waveform1.amplitude(beep_volume);
      wait(750);
      waveform1.amplitude(0);
      // Play the file
      playMessage.play(entry.name());
      mode = Mode::Playing; print_mode();
    }
    entry.close();

//    while (playWav1.isPlaying()) { // strangely enough, this works for playRaw, but it does not work properly for playWav
    while (!playMessage.isStopped()) { // this works for playWav
      buttonPlay.update();
      buttonRecord.update();
      // Button is pressed again
//      if(buttonPlay.risingEdge() || buttonRecord.risingEdge()) { // FIX
      if(buttonPlay.fallingEdge() || buttonRecord.risingEdge()) { 
        playMessage.stop();
        mode = Mode::Ready; print_mode();
        return;
      }   
    }
  }
  // All files have been played
  mode = Mode::Ready; print_mode();
}

void playLastRecording() {
  // Find the first available file number
  uint16_t idx = 0; 
  for (uint16_t i=0; i<9999; i++) {
    // Format the counter as a five-digit number with leading zeroes, followed by file extension
    snprintf(filename, 11, " %05d.wav", i);
    // check, if file with index i exists
    if (!SD.exists(filename)) {
     idx = i - 1;
     break;
      }
  }
      // now play file with index idx == last recorded file
      snprintf(filename, 11, " %05d.wav", idx);
      Serial.println(filename);
      playMessage.play(filename);
      mode = Mode::Playing; print_mode();
      while (!playMessage.isStopped()) { // this works for playWav
      buttonPlay.update();
      buttonRecord.update();
      // Button is pressed again
//      if(buttonPlay.risingEdge() || buttonRecord.risingEdge()) { // FIX
      if(buttonPlay.fallingEdge() || buttonRecord.risingEdge()) {
        playMessage.stop();
        mode = Mode::Ready; print_mode();
        return;
      }   
    }
      // file has been played
  mode = Mode::Ready; print_mode();  
  end_Beep();
}


// Retrieve the current time from Teensy built-in RTC
time_t getTeensy3Time(){
  return Teensy3Clock.get();
}

// Callback to assign timestamps for file system operations
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {

  // Return date using FS_DATE macro to format fields.
  *date = FS_DATE(year(), month(), day());

  // Return time using FS_TIME macro to format fields.
  *time = FS_TIME(hour(), minute(), second());

  // Return low time bits in units of 10 ms.
  *ms10 = second() & 1 ? 100 : 0;
}

// Non-blocking delay, which pauses execution of main program logic,
// but while still listening for input 
void wait(unsigned int milliseconds) {
  elapsedMillis msec=0;

  while (msec <= milliseconds) {
    buttonRecord.update();
    buttonPlay.update();
    if (buttonRecord.fallingEdge()) Serial.println("Button (pin 0) Press");
    if (buttonPlay.fallingEdge()) Serial.println("Button (pin 1) Press");
    if (buttonRecord.risingEdge()) Serial.println("Button (pin 0) Release");
    if (buttonPlay.risingEdge()) Serial.println("Button (pin 1) Release");
  }
}


void writeOutHeader() { // update WAV header with final filesize/datasize

//  NumSamples = (recByteSaved*8)/bitsPerSample/numChannels;
//  Subchunk2Size = NumSamples*numChannels*bitsPerSample/8; // number of samples x number of channels x number of bytes per sample
  Subchunk2Size = recByteSaved - 42; // because we didn't make space for the header to start with! Lose 21 samples...
  ChunkSize = Subchunk2Size + 34; // was 36;
  frec.seek(0);
  frec.write("RIFF");
  byte1 = ChunkSize & 0xff;
  byte2 = (ChunkSize >> 8) & 0xff;
  byte3 = (ChunkSize >> 16) & 0xff;
  byte4 = (ChunkSize >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  frec.write("WAVE");
  frec.write("fmt ");
  byte1 = Subchunk1Size & 0xff;
  byte2 = (Subchunk1Size >> 8) & 0xff;
  byte3 = (Subchunk1Size >> 16) & 0xff;
  byte4 = (Subchunk1Size >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = AudioFormat & 0xff;
  byte2 = (AudioFormat >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = numChannels & 0xff;
  byte2 = (numChannels >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = sampleRate & 0xff;
  byte2 = (sampleRate >> 8) & 0xff;
  byte3 = (sampleRate >> 16) & 0xff;
  byte4 = (sampleRate >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = byteRate & 0xff;
  byte2 = (byteRate >> 8) & 0xff;
  byte3 = (byteRate >> 16) & 0xff;
  byte4 = (byteRate >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = blockAlign & 0xff;
  byte2 = (blockAlign >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = bitsPerSample & 0xff;
  byte2 = (bitsPerSample >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  frec.write("data");
  byte1 = Subchunk2Size & 0xff;
  byte2 = (Subchunk2Size >> 8) & 0xff;
  byte3 = (Subchunk2Size >> 16) & 0xff;
  byte4 = (Subchunk2Size >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  frec.close();
  Serial.println("header written"); 
  Serial.print("Subchunk2: "); 
  Serial.println(Subchunk2Size); 
}

void end_Beep(void) {
          waveform1.frequency(523.25);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
        wait(250);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
        wait(250);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
        wait(250);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
}

void print_mode(void) { // only for debugging
  Serial.print("Mode switched to: ");
  // Initialising, Ready, Prompting, Recording, Playing
  if(mode == Mode::Ready)           Serial.println(" Ready");
  else if(mode == Mode::Prompting)  Serial.println(" Prompting");
  else if(mode == Mode::Recording)  Serial.println(" Recording");
  else if(mode == Mode::Playing)    Serial.println(" Playing");
  else if(mode == Mode::Initialising)  Serial.println(" Initialising");
  else Serial.println(" Undefined");
}
 
Can you turn on the "Show verbose output" checkbox and post the result (in code tags again)?
2023-09-12 21_28_41-AudioPatcher _ Arduino 1.8.19.png
That "FQBN" looks like lingering Arduino 2 stuff, as does still having things in your appdata/local, but I'm not sure. I've avoided installing both IDE versions on one PC, which is increasingly looking like an excellent decision, but also means I can't be much help at disentangling the resulting issues.
 
In response to #422 above I went to File/Preferences and checked the Verbose when compiling box and got the error message below.


C:\Arduino\arduino-1.8.19\arduino-builder -dump-prefs -logger=machine -hardware C:\Arduino\arduino-1.8.19\hardware -hardware C:\Users\15712\AppData\Local\Arduino15\packages -tools C:\Arduino\arduino-1.8.19\tools-builder -tools C:\Arduino\arduino-1.8.19\hardware\tools\avr -tools C:\Users\15712\AppData\Local\Arduino15\packages -built-in-libraries C:\Arduino\arduino-1.8.19\libraries -libraries C:\Users\15712\Documents\Arduino\libraries -fqbn=teensy:avr:teensy40:usb=serialmtp,speed=150,opt=o2std,keys=en-us -ide-version=10819 -build-path C:\Users\15712\AppData\Local\Temp\arduino_build_88555 -warnings=none -build-cache C:\Users\15712\AppData\Local\Temp\arduino_cache_591103 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.teensy-compile.path=C:\Users\15712\AppData\Local\Arduino15\packages\teensy\tools\teensy-compile\11.3.1 -prefs=runtime.tools.teensy-compile-11.3.1.path=C:\Users\15712\AppData\Local\Arduino15\packages\teensy\tools\teensy-compile\11.3.1 -prefs=runtime.tools.teensy-tools.path=C:\Users\15712\AppData\Local\Arduino15\packages\teensy\tools\teensy-tools\1.58.0 -prefs=runtime.tools.teensy-tools-1.58.0.path=C:\Users\15712\AppData\Local\Arduino15\packages\teensy\tools\teensy-tools\1.58.0 -verbose C:\Users\15712\Documents\Arduino\Audio-Guestbooks\audio-guestbook\audio-guestbook.ino

Error resolving FQBN: getting

Error compiling for board Teensy 4.0.

Tried selecting Teensy 4.1 (thinking, perhaps, that some extra Pins not on the 4.0 might be buried somewhere) but got the same error string except ending with "4.1."

I will try one more time tonight (it is 8:50 PM here in the EST of the American Colonies) to uninstall everthing in all of the different directories and reload the 1.8.19 zip file and the https://github.com/h4yn0nnym0u5e/audio-guestbook/tree/feature/doc-01 zip file from August 9th. The MTP and Teensy stuff is still on a flash drive. Perhaps I will even try rebooting the PC.

Code:
/**
 * Audio Guestbook, Copyright (c) 2022 Playful Technology
 * 
 * Tested using a Teensy 4.0 with Teensy Audio Shield, although should work 
 * with minor modifications on other similar hardware
 * 
 * When handset is lifted, a pre-recorded greeting message is played, followed by a tone.
 * Then, recording starts, and continues until the handset is replaced.
 * Playback button allows all messages currently saved on SD card through earpiece 
 * 
 * Files are saved on SD card as 44.1kHz, 16-bit, mono signed integer RAW audio format 
 * --> changed this to WAV recording, DD4WH 2022_07_31
 * --> added MTP support, which enables copying WAV files from the SD card via the USB connection, DD4WH 2022_08_01
 * 
 * 
 * Frank DD4WH, August 1st 2022 
 * for a DBP 611 telephone (closed contact when handheld is lifted) & with recording to WAV file
 * contact for switch button 0 is closed when handheld is lifted
 * 
 * GNU GPL v3.0 license
 * 
 */

#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <TimeLib.h>
#include <MTP_Teensy.h>
#include "play_sd_wav.h" // local copy with fixes

// DEFINES
// Define pins used by Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

// And those used for inputs
#define HOOK_PIN 0
#define PLAYBACK_BUTTON_PIN 1

#define MAX_RECORDING_TIME_MS 120'000 // limit recordings to this long (milliseconds)

#define noINSTRUMENT_SD_WRITE

// GLOBALS
// Audio initialisation code can be generated using the GUI interface at https://www.pjrc.com/teensy/gui/
// Inputs
AudioSynthWaveform          waveform1; // To create the "beep" sfx
AudioInputI2S               i2s2; // I2S input from microphone on audio shield
AudioPlaySdWavX              playGreeting; // Play 44.1kHz 16-bit PCM greeting WAV file
AudioPlaySdWavX              playMessage;  // Play 44.1kHz 16-bit PCM message WAV file
AudioRecordQueue            queue1; // Creating an audio buffer in memory before saving to SD
AudioMixer4                 mixer; // Allows merging several inputs to same output
AudioOutputI2S              i2s1; // I2S interface to Speaker/Line Out on Audio shield
AudioConnection patchCord1(waveform1, 0, mixer, 0); // wave to mixer 
AudioConnection patchCord2(playGreeting, 0, mixer, 1); // greeting file playback mixer
AudioConnection patchCord3(playMessage, 0, mixer, 2); // message file playback mixer
AudioConnection patchCord4(mixer, 0, i2s1, 0); // mixer output to speaker (L)
AudioConnection patchCord6(mixer, 0, i2s1, 1); // mixer output to speaker (R)
AudioConnection patchCord5(i2s2, 0, queue1, 0); // mic input to queue (L)
AudioControlSGTL5000      sgtl5000_1;

// Filename to save audio recording on SD card
char filename[15];
// The file object itself
File frec;

// Use long 40ms debounce time on both switches
Bounce buttonRecord = Bounce(HOOK_PIN, 40);
Bounce buttonPlay = Bounce(PLAYBACK_BUTTON_PIN, 40);

// Keep track of current state of the device
enum Mode {Initialising, Ready, Prompting, Recording, Playing};
Mode mode = Mode::Initialising;
elapsedMillis theTimer; // used to time out long messages

float beep_volume = 0.4f; // not too loud :-)

uint32_t MTPcheckInterval; // default value of device check interval [ms]

// variables for writing to WAV file
unsigned long ChunkSize = 0L;
unsigned long Subchunk1Size = 16;
unsigned int AudioFormat = 1;
unsigned int numChannels = 1;
unsigned long sampleRate = 44100;
unsigned int bitsPerSample = 16;
unsigned long byteRate = sampleRate*numChannels*(bitsPerSample/8);// samplerate x channels x (bitspersample / 8)
unsigned int blockAlign = numChannels*bitsPerSample/8;
unsigned long Subchunk2Size = 0L;
unsigned long recByteSaved = 0L;
unsigned long NumSamples = 0L;
byte byte1, byte2, byte3, byte4;


void setup() {

  Serial.begin(9600);
  while (!Serial && millis() < 5000) {
    // wait for serial port to connect.
  }
  Serial.println("Serial set up correctly");
  Serial.printf("Audio block set to %d samples\n",AUDIO_BLOCK_SAMPLES);
  print_mode();
  // Configure the input pins
  pinMode(HOOK_PIN, INPUT_PULLUP);
  pinMode(PLAYBACK_BUTTON_PIN, INPUT_PULLUP);

  // Audio connections require memory, and the record queue
  // uses this memory to buffer incoming audio.
  AudioMemory(60);

  // Enable the audio shield, select input, and enable output
  sgtl5000_1.enable();
  // Define which input on the audio shield to use (AUDIO_INPUT_LINEIN / AUDIO_INPUT_MIC)
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  //sgtl5000_1.adcHighPassFilterDisable(); //

  // ----- Level settings -----
  sgtl5000_1.micGain(39); // set to suit your microphone
  sgtl5000_1.audioPreProcessorEnable(); // optional: could be a good plan...
  sgtl5000_1.autoVolumeEnable();        // ...to prevent shouty people overloading the file
  sgtl5000_1.volume(0.5); // overall speaker volume

  mixer.gain(0, 0.1f); // beeps
  mixer.gain(1, 0.5f); // greeting
  mixer.gain(2, 1.0f); // message playback
  // --------------------------

  // Play a beep to indicate system is online
  waveform1.begin(beep_volume, 440, WAVEFORM_SINE);
  wait(1000);
  waveform1.amplitude(0);
  delay(1000);

  // Initialize the SD card
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) 
  {
    // stop here if no SD card, but print a message
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
    else Serial.println("SD card correctly initialized");


  // mandatory to begin the MTP session.
    MTP.begin();

  // Add SD Card
//    MTP.addFilesystem(SD, "SD Card");
    MTP.addFilesystem(SD, "Kais Audio guestbook"); // choose a nice name for the SD card volume to appear in your file explorer
    Serial.println("Added SD card via MTP");
    MTPcheckInterval = MTP.storage()->get_DeltaDeviceCheckTimeMS();
    
    // Value in dB
//  sgtl5000_1.micGain(15);
//  sgtl5000_1.micGain(5); // much lower gain is required for the AOM5024 electret capsule

  // Synchronise the Time object used in the program code with the RTC time provider.
  // See https://github.com/PaulStoffregen/Time
  setSyncProvider(getTeensy3Time);
  
  // Define a callback that will assign the correct datetime for any file system operations
  // (i.e. saving a new audio recording onto the SD card)
  FsDateTime::setCallback(dateTime);

  mode = Mode::Ready; print_mode();
}

void loop() {
  // First, read the buttons
  buttonRecord.update();
  buttonPlay.update();

  switch(mode){
    case Mode::Ready:
      // Falling edge occurs when the handset is lifted --> 611 telephone
      if (buttonRecord.fallingEdge()) {
        Serial.println("Handset lifted");
        mode = Mode::Prompting; print_mode();
      }
      else if(buttonPlay.fallingEdge()) {
        //playAllRecordings();
        playLastRecording();
      }
      break;

    case Mode::Prompting:
      // Wait a second for users to put the handset to their ear
      wait(1000);
      // Play the greeting inviting them to record their message
      playGreeting.play("greeting.wav");    
      // Wait until the  message has finished playing
//      while (playGreeting.isPlaying()) {
      while (!playGreeting.isStopped()) {
        // Check whether the handset is replaced
        buttonRecord.update();
        buttonPlay.update();
        // Handset is replaced
        if (buttonRecord.read()) { // wait() may have lost edge - use the level instead
          playGreeting.stop();
          mode = Mode::Ready; print_mode();
          return;
        }
        if(buttonPlay.fallingEdge()) {
          playGreeting.stop();
          //playAllRecordings();
          playLastRecording();
          return;
        }
        
      }
      // Debug message
      Serial.println("Starting Recording");
      // Play the tone sound effect
      waveform1.begin(beep_volume, 440, WAVEFORM_SINE);
      wait(1250);
      waveform1.amplitude(0);
      // Start the recording function
      startRecording();
      theTimer = 0;
      break;

    case Mode::Recording:
      // Handset is replaced
      if ( buttonRecord.risingEdge()
        || theTimer >= MAX_RECORDING_TIME_MS) // ...or has been off-hook too long)
      {
        // Debug log
        Serial.println("Stopping Recording");
        // Stop recording
        stopRecording();
        // Play audio tone to confirm recording has ended
        end_Beep();
      }
      else {
        continueRecording();
      }
      break;

    case Mode::Playing: // to make compiler happy
      break;  

    case Mode::Initialising: // to make compiler happy
      break;  
  }   
  
  MTP.loop();  // This is mandatory to be placed in the loop code.
}

void setMTPdeviceChecks(bool nable)
{
  if (nable)
  {
    MTP.storage()->set_DeltaDeviceCheckTimeMS(MTPcheckInterval);
    Serial.print("En");
  }
  else
  {
    MTP.storage()->set_DeltaDeviceCheckTimeMS((uint32_t) -1);
    Serial.print("Dis");
  }
  Serial.println("abled MTP storage device checks");
}
  

#if defined(INSTRUMENT_SD_WRITE)
static uint32_t worstSDwrite, printNext;
#endif // defined(INSTRUMENT_SD_WRITE)

void startRecording() {
  setMTPdeviceChecks(false); // disable MTP device checks while recording
#if defined(INSTRUMENT_SD_WRITE)
  worstSDwrite = 0;
  printNext = 0;
#endif // defined(INSTRUMENT_SD_WRITE)
  // Find the first available file number
//  for (uint8_t i=0; i<9999; i++) { // BUGFIX uint8_t overflows if it reaches 255  
  for (uint16_t i=0; i<9999; i++) {   
    // Format the counter as a five-digit number with leading zeroes, followed by file extension
    snprintf(filename, 11, " %05d.wav", i);
    // Create if does not exist, do not open existing, write, sync after write
    if (!SD.exists(filename)) {
      break;
    }
  }
  frec = SD.open(filename, FILE_WRITE);
  Serial.println("Opened file !");
  if(frec) {
    Serial.print("Recording to ");
    Serial.println(filename);
    queue1.begin();
    mode = Mode::Recording; print_mode();
    recByteSaved = 0L;
  }
  else {
    Serial.println("Couldn't open file to record!");
  }
}

void continueRecording() {
#if defined(INSTRUMENT_SD_WRITE)
  uint32_t started = micros();
#endif // defined(INSTRUMENT_SD_WRITE)
#define NBLOX 16  
  // Check if there is data in the queue
  if (queue1.available() >= NBLOX) {
    byte buffer[NBLOX*AUDIO_BLOCK_SAMPLES*sizeof(int16_t)];
    // Fetch 2 blocks from the audio library and copy
    // into a 512 byte buffer.  The Arduino SD library
    // is most efficient when full 512 byte sector size
    // writes are used.
    for (int i=0;i<NBLOX;i++)
    {
      memcpy(buffer+i*AUDIO_BLOCK_SAMPLES*sizeof(int16_t), queue1.readBuffer(), AUDIO_BLOCK_SAMPLES*sizeof(int16_t));
      queue1.freeBuffer();
    }
    // Write all 512 bytes to the SD card
    frec.write(buffer, sizeof buffer);
    recByteSaved += sizeof buffer;
  }
  
#if defined(INSTRUMENT_SD_WRITE)
  started = micros() - started;
  if (started > worstSDwrite)
    worstSDwrite = started;

  if (millis() >= printNext)
  {
    Serial.printf("Worst write took %luus\n",worstSDwrite);
    worstSDwrite = 0;
    printNext = millis()+250;
  }
#endif // defined(INSTRUMENT_SD_WRITE)
}

void stopRecording() {
  // Stop adding any new data to the queue
  queue1.end();
  // Flush all existing remaining data from the queue
  while (queue1.available() > 0) {
    // Save to open file
    frec.write((byte*)queue1.readBuffer(), AUDIO_BLOCK_SAMPLES*sizeof(int16_t));
    queue1.freeBuffer();
    recByteSaved += AUDIO_BLOCK_SAMPLES*sizeof(int16_t);
  }
  writeOutHeader();
  // Close the file
  frec.close();
  Serial.println("Closed file");
  mode = Mode::Ready; print_mode();
  setMTPdeviceChecks(true); // enable MTP device checks, recording is finished
}


void playAllRecordings() {
  // Recording files are saved in the root directory
  File dir = SD.open("/");
  
  while (true) {
    File entry =  dir.openNextFile();
    if (strstr(entry.name(), "greeting"))
    {
       entry =  dir.openNextFile();
    }
    if (!entry) {
      // no more files
      entry.close();
      end_Beep();
      break;
    }
    //int8_t len = strlen(entry.name()) - 4;
//    if (strstr(strlwr(entry.name() + (len - 4)), ".raw")) {
//    if (strstr(strlwr(entry.name() + (len - 4)), ".wav")) {
    // the lines above throw a warning, so I replace them with this (which is also easier to read):
    if (strstr(entry.name(), ".wav") || strstr(entry.name(), ".WAV")) {
      Serial.print("Now playing ");
      Serial.println(entry.name());
      // Play a short beep before each message
      waveform1.amplitude(beep_volume);
      wait(750);
      waveform1.amplitude(0);
      // Play the file
      playMessage.play(entry.name());
      mode = Mode::Playing; print_mode();
    }
    entry.close();

//    while (playWav1.isPlaying()) { // strangely enough, this works for playRaw, but it does not work properly for playWav
    while (!playMessage.isStopped()) { // this works for playWav
      buttonPlay.update();
      buttonRecord.update();
      // Button is pressed again
//      if(buttonPlay.risingEdge() || buttonRecord.risingEdge()) { // FIX
      if(buttonPlay.fallingEdge() || buttonRecord.risingEdge()) { 
        playMessage.stop();
        mode = Mode::Ready; print_mode();
        return;
      }   
    }
  }
  // All files have been played
  mode = Mode::Ready; print_mode();
}

void playLastRecording() {
  // Find the first available file number
  uint16_t idx = 0; 
  for (uint16_t i=0; i<9999; i++) {
    // Format the counter as a five-digit number with leading zeroes, followed by file extension
    snprintf(filename, 11, " %05d.wav", i);
    // check, if file with index i exists
    if (!SD.exists(filename)) {
     idx = i - 1;
     break;
      }
  }
      // now play file with index idx == last recorded file
      snprintf(filename, 11, " %05d.wav", idx);
      Serial.println(filename);
      playMessage.play(filename);
      mode = Mode::Playing; print_mode();
      while (!playMessage.isStopped()) { // this works for playWav
      buttonPlay.update();
      buttonRecord.update();
      // Button is pressed again
//      if(buttonPlay.risingEdge() || buttonRecord.risingEdge()) { // FIX
      if(buttonPlay.fallingEdge() || buttonRecord.risingEdge()) {
        playMessage.stop();
        mode = Mode::Ready; print_mode();
        return;
      }   
    }
      // file has been played
  mode = Mode::Ready; print_mode();  
  end_Beep();
}


// Retrieve the current time from Teensy built-in RTC
time_t getTeensy3Time(){
  return Teensy3Clock.get();
}

// Callback to assign timestamps for file system operations
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {

  // Return date using FS_DATE macro to format fields.
  *date = FS_DATE(year(), month(), day());

  // Return time using FS_TIME macro to format fields.
  *time = FS_TIME(hour(), minute(), second());

  // Return low time bits in units of 10 ms.
  *ms10 = second() & 1 ? 100 : 0;
}

// Non-blocking delay, which pauses execution of main program logic,
// but while still listening for input 
void wait(unsigned int milliseconds) {
  elapsedMillis msec=0;

  while (msec <= milliseconds) {
    buttonRecord.update();
    buttonPlay.update();
    if (buttonRecord.fallingEdge()) Serial.println("Button (pin 0) Press");
    if (buttonPlay.fallingEdge()) Serial.println("Button (pin 1) Press");
    if (buttonRecord.risingEdge()) Serial.println("Button (pin 0) Release");
    if (buttonPlay.risingEdge()) Serial.println("Button (pin 1) Release");
  }
}


void writeOutHeader() { // update WAV header with final filesize/datasize

//  NumSamples = (recByteSaved*8)/bitsPerSample/numChannels;
//  Subchunk2Size = NumSamples*numChannels*bitsPerSample/8; // number of samples x number of channels x number of bytes per sample
  Subchunk2Size = recByteSaved - 42; // because we didn't make space for the header to start with! Lose 21 samples...
  ChunkSize = Subchunk2Size + 34; // was 36;
  frec.seek(0);
  frec.write("RIFF");
  byte1 = ChunkSize & 0xff;
  byte2 = (ChunkSize >> 8) & 0xff;
  byte3 = (ChunkSize >> 16) & 0xff;
  byte4 = (ChunkSize >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  frec.write("WAVE");
  frec.write("fmt ");
  byte1 = Subchunk1Size & 0xff;
  byte2 = (Subchunk1Size >> 8) & 0xff;
  byte3 = (Subchunk1Size >> 16) & 0xff;
  byte4 = (Subchunk1Size >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = AudioFormat & 0xff;
  byte2 = (AudioFormat >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = numChannels & 0xff;
  byte2 = (numChannels >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = sampleRate & 0xff;
  byte2 = (sampleRate >> 8) & 0xff;
  byte3 = (sampleRate >> 16) & 0xff;
  byte4 = (sampleRate >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = byteRate & 0xff;
  byte2 = (byteRate >> 8) & 0xff;
  byte3 = (byteRate >> 16) & 0xff;
  byte4 = (byteRate >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = blockAlign & 0xff;
  byte2 = (blockAlign >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = bitsPerSample & 0xff;
  byte2 = (bitsPerSample >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  frec.write("data");
  byte1 = Subchunk2Size & 0xff;
  byte2 = (Subchunk2Size >> 8) & 0xff;
  byte3 = (Subchunk2Size >> 16) & 0xff;
  byte4 = (Subchunk2Size >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  frec.close();
  Serial.println("header written"); 
  Serial.print("Subchunk2: "); 
  Serial.println(Subchunk2Size); 
}

void end_Beep(void) {
          waveform1.frequency(523.25);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
        wait(250);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
        wait(250);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
        wait(250);
        waveform1.amplitude(beep_volume);
        wait(250);
        waveform1.amplitude(0);
}

void print_mode(void) { // only for debugging
  Serial.print("Mode switched to: ");
  // Initialising, Ready, Prompting, Recording, Playing
  if(mode == Mode::Ready)           Serial.println(" Ready");
  else if(mode == Mode::Prompting)  Serial.println(" Prompting");
  else if(mode == Mode::Recording)  Serial.println(" Recording");
  else if(mode == Mode::Playing)    Serial.println(" Playing");
  else if(mode == Mode::Initialising)  Serial.println(" Initialising");
  else Serial.println(" Undefined");
}

Above, again, is the virgin file from August 9th, unaltered, as far as I can tell, with the code brackets.

Wish me luck. Appreciate the valuable insights from the right side of the pond.
 
Code:
C:\Arduino\arduino-1.8.19\arduino-builder -dump-prefs -logger=machine -hardware C:\Arduino\arduino-1.8.19\hardware -hardware C:\Users\15712\AppData\Local\Arduino15\packages -tools C:\Arduino\arduino-1.8.19\tools-builder -tools C:\Arduino\arduino-1.8.19\hardware\tools\avr -tools C:\Users\15712\AppData\Local\Arduino15\packages -built-in-libraries C:\Arduino\arduino-1.8.19\libraries -libraries C:\Users\15712\Documents\Arduino\libraries -fqbn=teensy:avr:teensy40:usb=serialmtp,speed=150,o pt=o2std,keys=en-us -ide-version=10819 -build-path C:\Users\15712\AppData\Local\Temp\arduino_build_88 555 -warnings=none -build-cache C:\Users\15712\AppData\Local\Temp\arduino_cache_59 1103 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.teensy-compile.path=C:\Users\15712\AppData\Local\Arduino1 5\packages\teensy\tools\teensy-compile\11.3.1 -prefs=runtime.tools.teensy-compile-11.3.1.path=C:\Users\15712\AppData\Local\Arduino15 \packages\teensy\tools\teensy-compile\11.3.1 -prefs=runtime.tools.teensy-tools.path=C:\Users\15712\AppData\Local\Arduino15\ packages\teensy\tools\teensy-tools\1.58.0 -prefs=runtime.tools.teensy-tools-1.58.0.path=C:\Users\15712\AppData\Local\Arduino15 \packages\teensy\tools\teensy-tools\1.58.0 -verbose C:\Users\15712\Documents\Arduino\Audio-Guestbooks\audio-guestbook\audio-guestbook.ino

Error resolving FQBN: getting

Error compiling for board Teensy 4.0.

Sorry. Here is the error message using the hashtag code tags. User is virgin too.
 
Back
Top