Just downloaded the newest version of both tools.
Just downloaded the newest version of both tools.
Anyone an idea?
No one here who can help?
Just downloaded Audio Guestbook, set USB Type to Serial + MTP Disk (Experimental), set cpu to Teensy 3.6 and compiled just fine using TeensyDuino 1.58b3.
Note that you will have to alter the program to work with Teensy 3.6 as noted at the head of the program.
I have no coding experience, but I'm stumbling along. I need some help. I'm getting these error comments when I try compiling the audio guestbook sketch:
Arduino: 1.8.19 (Windows 10), TD: 1.57, Board: "Teensy 4.0, Serial + MTP Disk (Experimental), 600 MHz, Faster, US English"
C:\Users\thebe\AppData\Local\Temp\Temp3_audio-guestbook-main.zip\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:49:1: error: 'AudioPlaySdWavX' does not name a type
AudioPlaySdWavX playWav1; // Play 44.1kHz 16-bit PCM greeting WAV file
^
C:\Users\thebe\AppData\Local\Temp\Temp3_audio-guestbook-main.zip\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:54:28: error: 'playWav1' was not declared in this scope
AudioConnection patchCord3(playWav1, 0, mixer, 1); // wav file playback mixer
^
C:\Users\thebe\AppData\Local\Temp\Temp3_audio-guestbook-main.zip\audio-guestbook-main\audio-guestbook\audio-guestbook.ino: In function 'void loop()':
C:\Users\thebe\AppData\Local\Temp\Temp3_audio-guestbook-main.zip\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:185:7: error: 'playWav1' was not declared in this scope
playWav1.play("greeting.wav");
^
C:\Users\thebe\AppData\Local\Temp\Temp3_audio-guestbook-main.zip\audio-guestbook-main\audio-guestbook\audio-guestbook.ino: In function 'void playAllRecordings()':
C:\Users\thebe\AppData\Local\Temp\Temp3_audio-guestbook-main.zip\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:374:7: error: 'playWav1' was not declared in this scope
playWav1.play(entry.name());
^
C:\Users\thebe\AppData\Local\Temp\Temp3_audio-guestbook-main.zip\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:380:13: error: 'playWav1' was not declared in this scope
while (!playWav1.isStopped()) { // this works for playWav
^
C:\Users\thebe\AppData\Local\Temp\Temp3_audio-guestbook-main.zip\audio-guestbook-main\audio-guestbook\audio-guestbook.ino: In function 'void playLastRecording()':
C:\Users\thebe\AppData\Local\Temp\Temp3_audio-guestbook-main.zip\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:411:7: error: 'playWav1' was not declared in this scope
playWav1.play(filename);
^
Error compiling for board Teensy 4.0.
Can anyone help guide me through this?
Wow ... not quite sure how you managed this! The emboldened text suggests you've somehow managed to persuade the Arduino IDE to try to compile a sketch directly from the .ZIP you downloaded - I can't do that, though I did try briefly.
You should unzip the code into a sub-folder in your default sketches folder; it will need to end up looking roughly like this:
Now you need to follow the "Installation method" from the readme.md really carefully, and check that you have an option on the Tools menu called "Audio tweaks". When the sketch is loaded ready to compile, the IDE should look like this:
Note the two extra files along with the sketch - if these aren't there, then you get the error: 'AudioPlaySdWavX' does not name a type diagnostic. All the other errors you see are a direct result of this, so you can ignore them.
Assuming it now compiles and uploads, check the serial output that tells you the "Audio tweaks" have worked (again, documented in the readme).
EDIT: this is really not a great application for someone with "no coding experience, but I'm stumbling along" to be tackling! Too much of it is on the ragged edge of just about working...
Hi there!
I'm new to all this as many of the new members here, I like the concept of the phone and I hope this is the kickstart to get me into arduino which is something I've been wanting to do for some time.
I downloaded and installed all the latest versions of the required software, uploaded the code to a 32gb sd card, placed on the sd card reader of the teensy 4.1.
Managed to find the switch poles of my phone, I have all the wires ready and I can switch them to try different connections, because all I;m doing is trial and error here.
I have my greeting.wav in the root of the SD card, but I pick up the tube and I hear nothing, move switch the wires to see if anything changes and still nothing.
My serial monitor displays this :
Serial set up correctly
Mode switched to: Initialising
Button (pin 0) Release
Button (pin 1) Release
SD card correctly initialized
Add **SDClass** file system
Added SD card via MTP
Mode switched to: Ready
&&&&& Dump MTPStorage Loop Data &&&&&
Callback Data: 0 0x0 0
1 0xd059 1
2 0x0 0
3 0x0 0
4 0x0 0
File Systems:
0 0x200039c8 1
I was trying to be a smart a*s thinking I know everything, and I bought a phone already made from a guy in Canada. My idea was to have a working unit and reverse engineer it, but this guy says he cannot provide me with the code, and I've been doing some research and is not as easy as I thought it would be to download the code from that teensy so I can copy to mine.
The phone he sent me is a chinese replica, pure plastic, I bought a nice baquelite vintage phone I want to modify, but I'm hitting a wall here.
Any code for the Teensy has to be programmed into the Teensy. You can not just place it onto an SD card.
I suggest you read this about getting started with Arduino.
Think of the Teensy as a supercharged Arduino.
The Arduino is a Model T, the Teensy is a Ferrari.
They are both cars which do a similar thing but the Ferrari is faster and more complex.
well, I finally made it !!!
Changed a couple of things in the code that I completely missed and now I see action the serial monitor and see the wav files in the card.
I can't hear anything so far, neither the greeting or the recorded message, but I guess that should be an easy fix compared to the code errors, at least in your first phone.
Not sure if my old phone was working properly and have no idea how to test parts. The speaker made a lot of noises at some point, but not sure how to test it if it's able to reproduce any sounds.
Same thing with the mic, not sure how to test besides the most logical (to me) cutting a mic's cable and attach it to the corresponding terminals, but not sure if it's that straight forward or not.
In case I decide to change speaker and mic, not having access to an electronic store and very limited variety of parts online for fast an easy shippng based on where I live, what would you do? Buy another, newer phone and get some donor parts?
Can someone help me ?... The welcome message is perfect but the recorded messages sound very very reduced on the sd card and when playing them directly from the play button.
Thank You.
Does anyone have any ideas please ????
pm sent to you
I installed fresh everything from the original repo. After applying the audio tweak, my recordings sound choppy. I tried several high speed SD cards, all with the same error.
If in continueRecording() function decreases the NBLOX value from 16, it gets faster, if I increase it gets slower. I can't make it stop. Does anyone have any tips?
I use Teensy 4.0Code: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) }
what card you using a a1 or a2 type card
a1 Sandisk extreme 32GB
thank you!
what i am using
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, "Ian 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(100); sgtl5000_1.micGain(35); // 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"); }
Hi All! I still have a clicking sound, I've tried everything. Anyone have any tips on how to fix it?
T4.0, A1 SDHC 32gb micros, original repo with "256-sample audio blocks tweak"
Thank you very much!
00001.wav.zip
Hey Guys, i'm hoping someone can help because i'm losing my mind over here! LOL
so i finally got everything to compile with the latest code. (Thank you so much to DD4WH for the updated coding). i'm assuming since everything compiled correctly that i have all my libraries and everything in the right spots. My problem is that when i power up, i get the 1 beep, and the nothing. and i'm totally stumped. i've read through this entire thread 3 times already hoping i missed something with an answer but can't find anything.
i'm using a new phone from amazon in a retro style. i'm assuming since i cant record anything it has something to do with my hook switch, so i temporarily hooked up a momentary switch to act as the hook, but i still get nothing. i originally had the wires soldered to pins ground and 0 on the teensy and now i have the wires soldered to pins ground and zero on the audio shield. not sure there is a difference since they are connected via header pins but i figured i'd try, but still nothing. can anyone help?! i'm at a total loss. =(
i'm using a t4 with the Rev D audio shield (maybe that's why????) do i have the right components?
After the 1 long beep try saying something as thats when it records the message if you press the hook switch you would get 4 short beeps if you still got handset to ur ear at momonent i cant get the greeting message to play on mine
Nothing records after the first beep and nothing happens when I hit the hook switch after. I never get any other beeps or anything. I thought the code said 2 short beeps to record initial greeting. I could be wrong though. So I figured it does the 1st beep to "initialize" like ok power on, with the handset down, then pick up, hear the 2 beeps and record greeting.
look at post 218 thats the code im using cant get greeting message or replay to work at moment but it recording ok
i tried your code but it doesn't compile. i get errors for the playwav1 file.
Arduino: 1.8.19 (Windows 10), TD: 1.57, Board: "Teensy 4.0, Serial + MTP Disk (Experimental), 150 MHz, Faster, US English, Bigger blocks (256 samples)"
C:\Users\Tripz\Downloads\audio-guestbook-main\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:49:1: error: 'AudioPlaySdWavX' does not name a type
AudioPlaySdWavX playWav1; // Play 44.1kHz 16-bit PCM greeting WAV file
^
C:\Users\Tripz\Downloads\audio-guestbook-main\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:54:28: error: 'playWav1' was not declared in this scope
AudioConnection patchCord3(playWav1, 0, mixer, 1); // wav file playback mixer
^
C:\Users\Tripz\Downloads\audio-guestbook-main\audio-guestbook-main\audio-guestbook\audio-guestbook.ino: In function 'void loop()':
C:\Users\Tripz\Downloads\audio-guestbook-main\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:185:7: error: 'playWav1' was not declared in this scope
playWav1.play("greeting.wav");
^
C:\Users\Tripz\Downloads\audio-guestbook-main\audio-guestbook-main\audio-guestbook\audio-guestbook.ino: In function 'void playAllRecordings()':
C:\Users\Tripz\Downloads\audio-guestbook-main\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:374:7: error: 'playWav1' was not declared in this scope
playWav1.play(entry.name());
^
C:\Users\Tripz\Downloads\audio-guestbook-main\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:380:13: error: 'playWav1' was not declared in this scope
while (!playWav1.isStopped()) { // this works for playWav
^
C:\Users\Tripz\Downloads\audio-guestbook-main\audio-guestbook-main\audio-guestbook\audio-guestbook.ino: In function 'void playLastRecording()':
C:\Users\Tripz\Downloads\audio-guestbook-main\audio-guestbook-main\audio-guestbook\audio-guestbook.ino:411:7: error: 'playWav1' was not declared in this scope
playWav1.play(filename);
^
Error compiling for board Teensy 4.0.
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
one b4 mine
Code: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, "Ian 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[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"); }