Yet Another File Player (and recorder)

Thank you for adding this functionality!

I'm dealing with scenario where teensy's power can cut out (solar power) while recording. This means the stop() function is not called which results in an unplayable file. I'm assuming this is because the headers are written in the call to stop(). I'm okay with loosing whatever is in the buffer by the time the power cuts out but would like to keep the recording on the SD card in a playable state. Is there a function that could be called periodically to keep the file playable?
 
Is there a function that could be called periodically to keep the file playable?
There is indeed. It’s writeCurrentHeader(). Simply call it whenever it makes sense for an active recording object, and it’ll write the header with the current length data.

There’s an example of its use in examples/Buffered/PreloadWhileRecording, slightly over-complex for your purposes as it’s aimed at use in a looper application, and there turned out to be some oddities with playing back a partially recorded file.

Previous discussion on this topic starts around post #111.

I’d be slightly concerned that loss of power will occur while updating the filesystem, losing either the whole file or even corrupting the SD enough to lose multiple files. But dealing with that is well outside the Audio library … apart from anything else, you’d probably need extra hardware to detect when power is about to fail…
 
There is indeed. It’s writeCurrentHeader(). Simply call it whenever it makes sense for an active recording object, and it’ll write the header with the current length data.
Amazing! That works too! Thank you! Code for reference:

C++:
#include <Audio.h>

// Define audio components
AudioInputI2S microphone;      // Audio input object for the microphone
AudioPlayWAVstereo playWav;    // Audio object for playing WAV files
AudioOutputI2S audioOutput;    // Audio output object
AudioMixer4 mixer;             // Audio mixer
AudioRecordWAVmono recordWav;  // Audio recorder for WAV files
// AudioAnalyzeRMS        audioRMS;
// Audio connections
AudioConnection patchCord1(microphone, 0, mixer, 0);  // Microphone to mixer channel 0
// AudioConnection patchCord1(microphone, 0, audioRMS, 0);      // Microphone to rms channel 0
AudioConnection patchCord2(playWav, 0, mixer, 1);         // WAV player to mixer channel 1
AudioConnection patchCord3(mixer, 0, audioOutput, 0);     // Mixer to output (left channel)
AudioConnection patchCord4(mixer, 0, audioOutput, 1);     // Mixer to output (right channel)
AudioConnection patchCord5(microphone, 0, recordWav, 0);  // Mixer to output (right channel)

// Audio control
AudioControlSGTL5000 audioShield;  // Control object for the audio shield

const char* recFile = "rec133.wav";


void setup() {
  // Initialize audio memory and audio shield
  AudioMemory(60);
  audioShield.enable();
  audioShield.inputSelect(AUDIO_INPUT_MIC);
  audioShield.volume(0.5);

  // Initialize the built-in SD card
  if (!SD.begin(BUILTIN_SDCARD)) {
    // Handle error, such as by signaling with an LED or serial output
  }
  while (!Serial)
    ;  // Wait for Serial to be ready

  // Set mixer levels (adjust as needed)
  mixer.gain(0, 0.5);  // Set gain for microphone input
  mixer.gain(1, 0.5);  // Set gain for WAV player

  const size_t sz = 65536;
  const AudioBuffer::bufType bufMem = AudioBuffer::inHeap;
  playWav.createBuffer(sz, bufMem);
  recordWav.createBuffer(sz, bufMem);

  // playWav.play("rec133.wav", SD);  // Play a WAV file from the SD card
  // playWav.play("test.wav", SD);  // Play a WAV file from the SD card
  Serial.println("Playback started");
  // delay(2000); // A couple seconds to confirm audio playback is working


  // Begin recording to a WAV file

  if (!recordWav.record(recFile)) {
    Serial.println("Failed to start recording!");
  } else {
    Serial.println("recording");
    Serial.println("currentheader 1");
    delay(3000);
    recordWav.writeCurrentHeader();
    delay(3000);
    Serial.println("currentheader 2");
    delay(3000);
    recordWav.writeCurrentHeader();
    Serial.println("unplug now");
    // recordWav.stop(); // in case of powerloss not necessarily needed
  }

}

void loop() {
}
 
Just confirmed that Audacity can convert between wav and aiff formats.

So, I'm all in..... except for one reservation. Class 4 show lasers can be dangerous, if static.
What would the chances be of something like that happening during 6 channel wav playback?

Thank you for your time to consider this matter and forewarning me of any concerns you may have. Questions are very welcomed, but full disclosure, I'm only an old school laser artist, not a C++ developer. I've only gotten this far by watching YT tutorials.
 
Last edited:
Guess your essential question is “how likely is it that playback stalls, leaving the beam static?” Answer - I’ve no idea! SD cards can definitely be a bit weird, and I wouldn’t want to certify my code as safe (I get quite enough of that at work…).

You could add a tiny bit of position modulation, e.g driving the beam in a small circle with a low frequency, just high enough to avoid burns. Or use the 6th channel as a watchdog, e.g. with a sine wave you monitor with a peak or RMS block and cut output if the amplitude is too low.

The former is probably only useful during development, I guess, until you’re confident of thes system.
 
I’d imagine it’d be possible for some hoopy frood (that’d be you…) to nail an entirely independent galvo monitor module into your system for a lot less than $200, let alone $10k. Not sure what the simplest I2S ADC is, but that and a Pi Pico for about $5 should do it. Or do most of it in op-amps into the built-in ADCs. Or both, one method running on each of the RP2040’s cores! Plus a safety channel on the Teensy for triple redundancy.
 
I’d imagine it’d be possible for some hoopy frood (that’d be you…) to nail an entirely independent galvo monitor module into your system...
Yeah, I wish my one head were even 1/2 that hoopy, but nah.
To clarify, those prices were for the complete projectors, no just just the scan fail circuits.
BTW, the CS42448 is still available, but is on the 'to be discontinued' chopping block's list. I would like to replace it before placing my next order of PCBs, if you would please point my nose towards its recommended TDM replacement.
Thanks for your interest and feedback.
You folks on this forum are great!
👏👏👏
 
Last edited:
No worries, it’s not just “my” thread … I was rather enjoying it TBH. I’m sure I’d‘ve objected if it’d got really silly, and it’s fun to bump threads when they’ve gone a bit Moribund the Bürgermeister for a while…
 
Shame, but I can quite understand your reasoning.

I'm tinkering with making an evaluation board for Teensy + PCM3168, just because I always intended to mess with getting one of my own designs made, and this seemed like a suitable spur. Very much the most tenuous of vapourware at the moment... One thing I think I'm gonna have to look out for - it appears to use twice the power of the CS42448, and that gets pretty warm! If it gets close to running a batch, I'll let you know, just n case.
 
Sounds like a plan! I’ll park the hardware design and take a look at the mods needed for the TDM driver. I think theyll be fairly minor, and there aren’t too many registers to mess with to get it set up.

For my evaluation board I tracked to allow for either TDM, TDM2 or I2S, also for both I2C ports. Happy to review your schematic when you have one. Would it be quicker if you got a third arm fitted?

We should probably start a separate thread…
 
There seem to be at least several threads (here’s a recent example) where public discussions of preliminary stages of stuff take place, sometimes involving quite niche applications. As we know, a fair few of those fizzle with no end result, but it does allow interested parties to lurk, comment, contribute and find prior art.

Also, the Conversation facility is often a bit limited in the number of posts you can have. I’ve not used this one, but the old one was 30 messages total IIRC.

So I’d say public is better, except as you say for exchanging snail or e mail addresses.
 
I would love play RAW file support. I use this library extensively, and do multi file playback with many many files opening and closing in rapid succession, like one every 100ms across 8 channels, depending on use. The RAW playback makes opening files a lot faster, but would love to try this out. Currently USE_TEENSY3_OPTIMIZED_CODE for the SD card library does a decent job of improving playback. Or, any suggestions to improve USE_TEENSY3_OPTIMIZED_CODE would be cool.
 
How many is “many many”? I need to rework the SDpiano demo code, but that implements low latency playback by preloading the start of nearly 300 samples to PSRAM, so notes start within one audio update (~2,9ms) of being triggered. You don’t need to load the whole file, just enough to allow the file to be opened and playback to transition to streaming from the card. But the demo doesn’t use the preload I added later.

I don’t think RAW files will improve that.…
 
How many is “many many”? I need to rework the SDpiano demo code, but that implements low latency playback by preloading the start of nearly 300 samples to PSRAM, so notes start within one audio update (~2,9ms) of being triggered. You don’t need to load the whole file, just enough to allow the file to be opened and playback to transition to streaming from the card. But the demo doesn’t use the preload I added later.

I don’t think RAW files will improve that.…
I play up to 8 files at a time with an average of 3. All from SanDisk high speed cards. It's OK but s bit choppy with optimized SD library and extra spi SD card buffer at 50 instead of 7.
 
I think we have different definitions of "many many"... 8 files at once should be easy with the buffered SD library properly set up. I don't know what "optimized SD library" or "extra spi SD card buffer at 50 instead of 7" are, but I'm pretty sure I don't do any of that, just use the stock SD library as provided with Teensyduino.

Can you post a short sketch demonstrating choppy output, using this buffered library? Maybe then I can spot what (if anything) you're doing wrong. Please put the code in the </> code tags!
 
I think we have different definitions of "many many"... 8 files at once should be easy with the buffered SD library properly set up. I don't know what "optimized SD library" or "extra spi SD card buffer at 50 instead of 7" are, but I'm pretty sure I don't do any of that, just use the stock SD library as provided with Teensyduino.

Can you post a short sketch demonstrating choppy output, using this buffered library? Maybe then I can spot what (if anything) you're doing wrong. Please put the code in the </> code tags!
It's the modified SD library by teensy. You can open SD_T3.h I think, and edit two lines, one for memory one for enabling optimized/buffered. I assume it's similar to what you are doing, but I get best results with files with no header (RAW).
 
Sounds like you’re using a Teensy 3.x with some ancient experimental SD library. That’s not at all similar to what I’m doing - are you actually using my code?

Given that the 3.x series have been unfortunately rendered obsolete by NXP no longer making the parts, it makes very little sense for me to invest much time investigating any issues with them. I’d recommend you use a 4.x…
 
Sounds like you’re using a Teensy 3.x with some ancient experimental SD library. That’s not at all similar to what I’m doing - are you actually using my code?

Given that the 3.x series have been unfortunately rendered obsolete by NXP no longer making the parts, it makes very little sense for me to invest much time investigating any issues with them. I’d recommend you use a 4.x…
No problem, makes sense. I was not aware they obsoleted the teensy3.2 controller? the MK20DX256VLH7? Where did you see/hear that?
 
Teensy 3.2 was discontinued because NXP are no longer supplying the MK20DX256VLH7.
Well ... not to the likes of PJRC, it seems 🤬. It's still listed as Active on their website, albeit with a 26-week lead time: https://www.nxp.com/part/MK20DX256VLH7#/
1706355766917.png

I guess that could be sustainable if you're a huge business, and tiny ones will buy from distributors, but folk like Paul just get squeezed out.
 
NXP does appear to still be making the chip, but not in sufficient volume for PJRC to continue Teensy 3.2. We had large orders open for over 2 years but they could only ship small quantity. Why, we still don't know, though I kinda suspect production problems or lack of wafer capacity for this older 90nm silicon. Ultimately we had to give up and just discontinue Teensy 3.2.

If you're making a custom product using the Teensy 3.2 code (as I know @zachtos is) my advice is to plan ahead for NXP to have late deliveries and only partial if you're ordering large quantity.
 
Back
Top