Unverified Commit 8ba32081 authored by Wolle's avatar Wolle Committed by GitHub

Merge pull request #636 from schreibfaul1/dev

Arduino V3
parents 961b320c 7caef301
......@@ -3,8 +3,8 @@
*
* Created on: Oct 26.2018
*
* Version 3.0.7z
* Updated on: Dec 16.2023
* Version 3.0.8
* Updated on: Dec 22.2023
* Author: Wolle (schreibfaul1)
*
*/
......@@ -2130,30 +2130,33 @@ bool Audio::pauseResume() {
return retVal;
}
//---------------------------------------------------------------------------------------------------------------------
bool Audio::playChunk() {
// If we've got data, try and pump it out..
void Audio::playChunk() {
int16_t sample[2];
if(getBitsPerSample() == 8) {
if(getChannels() == 1) {
while(m_validSamples) {
auto pc = [&](int16_t *s16) { // lambda, inner function
if(playSample(s16)){
m_validSamples--;
m_curSample++;
return true;
}
return false;
};
// If we've got data, try and pump it out..
while(m_validSamples){
if(getBitsPerSample() == 8) {
if(getChannels() == 1) {
uint8_t x = m_outBuff[m_curSample] & 0x00FF;
uint8_t y = (m_outBuff[m_curSample] & 0xFF00) >> 8;
sample[RIGHTCHANNEL] = x;
sample[LEFTCHANNEL] = x;
while(1) {
if(playSample(sample)) break;
} // Can't send?
if(!pc(sample)){ break;} // playSample in lambda
sample[RIGHTCHANNEL] = y;
sample[LEFTCHANNEL] = y;
while(1) {
if(playSample(sample)) break;
} // Can't send?
m_validSamples--;
m_curSample++;
if(!pc(sample)){ break;} // playSample in lambda
}
}
if(getChannels() == 2) {
while(m_validSamples) {
if(getChannels() == 2) {
uint8_t x = m_outBuff[m_curSample] & 0x00FF;
uint8_t y = (m_outBuff[m_curSample] & 0xFF00) >> 8;
if(!m_f_forceMono) { // stereo mode
......@@ -2165,54 +2168,29 @@ bool Audio::playChunk() {
sample[RIGHTCHANNEL] = xy;
sample[LEFTCHANNEL] = xy;
}
while(1) {
if(playSample(sample)) break;
} // Can't send?
m_validSamples--;
m_curSample++;
if(!pc(sample)){ break;} // playSample in lambda
}
}
m_curSample = 0;
return true;
}
if(getBitsPerSample() == 16) {
if(getChannels() == 1) {
while(m_validSamples) {
if(getBitsPerSample() == 16) {
if(getChannels() == 1) {
sample[RIGHTCHANNEL] = m_outBuff[m_curSample];
sample[LEFTCHANNEL] = m_outBuff[m_curSample];
if(!playSample(sample)) {
log_e("can't send");
return false;
} // Can't send
m_validSamples--;
m_curSample++;
}
}
if(getChannels() == 2) {
m_curSample = 0;
while(m_validSamples) {
if(!m_f_forceMono) { // stereo mode
sample[RIGHTCHANNEL] = m_outBuff[m_curSample * 2];
sample[LEFTCHANNEL] = m_outBuff[m_curSample * 2 + 1];
}
else { // mono mode, #100
int16_t xy = (m_outBuff[m_curSample * 2] + m_outBuff[m_curSample * 2 + 1]) / 2;
sample[RIGHTCHANNEL] = xy;
sample[LEFTCHANNEL] = xy;
}
playSample(sample);
m_validSamples--;
m_curSample++;
if(getChannels() == 2) {
if(!m_f_forceMono) { // stereo mode
sample[RIGHTCHANNEL] = m_outBuff[m_curSample * 2];
sample[LEFTCHANNEL] = m_outBuff[m_curSample * 2 + 1];
}
else { // mono mode, #100
int16_t xy = (m_outBuff[m_curSample * 2] + m_outBuff[m_curSample * 2 + 1]) / 2;
sample[RIGHTCHANNEL] = xy;
sample[LEFTCHANNEL] = xy;
}
}
}
m_curSample = 0;
return true;
if(!pc(sample)){ break;} // playSample in lambda
}
log_e("BitsPer Sample must be 8 or 16!");
m_validSamples = 0;
stopSong();
return false;
}
//---------------------------------------------------------------------------------------------------------------------
void Audio::loop() {
......@@ -2952,6 +2930,7 @@ void Audio::processLocalFile() {
if(f_fileDataComplete && InBuff.bufferFilled() < InBuff.getMaxBlockSize()) {
if(InBuff.bufferFilled()) {
if(!readID3V1Tag()) {
if(m_validSamples) {playChunk(); return;} // play samples first
int bytesDecoded = sendBytes(InBuff.getReadPtr(), InBuff.bufferFilled());
if(bytesDecoded <= InBuff.bufferFilled()) { // avoid InBuff overrun (can be if file is corrupt)
if(m_f_playing) {
......@@ -3001,17 +2980,7 @@ void Audio::processLocalFile() {
// play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if(f_stream) {
static uint8_t cnt = 0;
uint8_t compression;
if(m_codec == CODEC_WAV) compression = 1;
if(m_codec == CODEC_FLAC) compression = 2;
else
compression = 3;
cnt++;
if(cnt == compression) {
playAudioData();
cnt = 0;
}
playAudioData();
}
}
//----------------------------------------------------------------------------------------------------------------------
......@@ -3091,17 +3060,7 @@ void Audio::processWebStream() {
// play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if(f_stream) {
static uint8_t cnt = 0;
uint8_t compression;
if(m_codec == CODEC_WAV) compression = 1;
if(m_codec == CODEC_FLAC) compression = 2;
else
compression = 3;
cnt++;
if(cnt == compression) {
playAudioData();
cnt = 0;
}
playAudioData();
}
}
//---------------------------------------------------------------------------------------------------------------------
......@@ -3200,6 +3159,7 @@ void Audio::processWebFile() {
if(f_webFileDataComplete && InBuff.bufferFilled() < InBuff.getMaxBlockSize()) {
if(InBuff.bufferFilled()) {
if(!readID3V1Tag()) {
if(m_validSamples) {playChunk(); return;} // play samples first
int bytesDecoded = sendBytes(InBuff.getReadPtr(), InBuff.bufferFilled());
if(bytesDecoded > 2) {
InBuff.bytesWasRead(bytesDecoded);
......@@ -3233,17 +3193,7 @@ void Audio::processWebFile() {
// play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if(f_stream) {
static uint8_t cnt = 0;
uint8_t compression;
if(m_codec == CODEC_WAV) compression = 1;
if(m_codec == CODEC_FLAC) compression = 2;
else
compression = 3;
cnt++;
if(cnt == compression) {
playAudioData();
cnt = 0;
}
playAudioData();
}
return;
}
......@@ -3356,12 +3306,7 @@ void Audio::processWebStreamTS() {
// play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if(f_stream) {
static uint8_t cnt = 0;
cnt++;
if(cnt == 3) {
playAudioData();
cnt = 0;
} // aac only
playAudioData();
}
return;
}
......@@ -3479,17 +3424,14 @@ void Audio::processWebStreamHLS() {
// play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if(f_stream) {
static uint8_t cnt = 0;
cnt++;
if(cnt == 2) {
playAudioData();
cnt = 0;
} // aac only
playAudioData();
}
return;
}
//---------------------------------------------------------------------------------------------------------------------
void Audio::playAudioData() {
if(m_validSamples) {playChunk(); return;} // play samples first
if(InBuff.bufferFilled() < InBuff.getMaxBlockSize()) return; // guard
int bytesDecoded = sendBytes(InBuff.getReadPtr(), InBuff.getMaxBlockSize());
......@@ -3506,7 +3448,7 @@ void Audio::playAudioData() {
InBuff.bytesWasRead(bytesDecoded);
return;
}
if(bytesDecoded == 0) return; // syncword at pos0 found
if(bytesDecoded == 0) return; // syncword at pos0
}
return;
......@@ -4245,6 +4187,7 @@ void Audio::setDecoderItems() {
}
//---------------------------------------------------------------------------------------------------------------------
int Audio::sendBytes(uint8_t* data, size_t len) {
int bytesLeft;
static bool f_setDecodeParamsOnce = true;
int nextSync = 0;
......@@ -4365,7 +4308,8 @@ int Audio::sendBytes(uint8_t* data, size_t len) {
audio_process_extern(m_outBuff, m_validSamples, &continueI2S);
if(!continueI2S) { return bytesDecoded; }
}
while(m_validSamples) { playChunk(); }
m_curSample = 0;
playChunk();
return bytesDecoded;
}
//---------------------------------------------------------------------------------------------------------------------
......@@ -4500,7 +4444,7 @@ void Audio::printDecodeError(int r) {
case ERR_OPUS_INVALID_SAMPLERATE: e = "SAMPLERATE IS NOT 48000Hz"; break;
case ERR_OPUS_EXTRA_CHANNELS_UNSUPPORTED: e = "EXTRA CHANNELS UNSUPPORTED"; break;
case ERR_OPUS_SILK_MODE_UNSUPPORTED: e = "SILK MODE UNSUPPORTED"; break;
case ERR_OPUS_HYBRID_MODE_UNSUPPORTED: e = "HYBRID MODE UMSUPPORTED"; break;
case ERR_OPUS_HYBRID_MODE_UNSUPPORTED: e = "HYBRID MODE UNSUPPORTED"; break;
case ERR_OPUS_CELT_BAD_ARG: e = "CELT_DECODER_BAD_ARG"; break;
case ERR_OPUS_CELT_INTERNAL_ERROR: e = "CELT DECODER INTERNAL ERROR"; break;
case ERR_OPUS_CELT_UNIMPLEMENTED: e = "CELT DECODER UNIMPLEMENTED ARG"; break;
......@@ -4835,7 +4779,7 @@ bool Audio::playSample(int16_t sample[2]) {
sample = IIR_filterChain2(sample);
//-------------------------------------------
uint32_t s32 = Gain(sample); // vosample2lume;
uint32_t s32 = Gain(sample); // sample2volume;
if(audio_process_i2s) {
// process audio sample just before writing to i2s
......@@ -4847,16 +4791,15 @@ bool Audio::playSample(int16_t sample[2]) {
if(m_f_internalDAC) { s32 += 0x80008000; }
m_i2s_bytesWritten = 0;
#if(ESP_IDF_VERSION_MAJOR == 5)
esp_err_t err = i2s_channel_write(m_i2s_tx_handle, (const char*)&s32, sizeof(uint32_t), &m_i2s_bytesWritten, 100);
esp_err_t err = i2s_channel_write(m_i2s_tx_handle, (const char*)&s32, sizeof(uint32_t), &m_i2s_bytesWritten, 0);
#else
esp_err_t err = i2s_write((i2s_port_t)m_i2s_num, (const char*)&s32, sizeof(uint32_t), &m_i2s_bytesWritten, 100);
esp_err_t err = i2s_write((i2s_port_t)m_i2s_num, (const char*)&s32, sizeof(uint32_t), &m_i2s_bytesWritten, 0); // no wait
#endif
if(err != ESP_OK) {
log_e("ESP32 Errorcode %i", err);
return false;
}
if(m_i2s_bytesWritten < 4) {
log_e("Can't stuff any more in I2S..."); // increase waitingtime or outputbuffer
if(m_i2s_bytesWritten < 4) { // no more space in dma buffer --> break and try it later
return false;
}
return true;
......
......@@ -3,8 +3,8 @@
*
* Created on: Oct 28,2018
*
* Version 3.0.7z
* Updated on: Dec 16.2023
* Version 3.0.8
* Updated on: Dec 22.2023
* Author: Wolle (schreibfaul1)
*/
......@@ -220,7 +220,7 @@ private:
bool setBitsPerSample(int bits);
bool setChannels(int channels);
bool setBitrate(int br);
bool playChunk();
void playChunk();
bool playSample(int16_t sample[2]);
void computeVUlevel(int16_t sample[2]);
void computeLimit();
......
......@@ -3,7 +3,7 @@
* based on Xiph.Org Foundation celt decoder
*
* Created on: 26.01.2023
* Updated on: 07.04.2023
* Updated on: 23.12.2023
*/
//----------------------------------------------------------------------------------------------------------------------
// O G G / O P U S I M P L.
......@@ -16,7 +16,9 @@ bool s_f_opusSubsequentPage = false;
bool s_f_opusParseOgg = false;
bool s_f_newSteamTitle = false; // streamTitle
bool s_f_opusFramePacket = false;
bool s_f_opusStereoFlag = false;
uint8_t s_opusChannels = 0;
uint8_t s_opusCountCode = 0;
uint16_t s_opusSamplerate = 0;
uint32_t s_opusSegmentLength = 0;
char *s_opusChbuf = NULL;
......@@ -58,6 +60,7 @@ void OPUSsetDefaults(){
s_f_opusParseOgg = false;
s_f_newSteamTitle = false; // streamTitle
s_f_opusFramePacket = false;
s_f_opusStereoFlag = false;
s_opusChannels = 0;
s_opusSamplerate = 0;
s_opusSegmentLength = 0;
......@@ -65,6 +68,7 @@ void OPUSsetDefaults(){
s_opusSegmentTableSize = 0;
s_opusOldMode = 0xFF;
s_opusSegmentTableRdPtr = -1;
s_opusCountCode = 0;
s_opusError = 0;
}
......@@ -73,38 +77,100 @@ void OPUSsetDefaults(){
int OPUSDecode(uint8_t *inbuf, int *bytesLeft, short *outbuf){
static uint16_t fs = 0;
static uint8_t M = 0;
static uint16_t paddingBytes = 0;
static uint16_t samplesPerFrame = 0;
int ret = ERR_OPUS_NONE;
int len = 0;
if(s_f_opusParseOgg){
int ret = OPUSparseOGG(inbuf, bytesLeft);
fs = 0;
M = 0;
paddingBytes = 0;
s_opusCountCode = 0;
ret = OPUSparseOGG(inbuf, bytesLeft);
if(ret == ERR_OPUS_NONE) return OPUS_PARSE_OGG_DONE; // ok
else return ret; // error
}
if(s_opusCountCode == 3) goto FramePacking;
if(s_f_opusFramePacket){
if(s_opusSegmentTableSize > 0){
s_opusSegmentTableRdPtr++;
s_opusSegmentTableSize--;
int len = s_opusSegmentTable[s_opusSegmentTableRdPtr];
len = s_opusSegmentTable[s_opusSegmentTableRdPtr];
}
ret = parseOpusTOC(inbuf[0]);
samplesPerFrame = opus_packet_get_samples_per_frame(inbuf, 48000);
if(ret < 0) goto exit; // error
FramePacking:
// https://www.tech-invite.com/y65/tinv-ietf-rfc-6716-2.html 3.2. Frame Packing
if(s_opusCountCode == 0){ // Code 0: One Frame in the Packet
*bytesLeft -= len;
int32_t ret = parseOpusTOC(inbuf[0]);
if(ret < 0) return ret;
int frame_size = opus_packet_get_samples_per_frame(inbuf, 48000);
ret = parseOpusTOC(inbuf[0]);
if(ret < 0) goto exit; // error
len--;
inbuf++;
ec_dec_init((uint8_t *)inbuf, len);
ret = celt_decode_with_ec(inbuf, len, (int16_t*)outbuf, frame_size);
if(ret < 0) return ret; // celt error
ret = celt_decode_with_ec(inbuf, len, (int16_t*)outbuf, samplesPerFrame);
if(ret < 0) goto exit; // celt error
s_opusValidSamples = ret;
if(s_opusSegmentTableSize== 0){
s_opusSegmentTableRdPtr = -1; // back to the parking position
s_f_opusFramePacket = false;
s_f_opusParseOgg = true;
ret = ERR_OPUS_NONE;
}
if(s_opusCountCode == 1){ // Code 1: Two Frames in the Packet, Each with Equal Compressed Size
log_e("OPUS countCode 1 not supported yet"); vTaskDelay(1000); // todo
}
if(s_opusCountCode == 2){ // Code 2: Two Frames in the Packet, with Different Compressed Sizes
log_e("OPUS countCode 2 not supported yet"); vTaskDelay(1000); // todo
}
if(s_opusCountCode == 3){ // Code 3: A Signaled Number of Frames in the Packet
if(M == 0){
bool v = ((inbuf[1] & 0x80) == 0x80); // VBR indicator
(void)v;
bool p = ((inbuf[1] & 0x40) == 0x40); // padding bit
M = inbuf[1] & 0x3F; // max framecount
// log_i("v %i, p %i, M %i", v, p, M);
paddingBytes = 0;
if(p){
int i = 0;
while(inbuf[2 + i] == 255){
paddingBytes += inbuf[2 + i];
i++;
}
paddingBytes += inbuf[2 + i];
fs = (len - 3 - i - paddingBytes) / M;
*bytesLeft -= 3 + i;
inbuf += 3 + i;
}
}
*bytesLeft -= fs;
ec_dec_init((uint8_t *)inbuf, fs);
ret = celt_decode_with_ec(inbuf, fs, (int16_t*)outbuf, samplesPerFrame);
if(ret < 0) goto exit; // celt error
s_opusValidSamples = ret;
M--;
// log_i("M %i fs %i spf %i", M, fs, samplesPerFrame);
ret = ERR_OPUS_NONE;
if(M == 0) {s_opusCountCode = 0; *bytesLeft -= paddingBytes; goto exit;}
return ret;
}
}
return ERR_OPUS_NONE;
exit:
if(s_opusSegmentTableSize== 0){
s_opusSegmentTableRdPtr = -1; // back to the parking position
s_f_opusFramePacket = false;
s_f_opusParseOgg = true;
}
return ret;
}
//----------------------------------------------------------------------------------------------------------------------
int32_t opus_packet_get_samples_per_frame(const uint8_t *data, int32_t Fs) {
......@@ -155,8 +221,8 @@ int parseOpusTOC(uint8_t TOC_Byte){ // https://www.rfc-editor.org/rfc/rfc6716
uint8_t mode = 0;
uint8_t configNr = 0;
uint8_t s = 0;
uint8_t c = 0; (void)c;
uint8_t s = 0; // stereo flag
uint8_t c = 0; (void)c; // count code
configNr = (TOC_Byte & 0b11111000) >> 3;
s = (TOC_Byte & 0b00000100) >> 2;
......@@ -184,13 +250,13 @@ int parseOpusTOC(uint8_t TOC_Byte){ // https://www.rfc-editor.org/rfc/rfc6716
c = 2: 2 frames in the packet, with different compressed sizes
c = 3: an arbitrary number of frames in the packet
*/
// log_i("configNr %i, s %i, c %i", configNr, s, c);
s_opusCountCode = c;
s_f_opusStereoFlag = s;
if(configNr < 12) return ERR_OPUS_SILK_MODE_UNSUPPORTED;
if(configNr < 16) return ERR_OPUS_HYBRID_MODE_UNSUPPORTED;
return s;
return configNr;
}
//----------------------------------------------------------------------------------------------------------------------
int parseOpusComment(uint8_t *inbuf, int nBytes){ // reference https://exiftool.org/TagNames/Vorbis.html#Comments
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment