
- FLAC container input and output support - FLAC container analyser - FLAC codec support in EBML input and output
128 lines
3.4 KiB
C++
128 lines
3.4 KiB
C++
#include "flac.h"
|
|
|
|
/// Checks the first 4 bytes for the string "flaC". Implementing a basic FLAC header check,
|
|
/// returning true if it is, false if not.
|
|
bool FLAC::is_header(const char *header){
|
|
if (header[0] != 'f') return false;
|
|
if (header[1] != 'L') return false;
|
|
if (header[2] != 'a') return false;
|
|
if (header[3] != 'C') return false;
|
|
return true;
|
|
}// FLAC::is_header
|
|
|
|
size_t FLAC::utfBytes(char p){
|
|
if ((p & 0x80) == 0x00){return 1;}
|
|
if ((p & 0xE0) == 0xC0){return 2;}
|
|
if ((p & 0xF0) == 0xE0){return 3;}
|
|
if ((p & 0xF8) == 0xF0){return 4;}
|
|
if ((p & 0xFC) == 0xF8){return 5;}
|
|
if ((p & 0xFE) == 0xFC){return 6;}
|
|
if ((p & 0xFF) == 0xFE){return 7;}
|
|
return 9;
|
|
}
|
|
|
|
uint32_t FLAC::utfVal(char *p){
|
|
size_t bytes = utfBytes(*p);
|
|
uint32_t ret = 0;
|
|
|
|
if (bytes == 1){
|
|
ret = (uint32_t)*p;
|
|
}else if (bytes == 2){
|
|
ret = (uint32_t)(*p & 0x1F) << 6;
|
|
ret = ret | (*(p + 1) & 0x3f);
|
|
}else if (bytes == 3){
|
|
ret = (uint32_t)(*p & 0x1F) << 6;
|
|
ret = (ret | (*(p + 1) & 0x3f)) << 6;
|
|
ret = ret | (*(p + 2) & 0x3f);
|
|
}else if (bytes == 4){
|
|
ret = (uint32_t)(*p & 0x1F) << 6;
|
|
ret = (ret | (*(p + 1) & 0x3f)) << 6;
|
|
ret = (ret | (*(p + 2) & 0x3f)) << 6;
|
|
ret = ret | (*(p + 3) & 0x3f);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
FLAC::Frame::Frame(char *pkt){
|
|
data = pkt;
|
|
if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8){
|
|
WARN_MSG("Sync code incorrect! Ignoring FLAC frame");
|
|
FAIL_MSG("%x %x", data[0], data[1]);
|
|
data = 0;
|
|
}
|
|
}
|
|
|
|
uint16_t FLAC::Frame::samples(){
|
|
if (!data){return 0;}
|
|
switch ((data[2] & 0xF0) >> 4){
|
|
case 0: return 0; // reserved
|
|
case 1: return 192;
|
|
case 2: return 576;
|
|
case 3: return 1152;
|
|
case 4: return 2304;
|
|
case 5: return 4608;
|
|
case 6: return 1; // 1b at end
|
|
case 7: return 2; // 2b at end
|
|
default: return 256 << (((data[2] & 0xf0) >> 4) - 8);
|
|
}
|
|
}
|
|
uint32_t FLAC::Frame::rate(){
|
|
if (!data){return 0;}
|
|
switch (data[2] & 0x0F){
|
|
case 0: return 0; // get from STREAMINFO
|
|
case 1: return 88200;
|
|
case 2: return 176400;
|
|
case 3: return 192000;
|
|
case 4: return 8000;
|
|
case 5: return 16000;
|
|
case 6: return 22050;
|
|
case 7: return 24000;
|
|
case 8: return 32000;
|
|
case 9: return 44100;
|
|
case 10: return 48000;
|
|
case 11: return 96000;
|
|
case 12: return 1; // 1b at end, *1000
|
|
case 13: return 2; // 2b at end
|
|
case 14: return 3; // 2b at end, *10
|
|
case 15: return 0; // invalid, get from STREAMINFO
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
uint8_t FLAC::Frame::channels(){
|
|
if (!data){return 0;}
|
|
uint8_t ret = ((data[3] & 0xF0) >> 4) + 1;
|
|
if (ret > 8 && ret < 12){return 2;}// special stereo
|
|
return ret;
|
|
}
|
|
uint8_t FLAC::Frame::size(){
|
|
if (!data){return 0;}
|
|
switch (data[3] & 0x0E){
|
|
case 0: return 0; // get from STREAMINFO
|
|
case 1: return 8;
|
|
case 2: return 12;
|
|
case 3: return 0; // reserved
|
|
case 4: return 16;
|
|
case 5: return 20;
|
|
case 6: return 24;
|
|
case 7: return 0; // reserved
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
uint32_t FLAC::Frame::utfVal(){
|
|
return FLAC::utfVal(data + 4);
|
|
}
|
|
|
|
std::string FLAC::Frame::toPrettyString(){
|
|
if (!data){return "Invalid frame";}
|
|
std::stringstream r;
|
|
r << "FLAC frame" << std::endl;
|
|
r << " Block size: " << ((data[1] & 0x1) ? "variable" : "fixed") << std::endl;
|
|
r << " Samples: " << samples() << std::endl;
|
|
r << " Rate: " << rate() << "Hz" << std::endl;
|
|
r << " Channels: " << (int)channels() << std::endl;
|
|
r << " Size: " << (int)size() << "-bit" << std::endl;
|
|
return r.str();
|
|
}
|