Minor corrections for playing WAV files from SD cards

boblark 5 months ago
parent ce659515ef
commit 59acb746ae
  1. 4
  2. 117
  3. 36

@ -630,7 +630,7 @@ bool AudioSDPlayer_F32::parse_format(void) {
rate = header[1];
currentWavData.sample_rate = header[1]; // uint32_t
Serial.print("WAV file sample rate = "); Serial.println(rate);
// Serial.print("WAV file sample rate = "); Serial.println(rate);
// b2m is used to determine playing time. We base it on the WAV
// file meta data. It is allowed to be played at a different rate
@ -665,7 +665,7 @@ bool AudioSDPlayer_F32::parse_format(void) {
else {return false;}
bytes2millis = b2m; // Transfer to global
Serial.print(" bytes2millis = "); Serial.println(b2m);
// Serial.print(" bytes2Millis = "); Serial.println(b2m);
// we're not checking the byte rate and block align fields
// if they're not the expected values, all we could do is
// return false. Do any real wav files have unexpected

@ -391,6 +391,7 @@ span.mainfunction {color: #993300; font-weight: bolder}
@ -2558,6 +2559,122 @@ look ahead delay, as well.</p>
<script type="text/x-red" data-help-name="AudioPlaySdWav_F32">
<div class=tooltipinfo>
<p>Plays a WAV file, stored on an SD card.</p>
<h3>Audio Connections</h3>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Port</th><th>Purpose</th></tr>
<tr class=odd><td align=center>Out 0</td><td>Left Channel Output</td></tr>
<tr class=odd><td align=center>Out 1</td><td>Right Channel Output</td></tr>
<p class=func><span class=keyword>play</span>(filename);</p>
<p class=desc>Begin playing a WAV file. If a file is already playing,
it is stopped and this file starts playing from the beginning.
No return value.</p>
<p class=func><span class=keyword>stop</span>();</p>
<p class=desc>Stop playing. If not playing, this function has no effect.
No return value.</p>
<p class=func><span class=keyword>togglePlayPause</span>();</p>
<p class=desc>Used to Pause the playing of a file, or to un-Pause
depending on which applies. No return value. </p>
<p class=func><span class=keyword>isPlaying</span>();</p>
<p class=desc>Return true (non-zero) if playing, or false (zero)
when not playing. See the note below about delayed start.</p>
<p class=func><span class=keyword>isPaused</span>();</p>
<p class=desc>Return true (non-zero) if paused (see
togglePlayPause above).
<p class=func><span class=keyword>isStopped</span>();</p>
<p class=desc>Return true (non-zero) if not playing and
not paused.</p>
<p class=func><span class=keyword>setSubMult</span>(subMult* pStruct)
<p class=desc>Used if the WAV file is to be run at a lower sample rate
than the audio sample rate. The two rates must be related by an integer.
The calling parameter is a pointer to a structure of type subMult.
That is defined as:
struct subMult {
uint16_t rateRatio; // Should be 1 for no rate change, else an integer
uint16_t numCoeffs; // FIR filter
float32_t* firCoeffs; // FIR Filter Coeffs
float32_t* firBufferL; // pointer to 127 + numCoeffs float32_t, left ch
float32_t* firBufferR; // pointer to 127 + numCoeffs float32_t, right ch
The struct is declared in the INO and this function transmits the selected
information. Note that the FIR filters can be used, even if the rateRatio
is 1. There is no need for this caused by rateRatio = 1, but
the filter function may be useful for other reasons. If the WAV file
and the Audio are both using the same sample rate, this function
is not needed and the rateRatio defaults to 1 and no FIR filters
are involked. The left and right FIR filters use the same coefficients
but need separate firBuffer. For monaural files, the firBufferR pointer can be
a NULL.</p>
<p class=func><span class=keyword>getCurrentWavData</span>();</p>
This returns a pointer to a structure containing data about the
WAV file currently selected for play. The structure is:
struct wavData {
uint16_t audio_format; // Should be 1 for PCM
uint16_t num_channels; // 1 for mono, 2 for stereo
uint32_t sample_rate; // 44100, 48000, etc
uint16_t bits; // Number of bits per sample, should be 16
<p class=func><span class=keyword>positionMillis</span>();</p>
<p class=desc>While playing, return the current time offset, in
milliseconds. When not playing, the return from this function
is undefined.
<p class=func><span class=keyword>lengthMillis</span>();</p>
<p class=desc>Return the total length of the current sound clip,
in milliseconds. When not playing, the return from this function
is undefined.
<p class=exam>File &gt; Examples &gt; Audio &gt; WavFilePlayer
<p class=exam>File &gt; Examples &gt; Audio &gt; WavFilePlayer2
<p>Only 16 bit PCM WAV files are supported. When mono
files are played, both output ports transmit a copy of the
single sound. Of course, stereo WAV files play with the left
channel on port 0 and the right channel on port 1.
<p>A brief delay after calling play() will usually occur before
isPlaying() returns true and positionMillis() returns valid
time offset. WAV files have a header at the beginning of the
file, which the audio library must read and parse before
playing can begin.
<p>While playing, the audio library accesses the SD card automatically.
If card access is needed for other purposes, you must
<a href="http://www.pjrc.com/teensy/td_libs_AudioProcessorUsage.html"
target="_blank">use AudioNoInterrupts()</a>
to prevent AudioPlaySDWav from accessing the SD card while you use it.
Disabling the audio library interrupt for too long may cause audible
dropouts or glitches.
<script type="text/x-red" data-template-name="AudioPlaySdWav_F32">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
<script type="text/x-red" data-help-name="AudioPlayQueue_F32">
<div class=tooltipinfo>

@ -4,7 +4,10 @@
* Created: Chip Audette, OpenAudio, Dec 2019
* Based On: WaveFilePlayer from Paul Stoffregen, PJRC, Teensy
* Play back a WAV file through the Typman.
* Play back a WAV file
* This is the basic WAV file player, adapted from the Tympan library.
* See also WAVFilePlayer and WAVFilePlayer2 Bob
* For access to WAV files, please visit https://www.pjrc.com/teensy/td_libs_AudioDataFiles.html.
@ -21,14 +24,12 @@ AudioSettings_F32 audio_settings(sample_rate_Hz, audio_block_samples);
//create audio objects
AudioSDPlayer_F32 audioSDPlayer(audio_settings);
AudioOutputI2S_F32 audioOutput(audio_settings);
//Tympan myTympan(TympanRev::E); //do TympanRev::D or TympanRev::E
//create audio connections
AudioConnection_F32 patchCord1(audioSDPlayer, 0, audioOutput, 0);
AudioConnection_F32 patchCord2(audioSDPlayer, 1, audioOutput, 1);
AudioControlSGTL5000 sgtl5000_1;
// Use these with the Teensy 4.x Rev D Audio Shield
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 11
@ -36,14 +37,17 @@ AudioControlSGTL5000 sgtl5000_1;
void setup() {
Serial.begin(300); delay(1000);
Serial.print("### SDWavPlayer ###");
Serial.print("Sample Rate (Hz): "); Serial.println(audio_settings.sample_rate_Hz);
Serial.print("Audio Block Size (samples): "); Serial.println(audio_settings.audio_block_samples);
Serial.println("### SDWavPlayer ###");
Serial.print("Audio Sample Rate (Hz): ");
Serial.print("Audio Block Size (samples): ");
// Audio connections require memory to work.
AudioMemory_F32(20, audio_settings);
audioOutput.setGain(0.05); // Volume control
@ -58,23 +62,17 @@ void setup() {
//finish setup
delay(2000); //stall a second
delay(1000); //stall a second
Serial.println("Setup complete.");
unsigned long end_millis = 0;
String filename = "SDTEST1.WAV";// filenames are always uppercase 8.3 format
void loop() {
//service the audio player
if (!audioSDPlayer.isPlaying()) { //wait until previous play is done
//start playing audio
Serial.print("Starting audio player: ");
if (!audioSDPlayer.isPlaying())
{ //wait until previous play is done
//start playing audio
Serial.println("Starting audio player: SDTEST1.WAV");