code upload
This commit is contained in:
556
yoRadio/src/audioI2S/flac_decoder/flac_decoder.cpp
Normal file
556
yoRadio/src/audioI2S/flac_decoder/flac_decoder.cpp
Normal file
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* flac_decoder.cpp
|
||||
* Java source code from https://www.nayuki.io/page/simple-flac-implementation
|
||||
* adapted to ESP32
|
||||
*
|
||||
* Created on: Jul 03,2020
|
||||
* Updated on: Jul 03,2021
|
||||
*
|
||||
* Author: Wolle
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include "flac_decoder.h"
|
||||
#include "vector"
|
||||
using namespace std;
|
||||
|
||||
|
||||
FLACFrameHeader_t *FLACFrameHeader;
|
||||
FLACMetadataBlock_t *FLACMetadataBlock;
|
||||
FLACsubFramesBuff_t *FLACsubFramesBuff;
|
||||
|
||||
vector<int32_t>coefs;
|
||||
const uint16_t outBuffSize = 2048;
|
||||
uint16_t m_blockSize=0;
|
||||
uint16_t m_blockSizeLeft = 0;
|
||||
uint16_t m_validSamples = 0;
|
||||
uint8_t m_status = 0;
|
||||
uint8_t* m_inptr;
|
||||
int16_t m_bytesAvail;
|
||||
int16_t m_bytesDecoded = 0;
|
||||
float m_compressionRatio = 0;
|
||||
uint16_t m_rIndex=0;
|
||||
uint64_t m_bitBuffer = 0;
|
||||
uint8_t m_bitBufferLen = 0;
|
||||
bool m_f_OggS_found = false;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// FLAC INI SECTION
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
bool FLACDecoder_AllocateBuffers(void){
|
||||
if(psramFound()) {
|
||||
// PSRAM found, Buffer will be allocated in PSRAM
|
||||
if(!FLACFrameHeader) {FLACFrameHeader = (FLACFrameHeader_t*) ps_malloc(sizeof(FLACFrameHeader_t));}
|
||||
if(!FLACMetadataBlock) {FLACMetadataBlock = (FLACMetadataBlock_t*) ps_malloc(sizeof(FLACMetadataBlock_t));}
|
||||
if(!FLACsubFramesBuff) {FLACsubFramesBuff = (FLACsubFramesBuff_t*) ps_malloc(sizeof(FLACsubFramesBuff_t));}
|
||||
}
|
||||
else {
|
||||
if(!FLACFrameHeader) {FLACFrameHeader = (FLACFrameHeader_t*) malloc(sizeof(FLACFrameHeader_t));}
|
||||
if(!FLACMetadataBlock) {FLACMetadataBlock = (FLACMetadataBlock_t*) malloc(sizeof(FLACMetadataBlock_t));}
|
||||
if(!FLACsubFramesBuff) {FLACsubFramesBuff = (FLACsubFramesBuff_t*) malloc(sizeof(FLACsubFramesBuff_t));}
|
||||
}
|
||||
if(!FLACFrameHeader || !FLACMetadataBlock || !FLACsubFramesBuff ){
|
||||
log_e("not enough memory to allocate flacdecoder buffers");
|
||||
return false;
|
||||
}
|
||||
FLACDecoder_ClearBuffer();
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void FLACDecoder_ClearBuffer(){
|
||||
memset(FLACFrameHeader, 0, sizeof(FLACFrameHeader_t));
|
||||
memset(FLACMetadataBlock, 0, sizeof(FLACMetadataBlock_t));
|
||||
memset(FLACsubFramesBuff, 0, sizeof(FLACsubFramesBuff_t));
|
||||
m_status = DECODE_FRAME;
|
||||
return;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void FLACDecoder_FreeBuffers(){
|
||||
if(FLACFrameHeader) {free(FLACFrameHeader); FLACFrameHeader = NULL;}
|
||||
if(FLACMetadataBlock) {free(FLACMetadataBlock); FLACMetadataBlock = NULL;}
|
||||
if(FLACsubFramesBuff) {free(FLACsubFramesBuff); FLACsubFramesBuff = NULL;}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// B I T R E A D E R
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
uint32_t readUint(uint8_t nBits){
|
||||
while (m_bitBufferLen < nBits){
|
||||
uint8_t temp = *(m_inptr + m_rIndex);
|
||||
m_rIndex++;
|
||||
m_bytesAvail--;
|
||||
if(m_bytesAvail < 0) { log_i("error in bitreader"); }
|
||||
m_bitBuffer = (m_bitBuffer << 8) | temp;
|
||||
m_bitBufferLen += 8;
|
||||
}
|
||||
m_bitBufferLen -= nBits;
|
||||
uint32_t result = m_bitBuffer >> m_bitBufferLen;
|
||||
if (nBits < 32)
|
||||
result &= (1 << nBits) - 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t readSignedInt(int nBits){
|
||||
int32_t temp = readUint(nBits) << (32 - nBits);
|
||||
temp = temp >> (32 - nBits); // The C++ compiler uses the sign bit to fill vacated bit positions
|
||||
return temp;
|
||||
}
|
||||
|
||||
int64_t readRiceSignedInt(uint8_t param){
|
||||
long val = 0;
|
||||
while (readUint(1) == 0)
|
||||
val++;
|
||||
val = (val << param) | readUint(param);
|
||||
return (val >> 1) ^ -(val & 1);
|
||||
}
|
||||
|
||||
void alignToByte() {
|
||||
m_bitBufferLen -= m_bitBufferLen % 8;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// F L A C - D E C O D E R
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void FLACSetRawBlockParams(uint8_t Chans, uint32_t SampRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength){
|
||||
FLACMetadataBlock->numChannels = Chans;
|
||||
FLACMetadataBlock->sampleRate = SampRate;
|
||||
FLACMetadataBlock->bitsPerSample = BPS;
|
||||
FLACMetadataBlock->totalSamples = tsis; // total samples in stream
|
||||
FLACMetadataBlock->audioDataLength = AuDaLength;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void FLACDecoderReset(){ // set var to default
|
||||
m_status = DECODE_FRAME;
|
||||
m_bitBuffer = 0;
|
||||
m_bitBufferLen = 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
int FLACFindSyncWord(unsigned char *buf, int nBytes) {
|
||||
int i;
|
||||
|
||||
/* find byte-aligned syncword - need 13 matching bits */
|
||||
for (i = 0; i < nBytes - 1; i++) {
|
||||
if ((buf[i + 0] & 0xFF) == 0xFF && (buf[i + 1] & 0xF8) == 0xF8) {
|
||||
FLACDecoderReset();
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
int FLACFindOggSyncWord(unsigned char *buf, int nBytes){
|
||||
int i;
|
||||
|
||||
/* find byte-aligned syncword - need 13 matching bits */
|
||||
for (i = 0; i < nBytes - 1; i++) {
|
||||
if ((buf[i + 0] & 0xFF) == 0xFF && (buf[i + 1] & 0xF8) == 0xF8) {
|
||||
FLACDecoderReset();
|
||||
log_i("FLAC sync found");
|
||||
return i;
|
||||
}
|
||||
}
|
||||
/* find byte-aligned OGG Magic - OggS */
|
||||
for (i = 0; i < nBytes - 1; i++) {
|
||||
if ((buf[i + 0] == 'O') && (buf[i + 1] == 'g') && (buf[i + 2] == 'g') && (buf[i + 3] == 'S')) {
|
||||
FLACDecoderReset();
|
||||
log_i("OggS found");
|
||||
m_f_OggS_found = true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
int FLACparseOggHeader(unsigned char *buf){
|
||||
uint8_t i = 0;
|
||||
uint8_t ssv = *(buf + i); // stream_structure_version
|
||||
(void)ssv;
|
||||
i++;
|
||||
uint8_t htf = *(buf + i); // header_type_flag
|
||||
(void)htf;
|
||||
i++;
|
||||
uint32_t tmp = 0; // absolute granule position
|
||||
for (int j = 0; j < 4; j++) {
|
||||
tmp += *(buf + j + i) << (4 -j - 1) * 8;
|
||||
}
|
||||
i += 4;
|
||||
uint64_t agp = (uint64_t) tmp << 32;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
agp += *(buf + j + i) << (4 -j - 1) * 8;
|
||||
}
|
||||
i += 4;
|
||||
uint32_t ssnr = 0; // stream serial number
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ssnr += *(buf + j + i) << (4 -j - 1) * 8;
|
||||
}
|
||||
i += 4;
|
||||
uint32_t psnr = 0; // page sequence no
|
||||
for (int j = 0; j < 4; j++) {
|
||||
psnr += *(buf + j + i) << (4 -j - 1) * 8;
|
||||
}
|
||||
i += 4;
|
||||
uint32_t pchk = 0; // page checksum
|
||||
for (int j = 0; j < 4; j++) {
|
||||
pchk += *(buf + j + i) << (4 -j - 1) * 8;
|
||||
}
|
||||
i += 4;
|
||||
uint8_t psegm = *(buf + i);
|
||||
i++;
|
||||
uint8_t psegmBuff[256];
|
||||
uint32_t pageLen = 0;
|
||||
for(uint8_t j = 0; j < psegm; j++){
|
||||
psegmBuff[j] = *(buf + i);
|
||||
pageLen += psegmBuff[j];
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
int8_t FLACDecode(uint8_t *inbuf, int *bytesLeft, short *outbuf){
|
||||
|
||||
if(m_f_OggS_found == true){
|
||||
m_f_OggS_found = false;
|
||||
*bytesLeft -= FLACparseOggHeader(inbuf);
|
||||
return ERR_FLAC_NONE;
|
||||
}
|
||||
|
||||
if(m_status != OUT_SAMPLES){
|
||||
m_rIndex = 0;
|
||||
m_bytesAvail = (*bytesLeft);
|
||||
m_inptr = inbuf;
|
||||
}
|
||||
|
||||
if(m_status == DECODE_FRAME){ // Read a ton of header fields, and ignore most of them
|
||||
|
||||
if ((inbuf[0] == 'O') && (inbuf[1] == 'g') && (inbuf[2] == 'g') && (inbuf[3] == 'S')){
|
||||
*bytesLeft -= 4;
|
||||
m_f_OggS_found = true;
|
||||
return ERR_FLAC_NONE;
|
||||
}
|
||||
|
||||
uint32_t temp = readUint(8);
|
||||
uint16_t sync = temp << 6 |readUint(6);
|
||||
if (sync != 0x3FFE){
|
||||
log_i("Sync code expected 0x3FFE but received %X", sync);
|
||||
return ERR_FLAC_SYNC_CODE_NOT_FOUND;
|
||||
}
|
||||
|
||||
readUint(1);
|
||||
FLACFrameHeader->blockingStrategy = readUint(1);
|
||||
FLACFrameHeader->blockSizeCode = readUint(4);
|
||||
FLACFrameHeader->sampleRateCode = readUint(4);
|
||||
FLACFrameHeader->chanAsgn = readUint(4);
|
||||
FLACFrameHeader->sampleSizeCode = readUint(3);
|
||||
|
||||
if(!FLACMetadataBlock->numChannels){
|
||||
if(FLACFrameHeader->chanAsgn == 0) FLACMetadataBlock->numChannels = 1;
|
||||
if(FLACFrameHeader->chanAsgn == 1) FLACMetadataBlock->numChannels = 2;
|
||||
if(FLACFrameHeader->chanAsgn > 7) FLACMetadataBlock->numChannels = 2;
|
||||
}
|
||||
if(FLACMetadataBlock->numChannels < 1) return ERR_FLAC_UNKNOWN_CHANNEL_ASSIGNMENT;
|
||||
|
||||
if(!FLACMetadataBlock->bitsPerSample){
|
||||
if(FLACFrameHeader->sampleSizeCode == 1) FLACMetadataBlock->bitsPerSample = 8;
|
||||
if(FLACFrameHeader->sampleSizeCode == 2) FLACMetadataBlock->bitsPerSample = 12;
|
||||
if(FLACFrameHeader->sampleSizeCode == 4) FLACMetadataBlock->bitsPerSample = 16;
|
||||
if(FLACFrameHeader->sampleSizeCode == 5) FLACMetadataBlock->bitsPerSample = 20;
|
||||
if(FLACFrameHeader->sampleSizeCode == 6) FLACMetadataBlock->bitsPerSample = 24;
|
||||
}
|
||||
if(FLACMetadataBlock->bitsPerSample > 16) return ERR_FLAC_BITS_PER_SAMPLE_TOO_BIG;
|
||||
if(FLACMetadataBlock->bitsPerSample < 8 ) return ERR_FLAG_BITS_PER_SAMPLE_UNKNOWN;
|
||||
|
||||
if(!FLACMetadataBlock->sampleRate){
|
||||
if(FLACFrameHeader->sampleRateCode == 1) FLACMetadataBlock->sampleRate = 88200;
|
||||
if(FLACFrameHeader->sampleRateCode == 2) FLACMetadataBlock->sampleRate = 176400;
|
||||
if(FLACFrameHeader->sampleRateCode == 3) FLACMetadataBlock->sampleRate = 192000;
|
||||
if(FLACFrameHeader->sampleRateCode == 4) FLACMetadataBlock->sampleRate = 8000;
|
||||
if(FLACFrameHeader->sampleRateCode == 5) FLACMetadataBlock->sampleRate = 16000;
|
||||
if(FLACFrameHeader->sampleRateCode == 6) FLACMetadataBlock->sampleRate = 22050;
|
||||
if(FLACFrameHeader->sampleRateCode == 7) FLACMetadataBlock->sampleRate = 24000;
|
||||
if(FLACFrameHeader->sampleRateCode == 8) FLACMetadataBlock->sampleRate = 32000;
|
||||
if(FLACFrameHeader->sampleRateCode == 9) FLACMetadataBlock->sampleRate = 44100;
|
||||
if(FLACFrameHeader->sampleRateCode == 10) FLACMetadataBlock->sampleRate = 48000;
|
||||
if(FLACFrameHeader->sampleRateCode == 11) FLACMetadataBlock->sampleRate = 96000;
|
||||
}
|
||||
|
||||
readUint(1);
|
||||
temp = (readUint(8) << 24);
|
||||
temp = ~temp;
|
||||
|
||||
uint32_t shift = 0x80000000; // Number of leading zeros
|
||||
int8_t count = 0;
|
||||
for(int i=0; i<32; i++){
|
||||
if((temp & shift) == 0) {count++; shift >>= 1;}
|
||||
else break;
|
||||
}
|
||||
count--;
|
||||
for (int i = 0; i < count; i++) readUint(8);
|
||||
m_blockSize = 0;
|
||||
|
||||
if (FLACFrameHeader->blockSizeCode == 1)
|
||||
m_blockSize = 192;
|
||||
else if (2 <= FLACFrameHeader->blockSizeCode && FLACFrameHeader->blockSizeCode <= 5)
|
||||
m_blockSize = 576 << (FLACFrameHeader->blockSizeCode - 2);
|
||||
else if (FLACFrameHeader->blockSizeCode == 6)
|
||||
m_blockSize = readUint(8) + 1;
|
||||
else if (FLACFrameHeader->blockSizeCode == 7)
|
||||
m_blockSize = readUint(16) + 1;
|
||||
else if (8 <= FLACFrameHeader->blockSizeCode && FLACFrameHeader->blockSizeCode <= 15)
|
||||
m_blockSize = 256 << (FLACFrameHeader->blockSizeCode - 8);
|
||||
else{
|
||||
return ERR_FLAC_RESERVED_BLOCKSIZE_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if(m_blockSize > 8192){
|
||||
log_e("Error: blockSize too big");
|
||||
return ERR_FLAC_BLOCKSIZE_TOO_BIG;
|
||||
}
|
||||
|
||||
if(FLACFrameHeader->sampleRateCode == 12)
|
||||
readUint(8);
|
||||
else if (FLACFrameHeader->sampleRateCode == 13 || FLACFrameHeader->sampleRateCode == 14){
|
||||
readUint(16);
|
||||
}
|
||||
readUint(8);
|
||||
m_status = DECODE_SUBFRAMES;
|
||||
*bytesLeft = m_bytesAvail;
|
||||
m_blockSizeLeft = m_blockSize;
|
||||
|
||||
return ERR_FLAC_NONE;
|
||||
}
|
||||
|
||||
if(m_status == DECODE_SUBFRAMES){
|
||||
|
||||
// Decode each channel's subframe, then skip footer
|
||||
int ret = decodeSubframes();
|
||||
if(ret != 0) return ret;
|
||||
m_status = OUT_SAMPLES;
|
||||
}
|
||||
|
||||
if(m_status == OUT_SAMPLES){ // Write the decoded samples
|
||||
// blocksize can be much greater than outbuff, so we can't stuff all in once
|
||||
// therefore we need often more than one loop (split outputblock into pieces)
|
||||
uint16_t blockSize;
|
||||
static uint16_t offset = 0;
|
||||
if(m_blockSize < outBuffSize + offset) blockSize = m_blockSize - offset;
|
||||
else blockSize = outBuffSize;
|
||||
|
||||
|
||||
for (int i = 0; i < blockSize; i++) {
|
||||
for (int j = 0; j < FLACMetadataBlock->numChannels; j++) {
|
||||
int val = FLACsubFramesBuff->samplesBuffer[j][i + offset];
|
||||
if (FLACMetadataBlock->bitsPerSample == 8) val += 128;
|
||||
outbuf[2*i+j] = val;
|
||||
}
|
||||
}
|
||||
|
||||
m_validSamples = blockSize * FLACMetadataBlock->numChannels;
|
||||
offset += blockSize;
|
||||
|
||||
if(offset != m_blockSize) return GIVE_NEXT_LOOP;
|
||||
offset = 0;
|
||||
if(offset > m_blockSize) { log_e("offset has a wrong value"); }
|
||||
}
|
||||
|
||||
alignToByte();
|
||||
readUint(16);
|
||||
m_bytesDecoded = *bytesLeft - m_bytesAvail;
|
||||
// log_i("m_bytesDecoded %i", m_bytesDecoded);
|
||||
// m_compressionRatio = (float)m_bytesDecoded / (float)m_blockSize * FLACMetadataBlock->numChannels * (16/8);
|
||||
// log_i("m_compressionRatio % f", m_compressionRatio);
|
||||
*bytesLeft = m_bytesAvail;
|
||||
m_status = DECODE_FRAME;
|
||||
return ERR_FLAC_NONE;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
uint16_t FLACGetOutputSamps(){
|
||||
int vs = m_validSamples;
|
||||
m_validSamples=0;
|
||||
return vs;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
uint64_t FLACGetTotoalSamplesInStream(){
|
||||
return FLACMetadataBlock->totalSamples;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
uint8_t FLACGetBitsPerSample(){
|
||||
return FLACMetadataBlock->bitsPerSample;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
uint8_t FLACGetChannels(){
|
||||
return FLACMetadataBlock->numChannels;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
uint32_t FLACGetSampRate(){
|
||||
return FLACMetadataBlock->sampleRate;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
uint32_t FLACGetBitRate(){
|
||||
if(FLACMetadataBlock->totalSamples){
|
||||
float BitsPerSamp = (float)FLACMetadataBlock->audioDataLength / (float)FLACMetadataBlock->totalSamples * 8;
|
||||
return ((uint32_t)BitsPerSamp * FLACMetadataBlock->sampleRate);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
uint32_t FLACGetAudioFileDuration() {
|
||||
if(FLACGetSampRate()){
|
||||
uint32_t afd = FLACGetTotoalSamplesInStream()/ FLACGetSampRate(); // AudioFileDuration
|
||||
return afd;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
int8_t decodeSubframes(){
|
||||
if(FLACFrameHeader->chanAsgn <= 7) {
|
||||
for (int ch = 0; ch < FLACMetadataBlock->numChannels; ch++)
|
||||
decodeSubframe(FLACMetadataBlock->bitsPerSample, ch);
|
||||
}
|
||||
else if (8 <= FLACFrameHeader->chanAsgn && FLACFrameHeader->chanAsgn <= 10) {
|
||||
decodeSubframe(FLACMetadataBlock->bitsPerSample + (FLACFrameHeader->chanAsgn == 9 ? 1 : 0), 0);
|
||||
decodeSubframe(FLACMetadataBlock->bitsPerSample + (FLACFrameHeader->chanAsgn == 9 ? 0 : 1), 1);
|
||||
if(FLACFrameHeader->chanAsgn == 8) {
|
||||
for (int i = 0; i < m_blockSize; i++)
|
||||
FLACsubFramesBuff->samplesBuffer[1][i] = (
|
||||
FLACsubFramesBuff->samplesBuffer[0][i] -
|
||||
FLACsubFramesBuff->samplesBuffer[1][i]);
|
||||
}
|
||||
else if (FLACFrameHeader->chanAsgn == 9) {
|
||||
for (int i = 0; i < m_blockSize; i++)
|
||||
FLACsubFramesBuff->samplesBuffer[0][i] += FLACsubFramesBuff->samplesBuffer[1][i];
|
||||
}
|
||||
else if (FLACFrameHeader->chanAsgn == 10) {
|
||||
for (int i = 0; i < m_blockSize; i++) {
|
||||
long side = FLACsubFramesBuff->samplesBuffer[1][i];
|
||||
long right = FLACsubFramesBuff->samplesBuffer[0][i] - (side >> 1);
|
||||
FLACsubFramesBuff->samplesBuffer[1][i] = right;
|
||||
FLACsubFramesBuff->samplesBuffer[0][i] = right + side;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log_e("unknown channel assignment");
|
||||
return ERR_FLAC_UNKNOWN_CHANNEL_ASSIGNMENT;
|
||||
}
|
||||
}
|
||||
else{
|
||||
log_e("Reserved channel assignment");
|
||||
return ERR_FLAC_RESERVED_CHANNEL_ASSIGNMENT;
|
||||
}
|
||||
return ERR_FLAC_NONE;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
int8_t decodeSubframe(uint8_t sampleDepth, uint8_t ch) {
|
||||
int8_t ret = 0;
|
||||
readUint(1);
|
||||
uint8_t type = readUint(6);
|
||||
int shift = readUint(1);
|
||||
if (shift == 1) {
|
||||
while (readUint(1) == 0)
|
||||
shift++;
|
||||
}
|
||||
sampleDepth -= shift;
|
||||
|
||||
if(type == 0){ // Constant coding
|
||||
int16_t s= readSignedInt(sampleDepth);
|
||||
for(int i=0; i < m_blockSize; i++){
|
||||
FLACsubFramesBuff->samplesBuffer[ch][i] = s;
|
||||
}
|
||||
}
|
||||
else if (type == 1) { // Verbatim coding
|
||||
for (int i = 0; i < m_blockSize; i++)
|
||||
FLACsubFramesBuff->samplesBuffer[ch][i] = readSignedInt(sampleDepth);
|
||||
}
|
||||
else if (8 <= type && type <= 12){
|
||||
ret = decodeFixedPredictionSubframe(type - 8, sampleDepth, ch);
|
||||
if(ret) return ret;
|
||||
}
|
||||
else if (32 <= type && type <= 63){
|
||||
ret = decodeLinearPredictiveCodingSubframe(type - 31, sampleDepth, ch);
|
||||
if(ret) return ret;
|
||||
}
|
||||
else{
|
||||
return ERR_FLAC_RESERVED_SUB_TYPE;
|
||||
}
|
||||
if(shift>0){
|
||||
for (int i = 0; i < m_blockSize; i++){
|
||||
FLACsubFramesBuff->samplesBuffer[ch][i] <<= shift;
|
||||
}
|
||||
}
|
||||
return ERR_FLAC_NONE;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
int8_t decodeFixedPredictionSubframe(uint8_t predOrder, uint8_t sampleDepth, uint8_t ch) {
|
||||
uint8_t ret = 0;
|
||||
for(uint8_t i = 0; i < predOrder; i++)
|
||||
FLACsubFramesBuff->samplesBuffer[ch][i] = readSignedInt(sampleDepth);
|
||||
ret = decodeResiduals(predOrder, ch);
|
||||
if(ret) return ret;
|
||||
coefs.clear();
|
||||
if(predOrder == 0) coefs.resize(0);
|
||||
if(predOrder == 1) coefs.push_back(1); // FIXED_PREDICTION_COEFFICIENTS
|
||||
if(predOrder == 2){coefs.push_back(2); coefs.push_back(-1);}
|
||||
if(predOrder == 3){coefs.push_back(3); coefs.push_back(-3); coefs.push_back(1);}
|
||||
if(predOrder == 4){coefs.push_back(4); coefs.push_back(-6); coefs.push_back(4); coefs.push_back(-1);}
|
||||
if(predOrder > 4) return ERR_FLAC_PREORDER_TOO_BIG; // Error: preorder > 4"
|
||||
restoreLinearPrediction(ch, 0);
|
||||
return ERR_FLAC_NONE;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
int8_t decodeLinearPredictiveCodingSubframe(int lpcOrder, int sampleDepth, uint8_t ch){
|
||||
int8_t ret = 0;
|
||||
for (int i = 0; i < lpcOrder; i++)
|
||||
FLACsubFramesBuff->samplesBuffer[ch][i] = readSignedInt(sampleDepth);
|
||||
int precision = readUint(4) + 1;
|
||||
int shift = readSignedInt(5);
|
||||
coefs.resize(0);
|
||||
for (uint8_t i = 0; i < lpcOrder; i++)
|
||||
coefs.push_back(readSignedInt(precision));
|
||||
ret = decodeResiduals(lpcOrder, ch);
|
||||
if(ret) return ret;
|
||||
restoreLinearPrediction(ch, shift);
|
||||
return ERR_FLAC_NONE;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
int8_t decodeResiduals(uint8_t warmup, uint8_t ch) {
|
||||
|
||||
int method = readUint(2);
|
||||
if (method >= 2)
|
||||
return ERR_FLAC_RESERVED_RESIDUAL_CODING; // Reserved residual coding method
|
||||
uint8_t paramBits = method == 0 ? 4 : 5;
|
||||
int escapeParam = (method == 0 ? 0xF : 0x1F);
|
||||
int partitionOrder = readUint(4);
|
||||
|
||||
int numPartitions = 1 << partitionOrder;
|
||||
if (m_blockSize % numPartitions != 0)
|
||||
return ERR_FLAC_WRONG_RICE_PARTITION_NR; //Error: Block size not divisible by number of Rice partitions
|
||||
int partitionSize = m_blockSize/ numPartitions;
|
||||
|
||||
for (int i = 0; i < numPartitions; i++) {
|
||||
int start = i * partitionSize + (i == 0 ? warmup : 0);
|
||||
int end = (i + 1) * partitionSize;
|
||||
|
||||
int param = readUint(paramBits);
|
||||
if (param < escapeParam) {
|
||||
for (int j = start; j < end; j++){
|
||||
FLACsubFramesBuff->samplesBuffer[ch][j] = readRiceSignedInt(param);
|
||||
}
|
||||
} else {
|
||||
int numBits = readUint(5);
|
||||
for (int j = start; j < end; j++){
|
||||
FLACsubFramesBuff->samplesBuffer[ch][j] = readSignedInt(numBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ERR_FLAC_NONE;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void restoreLinearPrediction(uint8_t ch, uint8_t shift) {
|
||||
|
||||
for (int i = coefs.size(); i < m_blockSize; i++) {
|
||||
int32_t sum = 0;
|
||||
for (int j = 0; j < coefs.size(); j++){
|
||||
sum += FLACsubFramesBuff->samplesBuffer[ch][i - 1 - j] * coefs[j];
|
||||
}
|
||||
FLACsubFramesBuff->samplesBuffer[ch][i] += (sum >> shift);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
175
yoRadio/src/audioI2S/flac_decoder/flac_decoder.h
Normal file
175
yoRadio/src/audioI2S/flac_decoder/flac_decoder.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* flac_decoder.h
|
||||
*
|
||||
* Created on: Jul 03,2020
|
||||
* Updated on: Apr 27,2021
|
||||
*
|
||||
* Author: wolle
|
||||
*
|
||||
* Restrictions:
|
||||
* blocksize must not exceed 8192
|
||||
* bits per sample must be 8 or 16
|
||||
* num Channels must be 1 or 2
|
||||
*
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#pragma GCC optimize ("Ofast")
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#define MAX_CHANNELS 2
|
||||
#define MAX_BLOCKSIZE 8192
|
||||
#define APLL_DISABLE 0
|
||||
#define EXTERNAL_I2S 0
|
||||
|
||||
|
||||
typedef struct FLACsubFramesBuff_t{
|
||||
int32_t samplesBuffer[MAX_CHANNELS][MAX_BLOCKSIZE];
|
||||
}FLACsubframesBuffer_t;
|
||||
|
||||
enum : uint8_t {FLACDECODER_INIT, FLACDECODER_READ_IN, FLACDECODER_WRITE_OUT};
|
||||
enum : uint8_t {DECODE_FRAME, DECODE_SUBFRAMES, OUT_SAMPLES};
|
||||
enum : int8_t {GIVE_NEXT_LOOP = +1,
|
||||
ERR_FLAC_NONE = 0,
|
||||
ERR_FLAC_BLOCKSIZE_TOO_BIG = -1,
|
||||
ERR_FLAC_RESERVED_BLOCKSIZE_UNSUPPORTED = -2,
|
||||
ERR_FLAC_SYNC_CODE_NOT_FOUND = -3,
|
||||
ERR_FLAC_UNKNOWN_CHANNEL_ASSIGNMENT = -4,
|
||||
ERR_FLAC_RESERVED_CHANNEL_ASSIGNMENT = -5,
|
||||
ERR_FLAC_RESERVED_SUB_TYPE = -6,
|
||||
ERR_FLAC_PREORDER_TOO_BIG = -7,
|
||||
ERR_FLAC_RESERVED_RESIDUAL_CODING = -8,
|
||||
ERR_FLAC_WRONG_RICE_PARTITION_NR = -9,
|
||||
ERR_FLAC_BITS_PER_SAMPLE_TOO_BIG = -10,
|
||||
ERR_FLAG_BITS_PER_SAMPLE_UNKNOWN = 11};
|
||||
|
||||
typedef struct FLACMetadataBlock_t{
|
||||
// METADATA_BLOCK_STREAMINFO
|
||||
uint16_t minblocksize; // The minimum block size (in samples) used in the stream.
|
||||
//----------------------------------------------------------------------------------------
|
||||
// The maximum block size (in samples) used in the stream.
|
||||
uint16_t maxblocksize; // (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream.
|
||||
//----------------------------------------------------------------------------------------
|
||||
// The minimum frame size (in bytes) used in the stream.
|
||||
uint32_t minframesize; // May be 0 to imply the value is not known.
|
||||
//----------------------------------------------------------------------------------------
|
||||
// The maximum frame size (in bytes) used in the stream.
|
||||
uint32_t maxframesize; // May be 0 to imply the value is not known.
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Sample rate in Hz. Though 20 bits are available,
|
||||
// the maximum sample rate is limited by the structure of frame headers to 655350Hz.
|
||||
uint32_t sampleRate; // Also, a value of 0 is invalid.
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Number of channels FLAC supports from 1 to 8 channels
|
||||
uint8_t numChannels; // 000 : 1 channel .... 111 : 8 channels
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Sample size in bits:
|
||||
// 000 : get from STREAMINFO metadata block
|
||||
// 001 : 8 bits per sample
|
||||
// 010 : 12 bits per sample
|
||||
// 011 : reserved
|
||||
// 100 : 16 bits per sample
|
||||
// 101 : 20 bits per sample
|
||||
// 110 : 24 bits per sample
|
||||
uint8_t bitsPerSample; // 111 : reserved
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Total samples in stream. 'Samples' means inter-channel sample,
|
||||
// i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number
|
||||
uint64_t totalSamples; // of channels. A value of zero here means the number of total samples is unknown.
|
||||
//----------------------------------------------------------------------------------------
|
||||
uint32_t audioDataLength;// is not the filelength, is only the length of the audio datablock in bytes
|
||||
|
||||
|
||||
|
||||
}FLACMetadataBlock_t;
|
||||
|
||||
|
||||
typedef struct FLACFrameHeader_t {
|
||||
// 0 : fixed-blocksize stream; frame header encodes the frame number
|
||||
uint8_t blockingStrategy; // 1 : variable-blocksize stream; frame header encodes the sample number
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Block size in inter-channel samples:
|
||||
// 0000 : reserved
|
||||
// 0001 : 192 samples
|
||||
// 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608
|
||||
// 0110 : get 8 bit (blocksize-1) from end of header
|
||||
// 0111 : get 16 bit (blocksize-1) from end of header
|
||||
uint8_t blockSizeCode; // 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768
|
||||
//----------------------------------------------------------------------------------------
|
||||
// 0000 : get from STREAMINFO metadata block
|
||||
// 0001 : 88.2kHz
|
||||
// 0010 : 176.4kHz
|
||||
// 0011 : 192kHz
|
||||
// 0100 : 8kHz
|
||||
// 0101 : 16kHz
|
||||
// 0110 : 22.05kHz
|
||||
// 0111 : 24kHz
|
||||
// 1000 : 32kHz
|
||||
// 1001 : 44.1kHz
|
||||
// 1010 : 48kHz
|
||||
// 1011 : 96kHz
|
||||
// 1100 : get 8 bit sample rate (in kHz) from end of header
|
||||
// 1101 : get 16 bit sample rate (in Hz) from end of header
|
||||
// 1110 : get 16 bit sample rate (in tens of Hz) from end of header
|
||||
uint8_t sampleRateCode; // 1111 : invalid, to prevent sync-fooling string of 1s
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Channel assignment
|
||||
// 0000 1 channel: mono
|
||||
// 0001 2 channels: left, right
|
||||
// 0010 3 channels
|
||||
// 0011 4 channels
|
||||
// 0100 5 channels
|
||||
// 0101 6 channels
|
||||
// 0110 7 channels
|
||||
// 0111 8 channels
|
||||
// 1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel
|
||||
// 1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel
|
||||
// 1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel
|
||||
uint8_t chanAsgn; // 1011-1111 : reserved
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Sample size in bits:
|
||||
// 000 : get from STREAMINFO metadata block
|
||||
// 001 : 8 bits per sample
|
||||
// 010 : 12 bits per sample
|
||||
// 011 : reserved
|
||||
// 100 : 16 bits per sample
|
||||
// 101 : 20 bits per sample
|
||||
// 110 : 24 bits per sample
|
||||
uint8_t sampleSizeCode; // 111 : reserved
|
||||
//----------------------------------------------------------------------------------------
|
||||
uint32_t totalSamples; // totalSamplesInStream
|
||||
//----------------------------------------------------------------------------------------
|
||||
uint32_t bitrate; // bitrate
|
||||
|
||||
|
||||
}FLACFrameHeader_t;
|
||||
|
||||
int FLACFindSyncWord(unsigned char *buf, int nBytes);
|
||||
int FLACFindOggSyncWord(unsigned char *buf, int nBytes);
|
||||
int FLACparseOggHeader(unsigned char *buf);
|
||||
bool FLACDecoder_AllocateBuffers(void);
|
||||
void FLACDecoder_ClearBuffer();
|
||||
void FLACDecoder_FreeBuffers();
|
||||
void FLACSetRawBlockParams(uint8_t Chans, uint32_t SampRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength);
|
||||
void FLACDecoderReset();
|
||||
int8_t FLACDecode(uint8_t *inbuf, int *bytesLeft, short *outbuf);
|
||||
uint16_t FLACGetOutputSamps();
|
||||
uint64_t FLACGetTotoalSamplesInStream();
|
||||
uint8_t FLACGetBitsPerSample();
|
||||
uint8_t FLACGetChannels();
|
||||
uint32_t FLACGetSampRate();
|
||||
uint32_t FLACGetBitRate();
|
||||
uint32_t FLACGetAudioFileDuration();
|
||||
uint32_t readUint(uint8_t nBits);
|
||||
int32_t readSignedInt(int nBits);
|
||||
int64_t readRiceSignedInt(uint8_t param);
|
||||
void alignToByte();
|
||||
int8_t decodeSubframes();
|
||||
int8_t decodeSubframe(uint8_t sampleDepth, uint8_t ch);
|
||||
int8_t decodeFixedPredictionSubframe(uint8_t predOrder, uint8_t sampleDepth, uint8_t ch);
|
||||
int8_t decodeLinearPredictiveCodingSubframe(int lpcOrder, int sampleDepth, uint8_t ch);
|
||||
int8_t decodeResiduals(uint8_t warmup, uint8_t ch);
|
||||
void restoreLinearPrediction(uint8_t ch, uint8_t shift);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user