Compare commits

...

5 Commits

Author SHA1 Message Date
ChuckMash 64e8d04004
Merge 4d76f39878 into b837e7d36a 2024-04-26 13:58:13 +01:00
ChuckMash b837e7d36a
Stop output on OOM in MP3 (#658) 2024-04-25 17:53:07 -07:00
Infinity 51a584c2b7
Update AudioGeneratorRTTTL.cpp for dotted length (#668) 2024-04-25 17:51:42 -07:00
ChuckMash 4d76f39878
make sure setrate can be called for default value 2023-12-17 06:10:48 -08:00
ChuckMash f72d75e267
setrate already set click bugfix 2023-12-16 00:55:17 -08:00
4 changed files with 29 additions and 10 deletions

View File

@ -1,7 +1,7 @@
/* /*
AudioGeneratorMP3 AudioGeneratorMP3
Wrap libmad MP3 library to play audio Wrap libmad MP3 library to play audio
Copyright (C) 2017 Earle F. Philhower, III Copyright (C) 2017 Earle F. Philhower, III
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@ -62,7 +62,7 @@ AudioGeneratorMP3::~AudioGeneratorMP3()
free(synth); free(synth);
free(frame); free(frame);
free(stream); free(stream);
} }
} }
@ -182,7 +182,7 @@ bool AudioGeneratorMP3::GetOneSample(int16_t sample[2])
output->SetChannels(synth->pcm.channels); output->SetChannels(synth->pcm.channels);
lastChannels = synth->pcm.channels; lastChannels = synth->pcm.channels;
} }
// If we're here, we have one decoded frame and sent 0 or more samples out // If we're here, we have one decoded frame and sent 0 or more samples out
if (samplePtr < synth->pcm.length) { if (samplePtr < synth->pcm.length) {
sample[AudioOutput::LEFTCHANNEL ] = synth->pcm.samples[0][samplePtr]; sample[AudioOutput::LEFTCHANNEL ] = synth->pcm.samples[0][samplePtr];
@ -190,7 +190,7 @@ bool AudioGeneratorMP3::GetOneSample(int16_t sample[2])
samplePtr++; samplePtr++;
} else { } else {
samplePtr = 0; samplePtr = 0;
switch ( mad_synth_frame_onens(synth, frame, nsCount++) ) { switch ( mad_synth_frame_onens(synth, frame, nsCount++) ) {
case MAD_FLOW_STOP: case MAD_FLOW_STOP:
case MAD_FLOW_BREAK: audioLogger->printf_P(PSTR("msf1ns failed\n")); case MAD_FLOW_BREAK: audioLogger->printf_P(PSTR("msf1ns failed\n"));
@ -302,6 +302,7 @@ bool AudioGeneratorMP3::begin(AudioFileSource *source, AudioOutput *output)
synth = reinterpret_cast<struct mad_synth *>(preallocateSynthSpace); synth = reinterpret_cast<struct mad_synth *>(preallocateSynthSpace);
} }
else { else {
output->stop();
audioLogger->printf_P("OOM error in MP3: Want %d/%d/%d/%d bytes, have %d/%d/%d/%d bytes preallocated.\n", audioLogger->printf_P("OOM error in MP3: Want %d/%d/%d/%d bytes, have %d/%d/%d/%d bytes preallocated.\n",
preAllocBuffSize(), preAllocStreamSize(), preAllocFrameSize(), preAllocSynthSize(), preAllocBuffSize(), preAllocStreamSize(), preAllocFrameSize(), preAllocSynthSize(),
preallocateSize, preallocateStreamSize, preallocateFrameSize, preallocateSynthSize); preallocateSize, preallocateStreamSize, preallocateFrameSize, preallocateSynthSize);
@ -319,6 +320,7 @@ bool AudioGeneratorMP3::begin(AudioFileSource *source, AudioOutput *output)
p += preAllocSynthSize(); p += preAllocSynthSize();
int neededBytes = p - reinterpret_cast<uint8_t *>(preallocateSpace); int neededBytes = p - reinterpret_cast<uint8_t *>(preallocateSpace);
if (neededBytes > preallocateSize) { if (neededBytes > preallocateSize) {
output->stop();
audioLogger->printf_P("OOM error in MP3: Want %d bytes, have %d bytes preallocated.\n", neededBytes, preallocateSize); audioLogger->printf_P("OOM error in MP3: Want %d bytes, have %d bytes preallocated.\n", neededBytes, preallocateSize);
return false; return false;
} }
@ -336,17 +338,20 @@ bool AudioGeneratorMP3::begin(AudioFileSource *source, AudioOutput *output)
stream = NULL; stream = NULL;
frame = NULL; frame = NULL;
synth = NULL; synth = NULL;
output->stop();
audioLogger->printf_P("OOM error in MP3\n");
return false; return false;
} }
} }
mad_stream_init(stream); mad_stream_init(stream);
mad_frame_init(frame); mad_frame_init(frame);
mad_synth_init(synth); mad_synth_init(synth);
synth->pcm.length = 0; synth->pcm.length = 0;
mad_stream_options(stream, 0); // TODO - add options support mad_stream_options(stream, 0); // TODO - add options support
madInitted = true; madInitted = true;
running = true; running = true;
return true; return true;
} }
@ -413,4 +418,3 @@ extern "C" {
} }
#endif #endif
} }

View File

@ -236,13 +236,13 @@ bool AudioGeneratorRTTTL::GetNextNote()
ptr++; ptr++;
note++; note++;
} }
if (!ReadInt(&scale)) {
scale = defaultOctave;
}
if ((ptr < len) && (buff[ptr] == '.')) { if ((ptr < len) && (buff[ptr] == '.')) {
ptr++; ptr++;
dur += dur / 2; dur += dur / 2;
} }
if (!ReadInt(&scale)) {
scale = defaultOctave;
}
// Eat any trailing whitespace and comma // Eat any trailing whitespace and comma
SkipWhitespace(); SkipWhitespace();
if ((ptr < len) && (buff[ptr]==',')) { if ((ptr < len) && (buff[ptr]==',')) {

View File

@ -33,6 +33,7 @@ AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int
{ {
this->portNo = port; this->portNo = port;
this->i2sOn = false; this->i2sOn = false;
this->i2sRateSet = false;
this->dma_buf_count = dma_buf_count; this->dma_buf_count = dma_buf_count;
if (output_mode != EXTERNAL_I2S && output_mode != INTERNAL_DAC && output_mode != INTERNAL_PDM) { if (output_mode != EXTERNAL_I2S && output_mode != INTERNAL_DAC && output_mode != INTERNAL_PDM) {
output_mode = EXTERNAL_I2S; output_mode = EXTERNAL_I2S;
@ -56,6 +57,7 @@ AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int
#elif defined(ARDUINO_ARCH_RP2040) #elif defined(ARDUINO_ARCH_RP2040)
AudioOutputI2S::AudioOutputI2S(long sampleRate, pin_size_t sck, pin_size_t data) { AudioOutputI2S::AudioOutputI2S(long sampleRate, pin_size_t sck, pin_size_t data) {
i2sOn = false; i2sOn = false;
i2sRateSet = false;
mono = false; mono = false;
bps = 16; bps = 16;
channels = 2; channels = 2;
@ -129,7 +131,13 @@ bool AudioOutputI2S::SetPinout(int bclk, int wclk, int dout, int mclk)
bool AudioOutputI2S::SetRate(int hz) bool AudioOutputI2S::SetRate(int hz)
{ {
// TODO - have a list of allowable rates from constructor, check them // TODO - have a list of allowable rates from constructor, check them
if(this->hertz == hz && this->i2sRateSet){ // hz already set to this
return true;
}
this->hertz = hz; this->hertz = hz;
if (i2sOn) if (i2sOn)
{ {
#ifdef ESP32 #ifdef ESP32
@ -140,6 +148,10 @@ bool AudioOutputI2S::SetRate(int hz)
i2s.setFrequency(hz); i2s.setFrequency(hz);
#endif #endif
} }
if(!this->i2sRateSet){
this->i2sRateSet = true;
}
return true; return true;
} }
@ -401,5 +413,6 @@ bool AudioOutputI2S::stop()
i2s.end(); i2s.end();
#endif #endif
i2sOn = false; i2sOn = false;
i2sRateSet = false;
return true; return true;
} }

View File

@ -62,10 +62,12 @@ class AudioOutputI2S : public AudioOutput
bool mono; bool mono;
int lsb_justified; int lsb_justified;
bool i2sOn; bool i2sOn;
bool i2sRateSet;
int dma_buf_count; int dma_buf_count;
int use_apll; int use_apll;
bool use_mclk; bool use_mclk;
bool swap_clocks; bool swap_clocks;
// We can restore the old values and free up these pins when in NoDAC mode // We can restore the old values and free up these pins when in NoDAC mode
uint32_t orig_bck; uint32_t orig_bck;
uint32_t orig_ws; uint32_t orig_ws;