Compare commits
5 Commits
4b55d5fa10
...
64e8d04004
Author | SHA1 | Date |
---|---|---|
ChuckMash | 64e8d04004 | |
ChuckMash | b837e7d36a | |
Infinity | 51a584c2b7 | |
ChuckMash | 4d76f39878 | |
ChuckMash | f72d75e267 |
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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]==',')) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue