code upload
This commit is contained in:
4538
yoRadio/src/audioI2S/Audio.cpp
Normal file
4538
yoRadio/src/audioI2S/Audio.cpp
Normal file
File diff suppressed because it is too large
Load Diff
480
yoRadio/src/audioI2S/AudioEx.h
Normal file
480
yoRadio/src/audioI2S/AudioEx.h
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* Audio.h
|
||||
*
|
||||
* Created on: Oct 26,2018
|
||||
* Updated on: Jan 05,2022
|
||||
* Author: Wolle (schreibfaul1)
|
||||
*/
|
||||
|
||||
//#define SDFATFS_USED // activate for SdFat
|
||||
|
||||
|
||||
#pragma once
|
||||
#pragma GCC optimize ("Ofast")
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <libb64/cencode.h>
|
||||
#include <SPI.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
#include <driver/i2s.h>
|
||||
|
||||
#ifdef SDFATFS_USED
|
||||
#include <SdFat.h> // https://github.com/greiman/SdFat
|
||||
#else
|
||||
#include <SD.h>
|
||||
#include <SD_MMC.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <FS.h>
|
||||
#include <FFat.h>
|
||||
#endif // SDFATFS_USED
|
||||
|
||||
#define AUDIOBUFFER_MULTIPLIER 13
|
||||
|
||||
#ifdef SDFATFS_USED
|
||||
typedef File32 File;
|
||||
|
||||
namespace fs {
|
||||
class FS : public SdFat {
|
||||
public:
|
||||
bool begin(SdCsPin_t csPin = SS, uint32_t maxSck = SD_SCK_MHZ(25)) { return SdFat::begin(csPin, maxSck); }
|
||||
};
|
||||
|
||||
class SDFATFS : public fs::FS {
|
||||
public:
|
||||
// sdcard_type_t cardType();
|
||||
uint64_t cardSize() {
|
||||
return totalBytes();
|
||||
}
|
||||
uint64_t usedBytes() {
|
||||
// set SdFatConfig MAINTAIN_FREE_CLUSTER_COUNT non-zero. Then only the first call will take time.
|
||||
return (uint64_t)(clusterCount() - freeClusterCount()) * (uint64_t)bytesPerCluster();
|
||||
}
|
||||
uint64_t totalBytes() {
|
||||
return (uint64_t)clusterCount() * (uint64_t)bytesPerCluster();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
extern fs::SDFATFS SD_SDFAT;
|
||||
|
||||
using namespace fs;
|
||||
#define SD SD_SDFAT
|
||||
#endif //SDFATFS_USED
|
||||
|
||||
|
||||
|
||||
|
||||
extern __attribute__((weak)) void audio_info(const char*);
|
||||
extern __attribute__((weak)) void audio_id3data(const char*); //ID3 metadata
|
||||
extern __attribute__((weak)) void audio_id3image(File& file, const size_t pos, const size_t size); //ID3 metadata image
|
||||
extern __attribute__((weak)) void audio_eof_mp3(const char*); //end of mp3 file
|
||||
extern __attribute__((weak)) void audio_showstreamtitle(const char*);
|
||||
extern __attribute__((weak)) void audio_showstation(const char*);
|
||||
extern __attribute__((weak)) void audio_bitrate(const char*);
|
||||
extern __attribute__((weak)) void audio_commercial(const char*);
|
||||
extern __attribute__((weak)) void audio_icyurl(const char*);
|
||||
extern __attribute__((weak)) void audio_icydescription(const char*);
|
||||
extern __attribute__((weak)) void audio_lasthost(const char*);
|
||||
extern __attribute__((weak)) void audio_eof_speech(const char*);
|
||||
extern __attribute__((weak)) void audio_eof_stream(const char*); // The webstream comes to an end
|
||||
extern __attribute__((weak)) void audio_process_extern(int16_t* buff, uint16_t len, bool *continueI2S); // record audiodata or send via BT
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class AudioBuffer {
|
||||
// AudioBuffer will be allocated in PSRAM, If PSRAM not available or has not enough space AudioBuffer will be
|
||||
// allocated in FlashRAM with reduced size
|
||||
//
|
||||
// m_buffer m_readPtr m_writePtr m_endPtr
|
||||
// | |<------dataLength------->|<------ writeSpace ----->|
|
||||
// ▼ ▼ ▼ ▼
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
// | <--m_buffSize--> | <--m_resBuffSize --> |
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
// |<-----freeSpace------->| |<------freeSpace-------->|
|
||||
//
|
||||
//
|
||||
//
|
||||
// if the space between m_readPtr and buffend < m_resBuffSize copy data from the beginning to resBuff
|
||||
// so that the mp3/aac/flac frame is always completed
|
||||
//
|
||||
// m_buffer m_writePtr m_readPtr m_endPtr
|
||||
// | |<-------writeSpace------>|<--dataLength-->|
|
||||
// ▼ ▼ ▼ ▼
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
// | <--m_buffSize--> | <--m_resBuffSize --> |
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
// |<--- ------dataLength-- ------>|<-------freeSpace------->|
|
||||
//
|
||||
//
|
||||
|
||||
public:
|
||||
AudioBuffer(size_t maxBlockSize = 0); // constructor
|
||||
~AudioBuffer(); // frees the buffer
|
||||
size_t init(); // set default values
|
||||
void changeMaxBlockSize(uint16_t mbs); // is default 1600 for mp3 and aac, set 16384 for FLAC
|
||||
uint16_t getMaxBlockSize(); // returns maxBlockSize
|
||||
size_t freeSpace(); // number of free bytes to overwrite
|
||||
size_t writeSpace(); // space fom writepointer to bufferend
|
||||
size_t bufferFilled(); // returns the number of filled bytes
|
||||
void bytesWritten(size_t bw); // update writepointer
|
||||
void bytesWasRead(size_t br); // update readpointer
|
||||
uint8_t* getWritePtr(); // returns the current writepointer
|
||||
uint8_t* getReadPtr(); // returns the current readpointer
|
||||
uint32_t getWritePos(); // write position relative to the beginning
|
||||
uint32_t getReadPos(); // read position relative to the beginning
|
||||
void resetBuffer(); // restore defaults
|
||||
|
||||
protected:
|
||||
const size_t m_buffSizePSRAM = 300000; // most webstreams limit the advance to 100...300Kbytes
|
||||
//const size_t m_buffSizeRAM = 1600 * 5 * AUDIOBUFFER_MULTIPLIER;
|
||||
const size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER;
|
||||
size_t m_buffSize = 0;
|
||||
size_t m_freeSpace = 0;
|
||||
size_t m_writeSpace = 0;
|
||||
size_t m_dataLength = 0;
|
||||
//size_t m_resBuffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER; // reserved buffspace, >= one mp3 frame
|
||||
size_t m_resBuffSizeRAM = 1600; // reserved buffspace, >= one mp3 frame
|
||||
size_t m_resBuffSizePSRAM = 4096 * 4; // reserved buffspace, >= one flac frame
|
||||
size_t m_maxBlockSize = 1600;
|
||||
uint8_t* m_buffer = NULL;
|
||||
uint8_t* m_writePtr = NULL;
|
||||
uint8_t* m_readPtr = NULL;
|
||||
uint8_t* m_endPtr = NULL;
|
||||
bool m_f_start = true;
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class Audio : private AudioBuffer{
|
||||
|
||||
AudioBuffer InBuff; // instance of input buffer
|
||||
|
||||
public:
|
||||
Audio(bool internalDAC = false, i2s_dac_mode_t channelEnabled = I2S_DAC_CHANNEL_LEFT_EN); // #99
|
||||
~Audio();
|
||||
bool connecttohost(const char* host, const char* user = "", const char* pwd = "");
|
||||
bool connecttospeech(const char* speech, const char* lang);
|
||||
bool connecttoFS(fs::FS &fs, const char* path);
|
||||
bool connecttoSD(const char* path);
|
||||
bool setFileLoop(bool input);//TEST loop
|
||||
bool setAudioPlayPosition(uint16_t sec);
|
||||
bool setFilePos(uint32_t pos);
|
||||
bool audioFileSeek(const float speed);
|
||||
bool setTimeOffset(int sec);
|
||||
bool setPinout(uint8_t BCLK, uint8_t LRC, uint8_t DOUT, int8_t DIN=I2S_PIN_NO_CHANGE);
|
||||
bool pauseResume();
|
||||
bool isRunning() {return m_f_running;}
|
||||
void loop();
|
||||
void stopSong();
|
||||
void forceMono(bool m);
|
||||
void setBalance(int8_t bal = 0);
|
||||
void setVolume(uint8_t vol);
|
||||
uint8_t getVolume();
|
||||
|
||||
uint32_t getAudioDataStartPos();
|
||||
uint32_t getFileSize();
|
||||
uint32_t getFilePos();
|
||||
uint32_t getSampleRate();
|
||||
uint8_t getBitsPerSample();
|
||||
uint8_t getChannels();
|
||||
uint32_t getBitRate();
|
||||
uint32_t getAudioFileDuration();
|
||||
uint32_t getAudioCurrentTime();
|
||||
uint32_t getTotalPlayingTime();
|
||||
|
||||
esp_err_t i2s_mclk_pin_select(const uint8_t pin);
|
||||
uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer
|
||||
uint32_t inBufferFree(); // returns the number of free bytes in the inputbuffer
|
||||
void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass);
|
||||
[[deprecated]]void setInternalDAC(bool internalDAC = true, i2s_dac_mode_t channelEnabled = I2S_DAC_CHANNEL_LEFT_EN);
|
||||
void setI2SCommFMT_LSB(bool commFMT);
|
||||
|
||||
private:
|
||||
void UTF8toASCII(char* str);
|
||||
bool latinToUTF8(char* buff, size_t bufflen);
|
||||
void httpPrint(const char* url);
|
||||
void setDefaults(); // free buffers and set defaults
|
||||
void initInBuff();
|
||||
void processLocalFile();
|
||||
void processWebStream();
|
||||
void processPlayListData();
|
||||
void processM3U8entries(uint8_t nrOfEntries = 0, uint32_t seqNr = 0, uint8_t pos = 0, uint16_t targetDuration = 0);
|
||||
bool STfromEXTINF(char* str);
|
||||
void showCodecParams();
|
||||
int findNextSync(uint8_t* data, size_t len);
|
||||
int sendBytes(uint8_t* data, size_t len);
|
||||
void compute_audioCurrentTime(int bd);
|
||||
void printDecodeError(int r);
|
||||
void showID3Tag(const char* tag, const char* val);
|
||||
void unicode2utf8(char* buff, uint32_t len);
|
||||
int read_WAV_Header(uint8_t* data, size_t len);
|
||||
int read_FLAC_Header(uint8_t *data, size_t len);
|
||||
int read_MP3_Header(uint8_t* data, size_t len);
|
||||
int read_M4A_Header(uint8_t* data, size_t len);
|
||||
int read_OGG_Header(uint8_t *data, size_t len);
|
||||
bool setSampleRate(uint32_t hz);
|
||||
bool setBitsPerSample(int bits);
|
||||
bool setChannels(int channels);
|
||||
bool setBitrate(int br);
|
||||
bool playChunk();
|
||||
bool playSample(int16_t sample[2]) ;
|
||||
bool playI2Sremains();
|
||||
int32_t Gain(int16_t s[2]);
|
||||
bool fill_InputBuf();
|
||||
void showstreamtitle(const char* ml);
|
||||
bool parseContentType(const char* ct);
|
||||
void processAudioHeaderData();
|
||||
bool readMetadata(uint8_t b, bool first = false);
|
||||
esp_err_t I2Sstart(uint8_t i2s_num);
|
||||
esp_err_t I2Sstop(uint8_t i2s_num);
|
||||
void urlencode(char* buff, uint16_t buffLen, bool spacesOnly = false);
|
||||
int16_t* IIR_filterChain0(int16_t iir_in[2], bool clear = false);
|
||||
int16_t* IIR_filterChain1(int16_t* iir_in, bool clear = false);
|
||||
int16_t* IIR_filterChain2(int16_t* iir_in, bool clear = false);
|
||||
inline void setDatamode(uint8_t dm){m_datamode=dm;}
|
||||
inline uint8_t getDatamode(){return m_datamode;}
|
||||
inline uint32_t streamavail() {if(m_f_ssl==false) return client.available(); else return clientsecure.available();}
|
||||
void IIR_calculateCoefficients(int8_t G1, int8_t G2, int8_t G3);
|
||||
|
||||
// implement several function with respect to the index of string
|
||||
void trim(char *s) {
|
||||
//fb trim in place
|
||||
char *pe;
|
||||
char *p = s;
|
||||
while ( isspace(*p) ) p++; //left
|
||||
pe = p; //right
|
||||
while ( *pe != '\0' ) pe++;
|
||||
do {
|
||||
pe--;
|
||||
} while ( (pe > p) && isspace(*pe) );
|
||||
if (p == s) {
|
||||
*++pe = '\0';
|
||||
} else { //move
|
||||
while ( p <= pe ) *s++ = *p++;
|
||||
*s = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
bool startsWith (const char* base, const char* str) {
|
||||
//fb
|
||||
char c;
|
||||
while ( (c = *str++) != '\0' )
|
||||
if (c != *base++) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool endsWith (const char* base, const char* str) {
|
||||
//fb
|
||||
int slen = strlen(str) - 1;
|
||||
const char *p = base + strlen(base) - 1;
|
||||
while(p > base && isspace(*p)) p--; // rtrim
|
||||
p -= slen;
|
||||
if (p < base) return false;
|
||||
return (strncmp(p, str, slen) == 0);
|
||||
}
|
||||
|
||||
int indexOf (const char* base, const char* str, int startIndex) {
|
||||
//fb
|
||||
const char *p = base;
|
||||
for (; startIndex > 0; startIndex--)
|
||||
if (*p++ == '\0') return -1;
|
||||
char* pos = strstr(p, str);
|
||||
if (pos == nullptr) return -1;
|
||||
return pos - base;
|
||||
}
|
||||
|
||||
int indexOf (const char* base, char ch, int startIndex) {
|
||||
//fb
|
||||
const char *p = base;
|
||||
for (; startIndex > 0; startIndex--)
|
||||
if (*p++ == '\0') return -1;
|
||||
char *pos = strchr(p, ch);
|
||||
if (pos == nullptr) return -1;
|
||||
return pos - base;
|
||||
}
|
||||
|
||||
int lastIndexOf(const char* haystack, const char* needle) {
|
||||
//fb
|
||||
int nlen = strlen(needle);
|
||||
if (nlen == 0) return -1;
|
||||
const char *p = haystack - nlen + strlen(haystack);
|
||||
while (p >= haystack) {
|
||||
int i = 0;
|
||||
while (needle[i] == p[i])
|
||||
if (++i == nlen) return p - haystack;
|
||||
p--;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lastIndexOf(const char* haystack, const char needle) {
|
||||
//fb
|
||||
const char *p = strrchr(haystack, needle);
|
||||
return (p ? p - haystack : -1);
|
||||
}
|
||||
|
||||
int specialIndexOf (uint8_t* base, const char* str, int baselen, bool exact = false){
|
||||
int result; // seek for str in buffer or in header up to baselen, not nullterninated
|
||||
if (strlen(str) > baselen) return -1; // if exact == true seekstr in buffer must have "\0" at the end
|
||||
for (int i = 0; i < baselen - strlen(str); i++){
|
||||
result = i;
|
||||
for (int j = 0; j < strlen(str) + exact; j++){
|
||||
if (*(base + i + j) != *(str + j)){
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result >= 0) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
size_t bigEndian(uint8_t* base, uint8_t numBytes, uint8_t shiftLeft = 8){
|
||||
size_t result = 0;
|
||||
if(numBytes < 1 or numBytes > 4) return 0;
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
result += *(base + i) << (numBytes -i - 1) * shiftLeft;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
bool b64encode(const char* source, uint16_t sourceLength, char* dest){
|
||||
size_t size = base64_encode_expected_len(sourceLength) + 1;
|
||||
char * buffer = (char *) malloc(size);
|
||||
if(buffer) {
|
||||
base64_encodestate _state;
|
||||
base64_init_encodestate(&_state);
|
||||
int len = base64_encode_block(&source[0], sourceLength, &buffer[0], &_state);
|
||||
len = base64_encode_blockend((buffer + len), &_state);
|
||||
memcpy(dest, buffer, strlen(buffer));
|
||||
dest[strlen(buffer)] = '\0';
|
||||
free(buffer);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
size_t urlencode_expected_len(const char* source){
|
||||
size_t expectedLen = strlen(source);
|
||||
for(int i = 0; i < strlen(source); i++) {
|
||||
if(isalnum(source[i])){;}
|
||||
else expectedLen += 2;
|
||||
}
|
||||
return expectedLen;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 };
|
||||
enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 };
|
||||
enum : int { CODEC_NONE, CODEC_WAV, CODEC_MP3, CODEC_AAC, CODEC_M4A, CODEC_FLAC, CODEC_OGG,
|
||||
CODEC_OGG_FLAC, CODEC_OGG_OPUS};
|
||||
enum : int { FORMAT_NONE = 0, FORMAT_M3U = 1, FORMAT_PLS = 2, FORMAT_ASX = 3, FORMAT_M3U8 = 4};
|
||||
enum : int { AUDIO_NONE, AUDIO_HEADER, AUDIO_DATA,
|
||||
AUDIO_PLAYLISTINIT, AUDIO_PLAYLISTHEADER, AUDIO_PLAYLISTDATA};
|
||||
enum : int { FLAC_BEGIN = 0, FLAC_MAGIC = 1, FLAC_MBH =2, FLAC_SINFO = 3, FLAC_PADDING = 4, FLAC_APP = 5,
|
||||
FLAC_SEEK = 6, FLAC_VORBIS = 7, FLAC_CUESHEET = 8, FLAC_PICTURE = 9, FLAC_OKAY = 100};
|
||||
enum : int { M4A_BEGIN = 0, M4A_FTYP = 1, M4A_CHK = 2, M4A_MOOV = 3, M4A_FREE = 4, M4A_TRAK = 5, M4A_MDAT = 6,
|
||||
M4A_ILST = 7, M4A_MP4A = 8, M4A_AMRDY = 99, M4A_OKAY = 100};
|
||||
enum : int { OGG_BEGIN = 0, OGG_MAGIC = 1, OGG_HEADER = 2, OGG_FIRST = 3, OGG_AMRDY = 99, OGG_OKAY = 100};
|
||||
typedef enum { LEFTCHANNEL=0, RIGHTCHANNEL=1 } SampleIndex;
|
||||
typedef enum { LOWSHELF = 0, PEAKEQ = 1, HIFGSHELF =2 } FilterType;
|
||||
|
||||
const uint8_t volumetable[22]={ 0, 1, 2, 3, 4 , 6 , 8, 10, 12, 14, 17,
|
||||
20, 23, 27, 30 ,34, 38, 43 ,48, 52, 58, 64}; //22 elements
|
||||
|
||||
typedef struct _filter{
|
||||
float a0;
|
||||
float a1;
|
||||
float a2;
|
||||
float b1;
|
||||
float b2;
|
||||
} filter_t;
|
||||
|
||||
File audiofile; // @suppress("Abstract class cannot be instantiated")
|
||||
WiFiClient client; // @suppress("Abstract class cannot be instantiated")
|
||||
WiFiClientSecure clientsecure; // @suppress("Abstract class cannot be instantiated")
|
||||
WiFiUDP udpclient; // @suppress("Abstract class cannot be instantiated")
|
||||
i2s_config_t m_i2s_config; // stores values for I2S driver
|
||||
i2s_pin_config_t m_pin_config;
|
||||
|
||||
const size_t m_frameSizeWav = 1600;
|
||||
const size_t m_frameSizeMP3 = 1600;
|
||||
const size_t m_frameSizeAAC = 1600;
|
||||
const size_t m_frameSizeFLAC = 4096 * 4;
|
||||
|
||||
char chbuf[512 + 128]; // must be greater than m_lastHost #254
|
||||
char m_lastHost[512]; // Store the last URL to a webstream
|
||||
char* m_playlistBuff = NULL; // stores playlistdata
|
||||
const uint16_t m_plsBuffEntryLen = 256; // length of each entry in playlistBuff
|
||||
filter_t m_filter[3]; // digital filters
|
||||
int m_LFcount = 0; // Detection of end of header
|
||||
uint32_t m_sampleRate=16000;
|
||||
uint32_t m_bitRate=0; // current bitrate given fom decoder
|
||||
uint32_t m_avr_bitrate = 0; // average bitrate, median computed by VBR
|
||||
int m_readbytes=0; // bytes read
|
||||
int m_metalen=0; // Number of bytes in metadata
|
||||
int m_controlCounter = 0; // Status within readID3data() and readWaveHeader()
|
||||
int8_t m_balance = 0; // -16 (mute left) ... +16 (mute right)
|
||||
uint8_t m_vol=64; // volume
|
||||
uint8_t m_bitsPerSample = 16; // bitsPerSample
|
||||
uint8_t m_channels=2;
|
||||
uint8_t m_i2s_num = I2S_NUM_0; // I2S_NUM_0 or I2S_NUM_1
|
||||
uint8_t m_playlistFormat = 0; // M3U, PLS, ASX
|
||||
uint8_t m_m3u8codec = CODEC_NONE; // M4A
|
||||
uint8_t m_codec = CODEC_NONE; //
|
||||
uint8_t m_filterType[2]; // lowpass, highpass
|
||||
int16_t m_outBuff[2048*2]; // Interleaved L/R
|
||||
int16_t m_validSamples = 0;
|
||||
int16_t m_curSample = 0;
|
||||
uint16_t m_st_remember = 0; // Save hash from the last streamtitle
|
||||
uint16_t m_datamode = 0; // Statemaschine
|
||||
uint8_t m_flacBitsPerSample = 0; // bps should be 16
|
||||
uint8_t m_flacNumChannels = 0; // can be read out in the FLAC file header
|
||||
uint32_t m_flacSampleRate = 0; // can be read out in the FLAC file header
|
||||
uint16_t m_flacMaxFrameSize = 0; // can be read out in the FLAC file header
|
||||
uint16_t m_flacMaxBlockSize = 0; // can be read out in the FLAC file header
|
||||
uint32_t m_flacTotalSamplesInStream = 0; // can be read out in the FLAC file header
|
||||
uint32_t m_metaint = 0; // Number of databytes between metadata
|
||||
uint32_t m_chunkcount = 0 ; // Counter for chunked transfer
|
||||
uint32_t m_t0 = 0; // store millis(), is needed for a small delay
|
||||
uint32_t m_contentlength = 0; // Stores the length if the stream comes from fileserver
|
||||
uint32_t m_bytesNotDecoded = 0; // pictures or something else that comes with the stream
|
||||
uint32_t m_PlayingStartTime = 0; // Stores the milliseconds after the start of the audio
|
||||
bool m_f_swm = true; // Stream without metadata
|
||||
bool m_f_unsync = false; // set within ID3 tag but not used
|
||||
bool m_f_exthdr = false; // ID3 extended header
|
||||
bool m_f_localfile = false ; // Play from local mp3-file
|
||||
bool m_f_webstream = false ; // Play from URL
|
||||
bool m_f_ssl = false;
|
||||
bool m_f_running = false;
|
||||
bool m_f_firstCall = false; // InitSequence for processWebstream and processLokalFile
|
||||
bool m_f_ctseen = false; // First line of header seen or not
|
||||
bool m_f_chunked = false ; // Station provides chunked transfer
|
||||
bool m_f_firstmetabyte = false; // True if first metabyte (counter)
|
||||
bool m_f_playing = false; // valid mp3 stream recognized
|
||||
bool m_f_webfile = false; // assume it's a radiostream, not a podcast
|
||||
bool m_f_tts = false; // text to speech
|
||||
bool m_f_psram = false; // set if PSRAM is availabe
|
||||
bool m_f_loop = false; // Set if audio file should loop
|
||||
bool m_f_forceMono = false; // if true stereo -> mono
|
||||
bool m_f_internalDAC = false; // false: output vis I2S, true output via internal DAC
|
||||
bool m_f_rtsp = false; // set if RTSP is used (m3u8 stream)
|
||||
bool m_f_m3u8data = false; // used in processM3U8entries
|
||||
bool m_f_Log = true; // if m3u8: log is cancelled
|
||||
bool m_f_continue = false; // next m3u8 chunk is available
|
||||
bool m_f_initInbuffOnce = false; // init InBuff only once
|
||||
i2s_dac_mode_t m_f_channelEnabled = I2S_DAC_CHANNEL_LEFT_EN; // internal DAC on GPIO26 for M5StickC/Plus
|
||||
uint32_t m_audioFileDuration = 0;
|
||||
float m_audioCurrentTime = 0;
|
||||
uint32_t m_audioDataStart = 0; // in bytes
|
||||
size_t m_audioDataSize = 0; //
|
||||
float m_filterBuff[3][2][2][2]; // IIR filters memory for Audio DSP
|
||||
size_t m_i2s_bytesWritten = 0; // set in i2s_write() but not used
|
||||
size_t m_file_size = 0; // size of the file
|
||||
uint16_t m_filterFrequency[2];
|
||||
int8_t m_gain0 = 0; // cut or boost filters (EQ)
|
||||
int8_t m_gain1 = 0;
|
||||
int8_t m_gain2 = 0;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
10224
yoRadio/src/audioI2S/aac_decoder/aac_decoder.cpp
Normal file
10224
yoRadio/src/audioI2S/aac_decoder/aac_decoder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
583
yoRadio/src/audioI2S/aac_decoder/aac_decoder.h
Normal file
583
yoRadio/src/audioI2S/aac_decoder/aac_decoder.h
Normal file
@@ -0,0 +1,583 @@
|
||||
// based on helix aac decoder
|
||||
#pragma once
|
||||
//#pragma GCC optimize ("O3")
|
||||
//#pragma GCC diagnostic ignored "-Wnarrowing"
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#define AAC_ENABLE_MPEG4
|
||||
//#define AAC_ENABLE_SBR // needs additional 60KB Heap,
|
||||
|
||||
#define ASSERT(x) /* do nothing */
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) std::max(a,b)
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) std::min(a,b)
|
||||
#endif
|
||||
|
||||
|
||||
/* AAC file format */
|
||||
enum {
|
||||
AAC_FF_Unknown = 0, /* should be 0 on init */
|
||||
AAC_FF_ADTS = 1,
|
||||
AAC_FF_ADIF = 2,
|
||||
AAC_FF_RAW = 3
|
||||
};
|
||||
|
||||
/* syntactic element type */
|
||||
enum {
|
||||
AAC_ID_INVALID = -1,
|
||||
AAC_ID_SCE = 0,
|
||||
AAC_ID_CPE = 1,
|
||||
AAC_ID_CCE = 2,
|
||||
AAC_ID_LFE = 3,
|
||||
AAC_ID_DSE = 4,
|
||||
AAC_ID_PCE = 5,
|
||||
AAC_ID_FIL = 6,
|
||||
AAC_ID_END = 7
|
||||
};
|
||||
|
||||
enum {
|
||||
ERR_AAC_NONE = 0,
|
||||
ERR_AAC_INDATA_UNDERFLOW = -1,
|
||||
ERR_AAC_NULL_POINTER = -2,
|
||||
ERR_AAC_INVALID_ADTS_HEADER = -3,
|
||||
ERR_AAC_INVALID_ADIF_HEADER = -4,
|
||||
ERR_AAC_INVALID_FRAME = -5,
|
||||
ERR_AAC_MPEG4_UNSUPPORTED = -6,
|
||||
ERR_AAC_CHANNEL_MAP = -7,
|
||||
ERR_AAC_SYNTAX_ELEMENT = -8,
|
||||
ERR_AAC_DEQUANT = -9,
|
||||
ERR_AAC_STEREO_PROCESS = -10,
|
||||
ERR_AAC_PNS = -11,
|
||||
ERR_AAC_SHORT_BLOCK_DEINT = -12,
|
||||
ERR_AAC_TNS = -13,
|
||||
ERR_AAC_IMDCT = -14,
|
||||
ERR_AAC_NCHANS_TOO_HIGH = -15,
|
||||
ERR_AAC_SBR_INIT = -16,
|
||||
ERR_AAC_SBR_BITSTREAM = -17,
|
||||
ERR_AAC_SBR_DATA = -18,
|
||||
ERR_AAC_SBR_PCM_FORMAT = -19,
|
||||
ERR_AAC_SBR_NCHANS_TOO_HIGH = -20,
|
||||
ERR_AAC_SBR_SINGLERATE_UNSUPPORTED = -21,
|
||||
ERR_AAC_RAWBLOCK_PARAMS = -22,
|
||||
ERR_AAC_UNKNOWN = -9999
|
||||
};
|
||||
|
||||
enum {
|
||||
SBR_GRID_FIXFIX = 0,
|
||||
SBR_GRID_FIXVAR = 1,
|
||||
SBR_GRID_VARFIX = 2,
|
||||
SBR_GRID_VARVAR = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
HuffTabSBR_tEnv15 = 0,
|
||||
HuffTabSBR_fEnv15 = 1,
|
||||
HuffTabSBR_tEnv15b = 2,
|
||||
HuffTabSBR_fEnv15b = 3,
|
||||
HuffTabSBR_tEnv30 = 4,
|
||||
HuffTabSBR_fEnv30 = 5,
|
||||
HuffTabSBR_tEnv30b = 6,
|
||||
HuffTabSBR_fEnv30b = 7,
|
||||
HuffTabSBR_tNoise30 = 8,
|
||||
HuffTabSBR_fNoise30 = 5,
|
||||
HuffTabSBR_tNoise30b = 9,
|
||||
HuffTabSBR_fNoise30b = 7
|
||||
};
|
||||
|
||||
typedef struct _AACDecInfo_t {
|
||||
/* raw decoded data, before rounding to 16-bit PCM (for postprocessing such as SBR) */
|
||||
void *rawSampleBuf[2];
|
||||
int rawSampleBytes;
|
||||
int rawSampleFBits;
|
||||
/* fill data (can be used for processing SBR or other extensions) */
|
||||
uint8_t *fillBuf;
|
||||
int fillCount;
|
||||
int fillExtType;
|
||||
int prevBlockID; /* block information */
|
||||
int currBlockID;
|
||||
int currInstTag;
|
||||
int sbDeinterleaveReqd[2]; // [MAX_NCHANS_ELEM]
|
||||
int adtsBlocksLeft;
|
||||
int bitRate; /* user-accessible info */
|
||||
int nChans;
|
||||
int sampRate;
|
||||
float compressionRatio;
|
||||
int id; /* 0: MPEG-4, 1: MPEG2 */
|
||||
int profile; /* 0: Main profile, 1: LowComplexity (LC), 2: ScalableSamplingRate (SSR), 3: reserved */
|
||||
int format;
|
||||
int sbrEnabled;
|
||||
int tnsUsed;
|
||||
int pnsUsed;
|
||||
int frameCount;
|
||||
} AACDecInfo_t;
|
||||
|
||||
|
||||
typedef struct _aac_BitStreamInfo_t {
|
||||
uint8_t *bytePtr;
|
||||
unsigned int iCache;
|
||||
int cachedBits;
|
||||
int nBytes;
|
||||
} aac_BitStreamInfo_t;
|
||||
|
||||
typedef union _U64 {
|
||||
int64_t w64;
|
||||
struct {
|
||||
unsigned int lo32;
|
||||
signed int hi32;
|
||||
} r;
|
||||
} U64;
|
||||
|
||||
typedef struct _AACFrameInfo_t {
|
||||
int bitRate;
|
||||
int nChans;
|
||||
int sampRateCore;
|
||||
int sampRateOut;
|
||||
int bitsPerSample;
|
||||
int outputSamps;
|
||||
int profile;
|
||||
int tnsUsed;
|
||||
int pnsUsed;
|
||||
} AACFrameInfo_t;
|
||||
|
||||
typedef struct _HuffInfo_t {
|
||||
int maxBits; /* number of bits in longest codeword */
|
||||
uint8_t count[20]; /* count[MAX_HUFF_BITS] = number of codes with length i+1 bits */
|
||||
int offset; /* offset into symbol table */
|
||||
} HuffInfo_t;
|
||||
|
||||
typedef struct _PulseInfo_t {
|
||||
uint8_t pulseDataPresent;
|
||||
uint8_t numPulse;
|
||||
uint8_t startSFB;
|
||||
uint8_t offset[4]; // [MAX_PULSES]
|
||||
uint8_t amp[4]; // [MAX_PULSES]
|
||||
} PulseInfo_t;
|
||||
|
||||
typedef struct _TNSInfo_t {
|
||||
uint8_t tnsDataPresent;
|
||||
uint8_t numFilt[8]; // [MAX_TNS_FILTERS] max 1 filter each for 8 short windows, or 3 filters for 1 long window
|
||||
uint8_t coefRes[8]; // [MAX_TNS_FILTERS]
|
||||
uint8_t length[8]; // [MAX_TNS_FILTERS]
|
||||
uint8_t order[8]; // [MAX_TNS_FILTERS]
|
||||
uint8_t dir[8]; // [MAX_TNS_FILTERS]
|
||||
int8_t coef[60]; // [MAX_TNS_COEFS] max 3 filters * 20 coefs for 1 long window,
|
||||
// or 1 filter * 7 coefs for each of 8 short windows
|
||||
} TNSInfo_t;
|
||||
|
||||
typedef struct _GainControlInfo_t {
|
||||
uint8_t gainControlDataPresent;
|
||||
uint8_t maxBand;
|
||||
uint8_t adjNum[3][8]; // [MAX_GAIN_BANDS][MAX_GAIN_WIN]
|
||||
uint8_t alevCode[3][8][7]; // [MAX_GAIN_BANDS][MAX_GAIN_WIN][MAX_GAIN_ADJUST]
|
||||
uint8_t alocCode[3][8][7]; // [MAX_GAIN_BANDS][MAX_GAIN_WIN][MAX_GAIN_ADJUST]
|
||||
} GainControlInfo_t;
|
||||
|
||||
typedef struct _ICSInfo_t {
|
||||
uint8_t icsResBit;
|
||||
uint8_t winSequence;
|
||||
uint8_t winShape;
|
||||
uint8_t maxSFB;
|
||||
uint8_t sfGroup;
|
||||
uint8_t predictorDataPresent;
|
||||
uint8_t predictorReset;
|
||||
uint8_t predictorResetGroupNum;
|
||||
uint8_t predictionUsed[41]; // [MAX_PRED_SFB]
|
||||
uint8_t numWinGroup;
|
||||
uint8_t winGroupLen[8]; // [MAX_WIN_GROUPS]
|
||||
} ICSInfo_t;
|
||||
|
||||
typedef struct _ADTSHeader_t {
|
||||
/* fixed */
|
||||
uint8_t id; /* MPEG bit - should be 1 */
|
||||
uint8_t layer; /* MPEG layer - should be 0 */
|
||||
uint8_t protectBit; /* 0 = CRC word follows, 1 = no CRC word */
|
||||
uint8_t profile; /* 0 = main, 1 = LC, 2 = SSR, 3 = reserved */
|
||||
uint8_t sampRateIdx; /* sample rate index range = [0, 11] */
|
||||
uint8_t privateBit; /* ignore */
|
||||
uint8_t channelConfig; /* 0 = implicit, >0 = use default table */
|
||||
uint8_t origCopy; /* 0 = copy, 1 = original */
|
||||
uint8_t home; /* ignore */
|
||||
/* variable */
|
||||
uint8_t copyBit; /* 1 bit of the 72-bit copyright ID (transmitted as 1 bit per frame) */
|
||||
uint8_t copyStart; /* 1 = this bit starts the 72-bit ID, 0 = it does not */
|
||||
int frameLength; /* length of frame */
|
||||
int bufferFull; /* number of 32-bit words left in enc buffer, 0x7FF = VBR */
|
||||
uint8_t numRawDataBlocks; /* number of raw data blocks in frame */
|
||||
/* CRC */
|
||||
int crcCheckWord; /* 16-bit CRC check word (present if protectBit == 0) */
|
||||
} ADTSHeader_t;
|
||||
|
||||
typedef struct _ADIFHeader_t {
|
||||
uint8_t copyBit; /* 0 = no copyright ID, 1 = 72-bit copyright ID follows immediately */
|
||||
uint8_t origCopy; /* 0 = copy, 1 = original */
|
||||
uint8_t home; /* ignore */
|
||||
uint8_t bsType; /* bitstream type: 0 = CBR, 1 = VBR */
|
||||
int bitRate; /* bitRate: CBR = bits/sec, VBR = peak bits/frame, 0 = unknown */
|
||||
uint8_t numPCE; /* number of program config elements (max = 16) */
|
||||
int bufferFull; /* bits left in bit reservoir */
|
||||
uint8_t copyID[9]; /* [ADIF_COPYID_SIZE] optional 72-bit copyright ID */
|
||||
} ADIFHeader_t;
|
||||
|
||||
/* sizeof(ProgConfigElement_t) = 82 bytes (if KEEP_PCE_COMMENTS not defined) */
|
||||
typedef struct _ProgConfigElement_t {
|
||||
uint8_t elemInstTag; /* element instance tag */
|
||||
uint8_t profile; /* 0 = main, 1 = LC, 2 = SSR, 3 = reserved */
|
||||
uint8_t sampRateIdx; /* sample rate index range = [0, 11] */
|
||||
uint8_t numFCE; /* number of front channel elements (max = 15) */
|
||||
uint8_t numSCE; /* number of side channel elements (max = 15) */
|
||||
uint8_t numBCE; /* number of back channel elements (max = 15) */
|
||||
uint8_t numLCE; /* number of LFE channel elements (max = 3) */
|
||||
uint8_t numADE; /* number of associated data elements (max = 7) */
|
||||
uint8_t numCCE; /* number of valid channel coupling elements (max = 15) */
|
||||
uint8_t monoMixdown; /* mono mixdown: bit 4 = present flag, bits 3-0 = element number */
|
||||
uint8_t stereoMixdown; /* stereo mixdown: bit 4 = present flag, bits 3-0 = element number */
|
||||
uint8_t matrixMixdown; /* bit 4 = present flag, bit 3 = unused,bits 2-1 = index, bit 0 = pseudo-surround enable */
|
||||
uint8_t fce[15]; /* [MAX_NUM_FCE] front element channel pair: bit 4 = SCE/CPE flag, bits 3-0 = inst tag */
|
||||
uint8_t sce[15]; /* [MAX_NUM_SCE] side element channel pair: bit 4 = SCE/CPE flag, bits 3-0 = inst tag */
|
||||
uint8_t bce[15]; /* [MAX_NUM_BCE] back element channel pair: bit 4 = SCE/CPE flag, bits 3-0 = inst tag */
|
||||
uint8_t lce[3]; /* [MAX_NUM_LCE] instance tag for LFE elements */
|
||||
uint8_t ade[7]; /* [MAX_NUM_ADE] instance tag for ADE elements */
|
||||
uint8_t cce[15]; /* [MAX_NUM_BCE] channel coupling elements: bit 4 = switching flag, bits 3-0 = inst tag */
|
||||
} ProgConfigElement_t;
|
||||
|
||||
typedef struct _SBRHeader {
|
||||
int count;
|
||||
|
||||
uint8_t ampRes;
|
||||
uint8_t startFreq;
|
||||
uint8_t stopFreq;
|
||||
uint8_t crossOverBand;
|
||||
uint8_t resBitsHdr;
|
||||
uint8_t hdrExtra1;
|
||||
uint8_t hdrExtra2;
|
||||
|
||||
uint8_t freqScale;
|
||||
uint8_t alterScale;
|
||||
uint8_t noiseBands;
|
||||
|
||||
uint8_t limiterBands;
|
||||
uint8_t limiterGains;
|
||||
uint8_t interpFreq;
|
||||
uint8_t smoothMode;
|
||||
} SBRHeader;
|
||||
|
||||
/* need one SBRGrid per channel, updated every frame */
|
||||
typedef struct _SBRGrid {
|
||||
uint8_t frameClass;
|
||||
uint8_t ampResFrame;
|
||||
uint8_t pointer;
|
||||
|
||||
uint8_t numEnv; /* L_E */
|
||||
uint8_t envTimeBorder[5 + 1]; // [MAX_NUM_ENV+1] /* t_E */
|
||||
uint8_t freqRes[5]; // [MAX_NUM_ENV]/* r */
|
||||
uint8_t numNoiseFloors; /* L_Q */
|
||||
uint8_t noiseTimeBorder[2 + 1]; // [MAX_NUM_NOISE_FLOORS+1] /* t_Q */
|
||||
|
||||
uint8_t numEnvPrev;
|
||||
uint8_t numNoiseFloorsPrev;
|
||||
uint8_t freqResPrev;
|
||||
} SBRGrid;
|
||||
|
||||
/* need one SBRFreq per element (SCE/CPE/LFE), updated only on header reset */
|
||||
typedef struct _SBRFreq {
|
||||
int kStart; /* k_x */
|
||||
int nMaster;
|
||||
int nHigh;
|
||||
int nLow;
|
||||
int nLimiter; /* N_l */
|
||||
int numQMFBands; /* M */
|
||||
int numNoiseFloorBands; /* Nq */
|
||||
int kStartPrev;
|
||||
int numQMFBandsPrev;
|
||||
uint8_t freqMaster[48 + 1]; // [MAX_QMF_BANDS + 1] /* not necessary to save this after derived tables are generated */
|
||||
uint8_t freqHigh[48 + 1]; // [MAX_QMF_BANDS + 1]
|
||||
uint8_t freqLow[48 / 2 + 1]; // [MAX_QMF_BANDS / 2 + 1] /* nLow = nHigh - (nHigh >> 1) */
|
||||
uint8_t freqNoise[5 + 1]; // [MAX_NUM_NOISE_FLOOR_BANDS+1]
|
||||
uint8_t freqLimiter[48 / 2 + 5];// [MAX_QMF_BANDS / 2 + MAX_NUM_PATCHES] /* max (intermediate) size = nLow + numPatches - 1 */
|
||||
|
||||
uint8_t numPatches;
|
||||
uint8_t patchNumSubbands[5 + 1]; // [MAX_NUM_PATCHES + 1]
|
||||
uint8_t patchStartSubband[5 + 1]; // [MAX_NUM_PATCHES + 1]
|
||||
} SBRFreq;
|
||||
|
||||
typedef struct _SBRChan {
|
||||
int reset;
|
||||
uint8_t deltaFlagEnv[5]; // [MAX_NUM_ENV]
|
||||
uint8_t deltaFlagNoise[2]; // [MAX_NUM_NOISE_FLOORS]
|
||||
int8_t envDataQuant[5][48]; // [MAX_NUM_ENV][MAX_QMF_BANDS] /* range = [0, 127] */
|
||||
int8_t noiseDataQuant[2][5]; // [MAX_NUM_NOISE_FLOORS][MAX_NUM_NOISE_FLOOR_BANDS]
|
||||
|
||||
uint8_t invfMode[2][5]; // [2][MAX_NUM_NOISE_FLOOR_BANDS] /* invfMode[0/1][band] = prev/curr */
|
||||
int chirpFact[5]; // [MAX_NUM_NOISE_FLOOR_BANDS] /* bwArray */
|
||||
uint8_t addHarmonicFlag[2]; /* addHarmonicFlag[0/1] = prev/curr */
|
||||
uint8_t addHarmonic[2][64]; /* addHarmonic[0/1][band] = prev/curr */
|
||||
|
||||
int gbMask[2]; /* gbMask[0/1] = XBuf[0-31]/XBuf[32-39] */
|
||||
int8_t laPrev;
|
||||
|
||||
int noiseTabIndex;
|
||||
int sinIndex;
|
||||
int gainNoiseIndex;
|
||||
int gTemp[5][48]; // [MAX_NUM_SMOOTH_COEFS][MAX_QMF_BANDS]
|
||||
int qTemp[5][48]; // [MAX_NUM_SMOOTH_COEFS][MAX_QMF_BANDS]
|
||||
|
||||
} SBRChan;
|
||||
|
||||
|
||||
/* state info struct for baseline (MPEG-4 LC) decoding */
|
||||
typedef struct _PSInfoBase_t {
|
||||
int dataCount;
|
||||
uint8_t dataBuf[510]; // [DATA_BUF_SIZE]
|
||||
int fillCount;
|
||||
uint8_t fillBuf[269]; //[FILL_BUF_SIZE]
|
||||
/* state information which is the same throughout whole frame */
|
||||
int nChans;
|
||||
int useImpChanMap;
|
||||
int sampRateIdx;
|
||||
/* state information which can be overwritten by subsequent elements within frame */
|
||||
ICSInfo_t icsInfo[2]; // [MAX_NCHANS_ELEM]
|
||||
int commonWin;
|
||||
short scaleFactors[2][15*8]; // [MAX_NCHANS_ELEM][MAX_SF_BANDS]
|
||||
uint8_t sfbCodeBook[2][15*8]; // [MAX_NCHANS_ELEM][MAX_SF_BANDS]
|
||||
int msMaskPresent;
|
||||
uint8_t msMaskBits[(15 * 8 + 7) >> 3]; // [MAX_MS_MASK_BYTES]
|
||||
int pnsUsed[2]; // [MAX_NCHANS_ELEM]
|
||||
int pnsLastVal;
|
||||
int intensityUsed[2]; // [MAX_NCHANS_ELEM]
|
||||
// PulseInfo_t pulseInfo[2]; // [MAX_NCHANS_ELEM]
|
||||
TNSInfo_t tnsInfo[2]; // [MAX_NCHANS_ELEM]
|
||||
int tnsLPCBuf[20]; // [MAX_TNS_ORDER]
|
||||
int tnsWorkBuf[20]; //[MAX_TNS_ORDER]
|
||||
GainControlInfo_t gainControlInfo[2]; // [MAX_NCHANS_ELEM]
|
||||
int gbCurrent[2]; // [MAX_NCHANS_ELEM]
|
||||
int coef[2][1024]; // [MAX_NCHANS_ELEM][AAC_MAX_NSAMPS]
|
||||
#ifdef AAC_ENABLE_SBR
|
||||
int sbrWorkBuf[2][1024]; // [MAX_NCHANS_ELEM][AAC_MAX_NSAMPS];
|
||||
#endif
|
||||
/* state information which must be saved for each element and used in next frame */
|
||||
int overlap[2][1024]; // [AAC_MAX_NCHANS][AAC_MAX_NSAMPS]
|
||||
int prevWinShape[2]; // [AAC_MAX_NCHANS]
|
||||
} PSInfoBase_t;
|
||||
|
||||
typedef struct _PSInfoSBR {
|
||||
/* save for entire file */
|
||||
int frameCount;
|
||||
int sampRateIdx;
|
||||
|
||||
/* state info that must be saved for each channel */
|
||||
SBRHeader sbrHdr[2];
|
||||
SBRGrid sbrGrid[2];
|
||||
SBRFreq sbrFreq[2];
|
||||
SBRChan sbrChan[2];
|
||||
|
||||
/* temp variables, no need to save between blocks */
|
||||
uint8_t dataExtra;
|
||||
uint8_t resBitsData;
|
||||
uint8_t extendedDataPresent;
|
||||
int extendedDataSize;
|
||||
|
||||
int8_t envDataDequantScale[2][5]; // [MAX_NCHANS_ELEM][MAX_NUM_ENV
|
||||
int envDataDequant[2][5][48]; // [MAX_NCHANS_ELEM][MAX_NUM_ENV][MAX_QMF_BANDS
|
||||
int noiseDataDequant[2][2][5]; // [MAX_NCHANS_ELEM][MAX_NUM_NOISE_FLOORS][MAX_NUM_NOISE_FLOOR_BANDS]
|
||||
|
||||
int eCurr[48]; // [MAX_QMF_BANDS]
|
||||
uint8_t eCurrExp[48]; // [MAX_QMF_BANDS]
|
||||
uint8_t eCurrExpMax;
|
||||
int8_t la;
|
||||
|
||||
int crcCheckWord;
|
||||
int couplingFlag;
|
||||
int envBand;
|
||||
int eOMGainMax;
|
||||
int gainMax;
|
||||
int gainMaxFBits;
|
||||
int noiseFloorBand;
|
||||
int qp1Inv;
|
||||
int qqp1Inv;
|
||||
int sMapped;
|
||||
int sBand;
|
||||
int highBand;
|
||||
|
||||
int sumEOrigMapped;
|
||||
int sumECurrGLim;
|
||||
int sumSM;
|
||||
int sumQM;
|
||||
int gLimBoost[48];
|
||||
int qmLimBoost[48];
|
||||
int smBoost[48];
|
||||
|
||||
int smBuf[48];
|
||||
int qmLimBuf[48];
|
||||
int gLimBuf[48];
|
||||
int gLimFbits[48];
|
||||
|
||||
int gFiltLast[48];
|
||||
int qFiltLast[48];
|
||||
|
||||
/* large buffers */
|
||||
int delayIdxQMFA[2]; // [AAC_MAX_NCHANS]
|
||||
int delayQMFA[2][10 * 32]; // [AAC_MAX_NCHANS][DELAY_SAMPS_QMFA]
|
||||
int delayIdxQMFS[2]; // [AAC_MAX_NCHANS]
|
||||
int delayQMFS[2][10 * 128]; // [AAC_MAX_NCHANS][DELAY_SAMPS_QMFS]
|
||||
int XBufDelay[2][8][64][2]; // [AAC_MAX_NCHANS][HF_GEN][64][2]
|
||||
int XBuf[32+8][64][2];
|
||||
} PSInfoSBR_t;
|
||||
|
||||
bool AACDecoder_AllocateBuffers(void);
|
||||
int AACFlushCodec();
|
||||
void AACDecoder_FreeBuffers(void);
|
||||
bool AACDecoder_IsInit(void);
|
||||
int AACFindSyncWord(uint8_t *buf, int nBytes);
|
||||
int AACSetRawBlockParams(int copyLast, int nChans, int sampRateCore, int profile);
|
||||
int AACDecode(uint8_t *inbuf, int *bytesLeft, short *outbuf);
|
||||
int AACGetSampRate();
|
||||
int AACGetChannels();
|
||||
int AACGetID(); // 0-MPEG4, 1-MPEG2
|
||||
uint8_t AACGetProfile(); // 0-Main, 1-LC, 2-SSR, 3-reserved
|
||||
uint8_t AACGetFormat(); // 0-unknown 1-ADTS 2-ADIF, 3-RAW
|
||||
int AACGetBitsPerSample();
|
||||
int AACGetBitrate();
|
||||
int AACGetOutputSamps();
|
||||
int AACGetBitrate();
|
||||
void DecodeLPCCoefs(int order, int res, int8_t *filtCoef, int *a, int *b);
|
||||
int FilterRegion(int size, int dir, int order, int *audioCoef, int *a, int *hist);
|
||||
int TNSFilter(int ch);
|
||||
int DecodeSingleChannelElement();
|
||||
int DecodeChannelPairElement();
|
||||
int DecodeLFEChannelElement();
|
||||
int DecodeDataStreamElement();
|
||||
int DecodeProgramConfigElement(uint8_t idx);
|
||||
int DecodeFillElement();
|
||||
int DecodeNextElement(uint8_t **buf, int *bitOffset, int *bitsAvail);
|
||||
void PreMultiply(int tabidx, int *zbuf1);
|
||||
void PostMultiply(int tabidx, int *fft1);
|
||||
void PreMultiplyRescale(int tabidx, int *zbuf1, int es);
|
||||
void PostMultiplyRescale(int tabidx, int *fft1, int es);
|
||||
void DCT4(int tabidx, int *coef, int gb);
|
||||
void BitReverse(int *inout, int tabidx);
|
||||
void R4FirstPass(int *x, int bg);
|
||||
void R8FirstPass(int *x, int bg);
|
||||
void R4Core(int *x, int bg, int gp, int *wtab);
|
||||
void R4FFT(int tabidx, int *x);
|
||||
void UnpackZeros(int nVals, int *coef);
|
||||
void UnpackQuads(int cb, int nVals, int *coef);
|
||||
void UnpackPairsNoEsc(int cb, int nVals, int *coef);
|
||||
void UnpackPairsEsc(int cb, int nVals, int *coef);
|
||||
void DecodeSpectrumLong(int ch);
|
||||
void DecodeSpectrumShort(int ch);
|
||||
void DecWindowOverlap(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev);
|
||||
void DecWindowOverlapLongStart(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev);
|
||||
void DecWindowOverlapLongStop(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev);
|
||||
void DecWindowOverlapShort(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev);
|
||||
int IMDCT(int ch, int chOut, short *outbuf);
|
||||
void DecodeICSInfo(ICSInfo_t *icsInfo, int sampRateIdx);
|
||||
void DecodeSectionData(int winSequence, int numWinGrp, int maxSFB, uint8_t *sfbCodeBook);
|
||||
int DecodeOneScaleFactor();
|
||||
void DecodeScaleFactors(int numWinGrp, int maxSFB, int globalGain, uint8_t *sfbCodeBook, short *scaleFactors);
|
||||
void DecodePulseInfo(uint8_t ch);
|
||||
void DecodeTNSInfo(int winSequence, TNSInfo_t *ti, int8_t *tnsCoef);
|
||||
void DecodeGainControlInfo(int winSequence, GainControlInfo_t *gi);
|
||||
void DecodeICS(int ch);
|
||||
int DecodeNoiselessData(uint8_t **buf, int *bitOffset, int *bitsAvail, int ch);
|
||||
int DecodeHuffmanScalar(const signed short *huffTab, const HuffInfo_t *huffTabInfo, unsigned int bitBuf, int32_t *val);
|
||||
int UnpackADTSHeader(uint8_t **buf, int *bitOffset, int *bitsAvail);
|
||||
int GetADTSChannelMapping(uint8_t *buf, int bitOffset, int bitsAvail);
|
||||
int GetNumChannelsADIF(int nPCE);
|
||||
int GetSampleRateIdxADIF(int nPCE);
|
||||
int UnpackADIFHeader(uint8_t **buf, int *bitOffset, int *bitsAvail);
|
||||
int SetRawBlockParams(int copyLast, int nChans, int sampRate, int profile);
|
||||
int PrepareRawBlock();
|
||||
int DequantBlock(int *inbuf, int nSamps, int scale);
|
||||
int AACDequantize(int ch);
|
||||
int DeinterleaveShortBlocks(int ch);
|
||||
unsigned int Get32BitVal(unsigned int *last);
|
||||
int InvRootR(int r);
|
||||
int ScaleNoiseVector(int *coef, int nVals, int sf);
|
||||
void GenerateNoiseVector(int *coef, int *last, int nVals);
|
||||
void CopyNoiseVector(int *coefL, int *coefR, int nVals);
|
||||
int PNS(int ch);
|
||||
int GetSampRateIdx(int sampRate);
|
||||
void StereoProcessGroup(int *coefL, int *coefR, const uint16_t *sfbTab, int msMaskPres, uint8_t *msMaskPtr,
|
||||
int msMaskOffset, int maxSFB, uint8_t *cbRight, short *sfRight, int *gbCurrent);
|
||||
int StereoProcess();
|
||||
int RatioPowInv(int a, int b, int c);
|
||||
int SqrtFix(int q, int fBitsIn, int *fBitsOut);
|
||||
int InvRNormalized(int r);
|
||||
void BitReverse32(int *inout);
|
||||
void R8FirstPass32(int *r0);
|
||||
void R4Core32(int *r0);
|
||||
void FFT32C(int *x);
|
||||
void CVKernel1(int *XBuf, int *accBuf);
|
||||
void CVKernel2(int *XBuf, int *accBuf);
|
||||
void SetBitstreamPointer(int nBytes, uint8_t *buf);
|
||||
inline void RefillBitstreamCache();
|
||||
unsigned int GetBits(int nBits);
|
||||
unsigned int GetBitsNoAdvance(int nBits);
|
||||
void AdvanceBitstream(int nBits);
|
||||
int CalcBitsUsed(uint8_t *startBuf, int startOffset);
|
||||
void ByteAlignBitstream();
|
||||
// SBR
|
||||
void InitSBRState();
|
||||
int DecodeSBRBitstream(int chBase);
|
||||
int DecodeSBRData(int chBase, short *outbuf);
|
||||
int FlushCodecSBR();
|
||||
void BubbleSort(uint8_t *v, int nItems);
|
||||
uint8_t VMin(uint8_t *v, int nItems);
|
||||
uint8_t VMax(uint8_t *v, int nItems);
|
||||
int CalcFreqMasterScaleZero(uint8_t *freqMaster, int alterScale, int k0, int k2);
|
||||
int CalcFreqMaster(uint8_t *freqMaster, int freqScale, int alterScale, int k0, int k2);
|
||||
int CalcFreqHigh(uint8_t *freqHigh, uint8_t *freqMaster, int nMaster, int crossOverBand);
|
||||
int CalcFreqLow(uint8_t *freqLow, uint8_t *freqHigh, int nHigh);
|
||||
int CalcFreqNoise(uint8_t *freqNoise, uint8_t *freqLow, int nLow, int kStart, int k2, int noiseBands);
|
||||
int BuildPatches(uint8_t *patchNumSubbands, uint8_t *patchStartSubband, uint8_t *freqMaster, int nMaster, int k0,
|
||||
int kStart, int numQMFBands, int sampRateIdx);
|
||||
int FindFreq(uint8_t *freq, int nFreq, uint8_t val);
|
||||
void RemoveFreq(uint8_t *freq, int nFreq, int removeIdx);
|
||||
int CalcFreqLimiter(uint8_t *freqLimiter, uint8_t *patchNumSubbands, uint8_t *freqLow, int nLow, int kStart,
|
||||
int limiterBands, int numPatches);
|
||||
int CalcFreqTables(SBRHeader *sbrHdr, SBRFreq *sbrFreq, int sampRateIdx);
|
||||
void EstimateEnvelope(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int env);
|
||||
int GetSMapped(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int env, int band, int la);
|
||||
void CalcMaxGain(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int ch, int env, int lim, int fbitsDQ);
|
||||
void CalcNoiseDivFactors(int q, int *qp1Inv, int *qqp1Inv);
|
||||
void CalcComponentGains(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch, int env, int lim, int fbitsDQ);
|
||||
void ApplyBoost(SBRFreq *sbrFreq, int lim, int fbitsDQ);
|
||||
void CalcGain(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch, int env);
|
||||
void MapHF(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int env, int hfReset);
|
||||
void AdjustHighFreq(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch);
|
||||
int CalcCovariance1(int *XBuf, int *p01reN, int *p01imN, int *p12reN, int *p12imN, int *p11reN, int *p22reN);
|
||||
int CalcCovariance2(int *XBuf, int *p02reN, int *p02imN);
|
||||
void CalcLPCoefs(int *XBuf, int *a0re, int *a0im, int *a1re, int *a1im, int gb);
|
||||
void GenerateHighFreq(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch);
|
||||
int DecodeHuffmanScalar(const signed int *huffTab, const HuffInfo_t *huffTabInfo, unsigned int bitBuf, signed int *val);
|
||||
int DecodeOneSymbol(int huffTabIndex);
|
||||
int DequantizeEnvelope(int nBands, int ampRes, int8_t *envQuant, int *envDequant);
|
||||
void DequantizeNoise(int nBands, int8_t *noiseQuant, int *noiseDequant);
|
||||
void DecodeSBREnvelope(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch);
|
||||
void DecodeSBRNoise(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch);
|
||||
void UncoupleSBREnvelope(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR);
|
||||
void UncoupleSBRNoise(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR);
|
||||
void DecWindowOverlapNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev);
|
||||
void DecWindowOverlapLongStartNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev);
|
||||
void DecWindowOverlapLongStopNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev);
|
||||
void DecWindowOverlapShortNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev);
|
||||
void PreMultiply64(int *zbuf1);
|
||||
void PostMultiply64(int *fft1, int nSampsOut);
|
||||
void QMFAnalysisConv(int *cTab, int *delay, int dIdx, int *uBuf);
|
||||
int QMFAnalysis(int *inbuf, int *delay, int *XBuf, int fBitsIn, int *delayIdx, int qmfaBands);
|
||||
void QMFSynthesisConv(int *cPtr, int *delay, int dIdx, short *outbuf, int nChans);
|
||||
void QMFSynthesis(int *inbuf, int *delay, int *delayIdx, int qmfsBands, short *outbuf, int nChans);
|
||||
int UnpackSBRHeader(SBRHeader *sbrHdr);
|
||||
void UnpackSBRGrid(SBRHeader *sbrHdr, SBRGrid *sbrGrid);
|
||||
void UnpackDeltaTimeFreq(int numEnv, uint8_t *deltaFlagEnv, int numNoiseFloors, uint8_t *deltaFlagNoise);
|
||||
void UnpackInverseFilterMode(int numNoiseFloorBands, uint8_t *mode);
|
||||
void UnpackSinusoids(int nHigh, int addHarmonicFlag, uint8_t *addHarmonic);
|
||||
void CopyCouplingGrid(SBRGrid *sbrGridLeft, SBRGrid *sbrGridRight);
|
||||
void CopyCouplingInverseFilterMode(int numNoiseFloorBands, uint8_t *modeLeft, uint8_t *modeRight);
|
||||
void UnpackSBRSingleChannel(int chBase);
|
||||
void UnpackSBRChannelPair(int chBase);
|
||||
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);
|
||||
|
||||
|
||||
3822
yoRadio/src/audioI2S/mp3_decoder/mp3_decoder.cpp
Normal file
3822
yoRadio/src/audioI2S/mp3_decoder/mp3_decoder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
513
yoRadio/src/audioI2S/mp3_decoder/mp3_decoder.h
Normal file
513
yoRadio/src/audioI2S/mp3_decoder/mp3_decoder.h
Normal file
@@ -0,0 +1,513 @@
|
||||
// based om helix mp3 decoder
|
||||
#pragma once
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "assert.h"
|
||||
|
||||
static const uint8_t m_HUFF_PAIRTABS =32;
|
||||
static const uint8_t m_BLOCK_SIZE =18;
|
||||
static const uint8_t m_NBANDS =32;
|
||||
static const uint8_t m_MAX_REORDER_SAMPS =(192-126)*3; // largest critical band for short blocks (see sfBandTable)
|
||||
static const uint16_t m_VBUF_LENGTH =17*2* m_NBANDS; // for double-sized vbuf FIFO
|
||||
static const uint8_t m_MAX_SCFBD =4; // max scalefactor bands per channel
|
||||
static const uint16_t m_MAINBUF_SIZE =1940;
|
||||
static const uint8_t m_MAX_NGRAN =2; // max granules
|
||||
static const uint8_t m_MAX_NCHAN =2; // max channels
|
||||
static const uint16_t m_MAX_NSAMP =576; // max samples per channel, per granule
|
||||
|
||||
enum {
|
||||
ERR_MP3_NONE = 0,
|
||||
ERR_MP3_INDATA_UNDERFLOW = -1,
|
||||
ERR_MP3_MAINDATA_UNDERFLOW = -2,
|
||||
ERR_MP3_FREE_BITRATE_SYNC = -3,
|
||||
ERR_MP3_OUT_OF_MEMORY = -4,
|
||||
ERR_MP3_NULL_POINTER = -5,
|
||||
ERR_MP3_INVALID_FRAMEHEADER = -6,
|
||||
ERR_MP3_INVALID_SIDEINFO = -7,
|
||||
ERR_MP3_INVALID_SCALEFACT = -8,
|
||||
ERR_MP3_INVALID_HUFFCODES = -9,
|
||||
ERR_MP3_INVALID_DEQUANTIZE = -10,
|
||||
ERR_MP3_INVALID_IMDCT = -11,
|
||||
ERR_MP3_INVALID_SUBBAND = -12,
|
||||
|
||||
ERR_UNKNOWN = -9999
|
||||
};
|
||||
|
||||
typedef struct MP3FrameInfo {
|
||||
int bitrate;
|
||||
int nChans;
|
||||
int samprate;
|
||||
int bitsPerSample;
|
||||
int outputSamps;
|
||||
int layer;
|
||||
int version;
|
||||
} MP3FrameInfo_t;
|
||||
|
||||
typedef struct SFBandTable {
|
||||
int/*short*/ l[23];
|
||||
int/*short*/ s[14];
|
||||
} SFBandTable_t;
|
||||
|
||||
typedef struct BitStreamInfo {
|
||||
unsigned char *bytePtr;
|
||||
unsigned int iCache;
|
||||
int cachedBits;
|
||||
int nBytes;
|
||||
} BitStreamInfo_t;
|
||||
|
||||
typedef enum { /* map these to the corresponding 2-bit values in the frame header */
|
||||
Stereo = 0x00, /* two independent channels, but L and R frames might have different # of bits */
|
||||
Joint = 0x01, /* coupled channels - layer III: mix of M-S and intensity, Layers I/II: intensity and direct coding only */
|
||||
Dual = 0x02, /* two independent channels, L and R always have exactly 1/2 the total bitrate */
|
||||
Mono = 0x03 /* one channel */
|
||||
} StereoMode_t;
|
||||
|
||||
typedef enum { /* map to 0,1,2 to make table indexing easier */
|
||||
MPEG1 = 0,
|
||||
MPEG2 = 1,
|
||||
MPEG25 = 2
|
||||
} MPEGVersion_t;
|
||||
|
||||
typedef struct FrameHeader {
|
||||
int layer; /* layer index (1, 2, or 3) */
|
||||
int crc; /* CRC flag: 0 = disabled, 1 = enabled */
|
||||
int brIdx; /* bitrate index (0 - 15) */
|
||||
int srIdx; /* sample rate index (0 - 2) */
|
||||
int paddingBit; /* padding flag: 0 = no padding, 1 = single pad byte */
|
||||
int privateBit; /* unused */
|
||||
int modeExt; /* used to decipher joint stereo mode */
|
||||
int copyFlag; /* copyright flag: 0 = no, 1 = yes */
|
||||
int origFlag; /* original flag: 0 = copy, 1 = original */
|
||||
int emphasis; /* deemphasis mode */
|
||||
int CRCWord; /* CRC word (16 bits, 0 if crc not enabled) */
|
||||
} FrameHeader_t;
|
||||
|
||||
typedef struct SideInfoSub {
|
||||
int part23Length; /* number of bits in main data */
|
||||
int nBigvals; /* 2x this = first set of Huffman cw's (maximum amplitude can be > 1) */
|
||||
int globalGain; /* overall gain for dequantizer */
|
||||
int sfCompress; /* unpacked to figure out number of bits in scale factors */
|
||||
int winSwitchFlag; /* window switching flag */
|
||||
int blockType; /* block type */
|
||||
int mixedBlock; /* 0 = regular block (all short or long), 1 = mixed block */
|
||||
int tableSelect[3]; /* index of Huffman tables for the big values regions */
|
||||
int subBlockGain[3]; /* subblock gain offset, relative to global gain */
|
||||
int region0Count; /* 1+region0Count = num scale factor bands in first region of bigvals */
|
||||
int region1Count; /* 1+region1Count = num scale factor bands in second region of bigvals */
|
||||
int preFlag; /* for optional high frequency boost */
|
||||
int sfactScale; /* scaling of the scalefactors */
|
||||
int count1TableSelect; /* index of Huffman table for quad codewords */
|
||||
} SideInfoSub_t;
|
||||
|
||||
typedef struct SideInfo {
|
||||
int mainDataBegin;
|
||||
int privateBits;
|
||||
int scfsi[m_MAX_NCHAN][m_MAX_SCFBD]; /* 4 scalefactor bands per channel */
|
||||
} SideInfo_t;
|
||||
|
||||
typedef struct {
|
||||
int cbType; /* pure long = 0, pure short = 1, mixed = 2 */
|
||||
int cbEndS[3]; /* number nonzero short cb's, per subbblock */
|
||||
int cbEndSMax; /* max of cbEndS[] */
|
||||
int cbEndL; /* number nonzero long cb's */
|
||||
} CriticalBandInfo_t;
|
||||
|
||||
typedef struct DequantInfo {
|
||||
int workBuf[m_MAX_REORDER_SAMPS]; /* workbuf for reordering short blocks */
|
||||
} DequantInfo_t;
|
||||
|
||||
typedef struct HuffmanInfo {
|
||||
int huffDecBuf[m_MAX_NCHAN][m_MAX_NSAMP]; /* used both for decoded Huffman values and dequantized coefficients */
|
||||
int nonZeroBound[m_MAX_NCHAN]; /* number of coeffs in huffDecBuf[ch] which can be > 0 */
|
||||
int gb[m_MAX_NCHAN]; /* minimum number of guard bits in huffDecBuf[ch] */
|
||||
} HuffmanInfo_t;
|
||||
|
||||
typedef enum HuffTabType {
|
||||
noBits,
|
||||
oneShot,
|
||||
loopNoLinbits,
|
||||
loopLinbits,
|
||||
quadA,
|
||||
quadB,
|
||||
invalidTab
|
||||
} HuffTabType_t;
|
||||
|
||||
typedef struct HuffTabLookup {
|
||||
int linBits;
|
||||
int tabType; /*HuffTabType*/
|
||||
} HuffTabLookup_t;
|
||||
|
||||
typedef struct IMDCTInfo {
|
||||
int outBuf[m_MAX_NCHAN][m_BLOCK_SIZE][m_NBANDS]; /* output of IMDCT */
|
||||
int overBuf[m_MAX_NCHAN][m_MAX_NSAMP / 2]; /* overlap-add buffer (by symmetry, only need 1/2 size) */
|
||||
int numPrevIMDCT[m_MAX_NCHAN]; /* how many IMDCT's calculated in this channel on prev. granule */
|
||||
int prevType[m_MAX_NCHAN];
|
||||
int prevWinSwitch[m_MAX_NCHAN];
|
||||
int gb[m_MAX_NCHAN];
|
||||
} IMDCTInfo_t;
|
||||
|
||||
typedef struct BlockCount {
|
||||
int nBlocksLong;
|
||||
int nBlocksTotal;
|
||||
int nBlocksPrev;
|
||||
int prevType;
|
||||
int prevWinSwitch;
|
||||
int currWinSwitch;
|
||||
int gbIn;
|
||||
int gbOut;
|
||||
} BlockCount_t;
|
||||
|
||||
typedef struct ScaleFactorInfoSub { /* max bits in scalefactors = 5, so use char's to save space */
|
||||
char l[23]; /* [band] */
|
||||
char s[13][3]; /* [band][window] */
|
||||
} ScaleFactorInfoSub_t;
|
||||
|
||||
typedef struct ScaleFactorJS { /* used in MPEG 2, 2.5 intensity (joint) stereo only */
|
||||
int intensityScale;
|
||||
int slen[4];
|
||||
int nr[4];
|
||||
} ScaleFactorJS_t;
|
||||
|
||||
/* NOTE - could get by with smaller vbuf if memory is more important than speed
|
||||
* (in Subband, instead of replicating each block in FDCT32 you would do a memmove on the
|
||||
* last 15 blocks to shift them down one, a hardware style FIFO)
|
||||
*/
|
||||
typedef struct SubbandInfo {
|
||||
int vbuf[m_MAX_NCHAN * m_VBUF_LENGTH]; /* vbuf for fast DCT-based synthesis PQMF - double size for speed (no modulo indexing) */
|
||||
int vindex; /* internal index for tracking position in vbuf */
|
||||
} SubbandInfo_t;
|
||||
|
||||
typedef struct MP3DecInfo {
|
||||
/* buffer which must be large enough to hold largest possible main_data section */
|
||||
unsigned char mainBuf[m_MAINBUF_SIZE];
|
||||
/* special info for "free" bitrate files */
|
||||
int freeBitrateFlag;
|
||||
int freeBitrateSlots;
|
||||
/* user-accessible info */
|
||||
int bitrate;
|
||||
int nChans;
|
||||
int samprate;
|
||||
int nGrans; /* granules per frame */
|
||||
int nGranSamps; /* samples per granule */
|
||||
int nSlots;
|
||||
int layer;
|
||||
|
||||
int mainDataBegin;
|
||||
int mainDataBytes;
|
||||
int part23Length[m_MAX_NGRAN][m_MAX_NCHAN];
|
||||
} MP3DecInfo_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/* format = Q31
|
||||
* #define M_PI 3.14159265358979323846
|
||||
* double u = 2.0 * M_PI / 9.0;
|
||||
* float c0 = sqrt(3.0) / 2.0;
|
||||
* float c1 = cos(u);
|
||||
* float c2 = cos(2*u);
|
||||
* float c3 = sin(u);
|
||||
* float c4 = sin(2*u);
|
||||
*/
|
||||
|
||||
const int c9_0 = 0x6ed9eba1;
|
||||
const int c9_1 = 0x620dbe8b;
|
||||
const int c9_2 = 0x163a1a7e;
|
||||
const int c9_3 = 0x5246dd49;
|
||||
const int c9_4 = 0x7e0e2e32;
|
||||
|
||||
|
||||
|
||||
const int c3_0 = 0x6ed9eba1; /* format = Q31, cos(pi/6) */
|
||||
const int c6[3] = { 0x7ba3751d, 0x5a82799a, 0x2120fb83 }; /* format = Q31, cos(((0:2) + 0.5) * (pi/6)) */
|
||||
|
||||
/* format = Q31
|
||||
* cos(((0:8) + 0.5) * (pi/18))
|
||||
*/
|
||||
const uint32_t c18[9] = { 0x7f834ed0, 0x7ba3751d, 0x7401e4c1, 0x68d9f964, 0x5a82799a, 0x496af3e2, 0x36185aee, 0x2120fb83, 0x0b27eb5c};
|
||||
|
||||
/* scale factor lengths (num bits) */
|
||||
const char m_SFLenTab[16][2] = { {0, 0}, {0, 1}, {0, 2}, {0, 3}, {3, 0}, {1, 1}, {1, 2}, {1, 3},
|
||||
{2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}, {4, 2}, {4, 3}};
|
||||
|
||||
/* NRTab[size + 3*is_right][block type][partition]
|
||||
* block type index: 0 = (bt0,bt1,bt3), 1 = bt2 non-mixed, 2 = bt2 mixed
|
||||
* partition: scale factor groups (sfb1 through sfb4)
|
||||
* for block type = 2 (mixed or non-mixed) / by 3 is rolled into this table
|
||||
* (for 3 short blocks per long block)
|
||||
* see 2.4.3.2 in MPEG 2 (low sample rate) spec
|
||||
* stuff rolled into this table:
|
||||
* NRTab[x][1][y] --> (NRTab[x][1][y]) / 3
|
||||
* NRTab[x][2][>=1] --> (NRTab[x][2][>=1]) / 3 (first partition is long block)
|
||||
*/
|
||||
const char NRTab[6][3][4] = {
|
||||
{{ 6, 5, 5, 5}, {3, 3, 3, 3}, {6, 3, 3, 3}},
|
||||
{{ 6, 5, 7, 3}, {3, 3, 4, 2}, {6, 3, 4, 2}},
|
||||
{{11, 10, 0, 0}, {6, 6, 0, 0}, {6, 3, 6, 0}},
|
||||
{{ 7, 7, 7, 0}, {4, 4, 4, 0}, {6, 5, 4, 0}},
|
||||
{{ 6, 6, 6, 3}, {4, 3, 3, 2}, {6, 4, 3, 2}},
|
||||
{{ 8, 8, 5, 0}, {5, 4, 3, 0}, {6, 6, 3, 0}}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* optional pre-emphasis for high-frequency scale factor bands */
|
||||
const char preTab[22] = { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0 };
|
||||
|
||||
/* pow(2,-i/4) for i=0..3, Q31 format */
|
||||
const int pow14[4] PROGMEM = {
|
||||
0x7fffffff, 0x6ba27e65, 0x5a82799a, 0x4c1bf829
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Minimax polynomial approximation to pow(x, 4/3), over the range
|
||||
* poly43lo: x = [0.5, 0.7071]
|
||||
* poly43hi: x = [0.7071, 1.0]
|
||||
*
|
||||
* Relative error < 1E-7
|
||||
* Coefs are scaled by 4, 2, 1, 0.5, 0.25
|
||||
*/
|
||||
const unsigned int poly43lo[5] PROGMEM = { 0x29a0bda9, 0xb02e4828, 0x5957aa1b, 0x236c498d, 0xff581859 };
|
||||
const unsigned int poly43hi[5] PROGMEM = { 0x10852163, 0xd333f6a4, 0x46e9408b, 0x27c2cef0, 0xfef577b4 };
|
||||
|
||||
/* pow(2, i*4/3) as exp and frac */
|
||||
const int pow2exp[8] PROGMEM = { 14, 13, 11, 10, 9, 7, 6, 5 };
|
||||
|
||||
const int pow2frac[8] PROGMEM = {
|
||||
0x6597fa94, 0x50a28be6, 0x7fffffff, 0x6597fa94,
|
||||
0x50a28be6, 0x7fffffff, 0x6597fa94, 0x50a28be6
|
||||
};
|
||||
|
||||
const uint16_t m_HUFF_OFFSET_01= 0;
|
||||
const uint16_t m_HUFF_OFFSET_02= 9 + m_HUFF_OFFSET_01;
|
||||
const uint16_t m_HUFF_OFFSET_03= 65 + m_HUFF_OFFSET_02;
|
||||
const uint16_t m_HUFF_OFFSET_05= 65 + m_HUFF_OFFSET_03;
|
||||
const uint16_t m_HUFF_OFFSET_06=257 + m_HUFF_OFFSET_05;
|
||||
const uint16_t m_HUFF_OFFSET_07=129 + m_HUFF_OFFSET_06;
|
||||
const uint16_t m_HUFF_OFFSET_08=110 + m_HUFF_OFFSET_07;
|
||||
const uint16_t m_HUFF_OFFSET_09=280 + m_HUFF_OFFSET_08;
|
||||
const uint16_t m_HUFF_OFFSET_10= 93 + m_HUFF_OFFSET_09;
|
||||
const uint16_t m_HUFF_OFFSET_11=320 + m_HUFF_OFFSET_10;
|
||||
const uint16_t m_HUFF_OFFSET_12=296 + m_HUFF_OFFSET_11;
|
||||
const uint16_t m_HUFF_OFFSET_13=185 + m_HUFF_OFFSET_12;
|
||||
const uint16_t m_HUFF_OFFSET_15=497 + m_HUFF_OFFSET_13;
|
||||
const uint16_t m_HUFF_OFFSET_16=580 + m_HUFF_OFFSET_15;
|
||||
const uint16_t m_HUFF_OFFSET_24=651 + m_HUFF_OFFSET_16;
|
||||
|
||||
const int huffTabOffset[m_HUFF_PAIRTABS] PROGMEM = {
|
||||
0, m_HUFF_OFFSET_01, m_HUFF_OFFSET_02, m_HUFF_OFFSET_03,
|
||||
0, m_HUFF_OFFSET_05, m_HUFF_OFFSET_06, m_HUFF_OFFSET_07,
|
||||
m_HUFF_OFFSET_08, m_HUFF_OFFSET_09, m_HUFF_OFFSET_10, m_HUFF_OFFSET_11,
|
||||
m_HUFF_OFFSET_12, m_HUFF_OFFSET_13, 0, m_HUFF_OFFSET_15,
|
||||
m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16,
|
||||
m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16,
|
||||
m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24,
|
||||
m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24,};
|
||||
|
||||
const HuffTabLookup_t huffTabLookup[m_HUFF_PAIRTABS] PROGMEM = {
|
||||
{ 0, noBits },
|
||||
{ 0, oneShot },
|
||||
{ 0, oneShot },
|
||||
{ 0, oneShot },
|
||||
{ 0, invalidTab },
|
||||
{ 0, oneShot },
|
||||
{ 0, oneShot },
|
||||
{ 0, loopNoLinbits },
|
||||
{ 0, loopNoLinbits },
|
||||
{ 0, loopNoLinbits },
|
||||
{ 0, loopNoLinbits },
|
||||
{ 0, loopNoLinbits },
|
||||
{ 0, loopNoLinbits },
|
||||
{ 0, loopNoLinbits },
|
||||
{ 0, invalidTab },
|
||||
{ 0, loopNoLinbits },
|
||||
{ 1, loopLinbits },
|
||||
{ 2, loopLinbits },
|
||||
{ 3, loopLinbits },
|
||||
{ 4, loopLinbits },
|
||||
{ 6, loopLinbits },
|
||||
{ 8, loopLinbits },
|
||||
{ 10, loopLinbits },
|
||||
{ 13, loopLinbits },
|
||||
{ 4, loopLinbits },
|
||||
{ 5, loopLinbits },
|
||||
{ 6, loopLinbits },
|
||||
{ 7, loopLinbits },
|
||||
{ 8, loopLinbits },
|
||||
{ 9, loopLinbits },
|
||||
{ 11, loopLinbits },
|
||||
{ 13, loopLinbits },
|
||||
};
|
||||
|
||||
|
||||
const int quadTabOffset[2] PROGMEM = {0, 64};
|
||||
const int quadTabMaxBits[2] PROGMEM = {6, 4};
|
||||
|
||||
/* indexing = [version][samplerate index]
|
||||
* sample rate of frame (Hz)
|
||||
*/
|
||||
const int samplerateTab[3][3] PROGMEM = {
|
||||
{ 44100, 48000, 32000 }, /* MPEG-1 */
|
||||
{ 22050, 24000, 16000 }, /* MPEG-2 */
|
||||
{ 11025, 12000, 8000 }, /* MPEG-2.5 */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* indexing = [version][layer]
|
||||
* number of samples in one frame (per channel)
|
||||
*/
|
||||
const int/*short*/samplesPerFrameTab[3][3] PROGMEM = { { 384, 1152, 1152 }, /* MPEG1 */
|
||||
{ 384, 1152, 576 }, /* MPEG2 */
|
||||
{ 384, 1152, 576 }, /* MPEG2.5 */
|
||||
};
|
||||
|
||||
/* layers 1, 2, 3 */
|
||||
const short bitsPerSlotTab[3] = { 32, 8, 8 };
|
||||
|
||||
/* indexing = [version][mono/stereo]
|
||||
* number of bytes in side info section of bitstream
|
||||
*/
|
||||
const int/*short*/sideBytesTab[3][2] PROGMEM = { { 17, 32 }, /* MPEG-1: mono, stereo */
|
||||
{ 9, 17 }, /* MPEG-2: mono, stereo */
|
||||
{ 9, 17 }, /* MPEG-2.5: mono, stereo */
|
||||
};
|
||||
|
||||
/* indexing = [version][sampleRate][long (.l) or short (.s) block]
|
||||
* sfBandTable[v][s].l[cb] = index of first bin in critical band cb (long blocks)
|
||||
* sfBandTable[v][s].s[cb] = index of first bin in critical band cb (short blocks)
|
||||
*/
|
||||
const SFBandTable_t sfBandTable[3][3] PROGMEM = {
|
||||
{ /* MPEG-1 (44, 48, 32 kHz) */
|
||||
{ {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576 },
|
||||
{0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192} },
|
||||
{ {0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576 },
|
||||
{0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80, 100, 126, 192} },
|
||||
{ {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576 },
|
||||
{0, 4, 8, 12, 16, 22, 30, 42, 58, 78, 104, 138, 180, 192} } },
|
||||
{ /* MPEG-2 (22, 24, 16 kHz) */
|
||||
{ {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
|
||||
{0, 4, 8, 12, 18, 24, 32, 42, 56, 74, 100, 132, 174, 192} },
|
||||
{ {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 332, 394, 464, 540, 576 },
|
||||
{0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 136, 180, 192} },
|
||||
{ {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
|
||||
{0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192} }, },
|
||||
{ /* MPEG-2.5 (11, 12, 8 kHz) */
|
||||
{ {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
|
||||
{0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 } },
|
||||
{ {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
|
||||
{0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 } },
|
||||
{ {0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, 572, 574, 576 },
|
||||
{0, 8, 16, 24, 36, 52, 72, 96, 124, 160, 162, 164, 166, 192 } }, },
|
||||
};
|
||||
|
||||
|
||||
/* indexing = [intensity scale on/off][left/right]
|
||||
* format = Q30, range = [0.0, 1.414]
|
||||
*
|
||||
* illegal intensity position scalefactors (see comments on ISFMpeg1)
|
||||
*/
|
||||
const int ISFIIP[2][2] PROGMEM = {
|
||||
{0x40000000, 0x00000000}, /* mid-side off */
|
||||
{0x40000000, 0x40000000}, /* mid-side on */
|
||||
};
|
||||
|
||||
const unsigned char uniqueIDTab[8] = {0x5f, 0x4b, 0x43, 0x5f, 0x5f, 0x4a, 0x52, 0x5f};
|
||||
|
||||
/* anti-alias coefficients - see spec Annex B, table 3-B.9
|
||||
* csa[0][i] = CSi, csa[1][i] = CAi
|
||||
* format = Q31
|
||||
*/
|
||||
const uint32_t csa[8][2] PROGMEM = {
|
||||
{0x6dc253f0, 0xbe2500aa},
|
||||
{0x70dcebe4, 0xc39e4949},
|
||||
{0x798d6e73, 0xd7e33f4a},
|
||||
{0x7ddd40a7, 0xe8b71176},
|
||||
{0x7f6d20b7, 0xf3e4fe2f},
|
||||
{0x7fe47e40, 0xfac1a3c7},
|
||||
{0x7ffcb263, 0xfe2ebdc6},
|
||||
{0x7fffc694, 0xff86c25d},
|
||||
};
|
||||
|
||||
/* format = Q30, right shifted by 12 (sign bits only in top 12 - undo this when rounding to short)
|
||||
* this is to enable early-terminating multiplies on ARM
|
||||
* range = [-1.144287109, 1.144989014]
|
||||
* max gain of filter (per output sample) ~= 2.731
|
||||
*
|
||||
* new (properly sign-flipped) values
|
||||
* - these actually are correct to 32 bits, (floating-pt coefficients in spec
|
||||
* chosen such that only ~20 bits are required)
|
||||
*
|
||||
* Reordering - see table 3-B.3 in spec (appendix B)
|
||||
*
|
||||
* polyCoef[i] =
|
||||
* D[ 0, 32, 64, ... 480], i = [ 0, 15]
|
||||
* D[ 1, 33, 65, ... 481], i = [ 16, 31]
|
||||
* D[ 2, 34, 66, ... 482], i = [ 32, 47]
|
||||
* ...
|
||||
* D[15, 47, 79, ... 495], i = [240,255]
|
||||
*
|
||||
* also exploits symmetry: D[i] = -D[512 - i], for i = [1, 255]
|
||||
*
|
||||
* polyCoef[256, 257, ... 263] are for special case of sample 16 (out of 0)
|
||||
* see PolyphaseStereo() and PolyphaseMono()
|
||||
*/
|
||||
|
||||
// prototypes
|
||||
bool MP3Decoder_AllocateBuffers(void);
|
||||
void MP3Decoder_FreeBuffers();
|
||||
int MP3Decode( unsigned char *inbuf, int *bytesLeft, short *outbuf, int useSize);
|
||||
void MP3GetLastFrameInfo();
|
||||
int MP3GetNextFrameInfo(unsigned char *buf);
|
||||
int MP3FindSyncWord(unsigned char *buf, int nBytes);
|
||||
int MP3GetSampRate();
|
||||
int MP3GetChannels();
|
||||
int MP3GetBitsPerSample();
|
||||
int MP3GetBitrate();
|
||||
int MP3GetOutputSamps();
|
||||
|
||||
//internally used
|
||||
void MP3Decoder_ClearBuffer(void);
|
||||
void PolyphaseMono(short *pcm, int *vbuf, const uint32_t *coefBase);
|
||||
void PolyphaseStereo(short *pcm, int *vbuf, const uint32_t *coefBase);
|
||||
void SetBitstreamPointer(BitStreamInfo_t *bsi, int nBytes, unsigned char *buf);
|
||||
unsigned int GetBits(BitStreamInfo_t *bsi, int nBits);
|
||||
int CalcBitsUsed(BitStreamInfo_t *bsi, unsigned char *startBuf, int startOffset);
|
||||
int DequantChannel(int *sampleBuf, int *workBuf, int *nonZeroBound, SideInfoSub_t *sis, ScaleFactorInfoSub_t *sfis, CriticalBandInfo_t *cbi);
|
||||
void MidSideProc(int x[m_MAX_NCHAN][m_MAX_NSAMP], int nSamps, int mOut[2]);
|
||||
void IntensityProcMPEG1(int x[m_MAX_NCHAN][m_MAX_NSAMP], int nSamps, ScaleFactorInfoSub_t *sfis, CriticalBandInfo_t *cbi, int midSideFlag, int mixFlag, int mOut[2]);
|
||||
void IntensityProcMPEG2(int x[m_MAX_NCHAN][m_MAX_NSAMP], int nSamps, ScaleFactorInfoSub_t *sfis, CriticalBandInfo_t *cbi, ScaleFactorJS_t *sfjs, int midSideFlag, int mixFlag, int mOut[2]);
|
||||
void FDCT32(int *x, int *d, int offset, int oddBlock, int gb);// __attribute__ ((section (".data")));
|
||||
void FreeBuffers();
|
||||
int CheckPadBit();
|
||||
int UnpackFrameHeader(unsigned char *buf);
|
||||
int UnpackSideInfo(unsigned char *buf);
|
||||
int DecodeHuffman( unsigned char *buf, int *bitOffset, int huffBlockBits, int gr, int ch);
|
||||
int MP3Dequantize( int gr);
|
||||
int IMDCT( int gr, int ch);
|
||||
int UnpackScaleFactors( unsigned char *buf, int *bitOffset, int bitsAvail, int gr, int ch);
|
||||
int Subband(short *pcmBuf);
|
||||
short ClipToShort(int x, int fracBits);
|
||||
void RefillBitstreamCache(BitStreamInfo_t *bsi);
|
||||
void UnpackSFMPEG1(BitStreamInfo_t *bsi, SideInfoSub_t *sis, ScaleFactorInfoSub_t *sfis, int *scfsi, int gr, ScaleFactorInfoSub_t *sfisGr0);
|
||||
void UnpackSFMPEG2(BitStreamInfo_t *bsi, SideInfoSub_t *sis, ScaleFactorInfoSub_t *sfis, int gr, int ch, int modeExt, ScaleFactorJS_t *sfjs);
|
||||
int MP3FindFreeSync(unsigned char *buf, unsigned char firstFH[4], int nBytes);
|
||||
void MP3ClearBadFrame( short *outbuf);
|
||||
int DecodeHuffmanPairs(int *xy, int nVals, int tabIdx, int bitsLeft, unsigned char *buf, int bitOffset);
|
||||
int DecodeHuffmanQuads(int *vwxy, int nVals, int tabIdx, int bitsLeft, unsigned char *buf, int bitOffset);
|
||||
int DequantBlock(int *inbuf, int *outbuf, int num, int scale);
|
||||
void AntiAlias(int *x, int nBfly);
|
||||
void WinPrevious(int *xPrev, int *xPrevWin, int btPrev);
|
||||
int FreqInvertRescale(int *y, int *xPrev, int blockIdx, int es);
|
||||
void idct9(int *x);
|
||||
int IMDCT36(int *xCurr, int *xPrev, int *y, int btCurr, int btPrev, int blockIdx, int gb);
|
||||
void imdct12(int *x, int *out);
|
||||
int IMDCT12x3(int *xCurr, int *xPrev, int *y, int btPrev, int blockIdx, int gb);
|
||||
int HybridTransform(int *xCurr, int *xPrev, int y[m_BLOCK_SIZE][m_NBANDS], SideInfoSub_t *sis, BlockCount_t *bc);
|
||||
inline uint64_t SAR64(uint64_t x, int n) {return x >> n;}
|
||||
inline int MULSHIFT32(int x, int y) { int z; z = (uint64_t) x * (uint64_t) y >> 32; return z;}
|
||||
inline uint64_t MADD64(uint64_t sum64, int x, int y) {sum64 += (uint64_t) x * (uint64_t) y; return sum64;}/* returns 64-bit value in [edx:eax] */
|
||||
inline uint64_t xSAR64(uint64_t x, int n){return x >> n;}
|
||||
inline int FASTABS(int x){ return __builtin_abs(x);} //xtensa has a fast abs instruction //fb
|
||||
#define CLZ(x) __builtin_clz(x) //fb
|
||||
Reference in New Issue
Block a user