#include <iostream>
#include <cstdint>
#include <cassert>
 
//----------[ generischer Kram ]----------
 
// extracts a sequence of bits from an unsigned char array
// at arbitrary bit positions (most significant bits first)
std::uint32_t get_bits_msbf(
    const unsigned char data[],
    unsigned bit_offset, unsigned nbits)
{
    // TODO: Diese Implementierung kann man vielleicht noch vereinfachen.
    assert(nbits <= 32);
    if (nbits == 0) return 0u;
    data += bit_offset / 8;
    bit_offset &= 7;
    unsigned tlen = 8 - bit_offset;
    std::uint32_t temp = *data & (0xFFu >> bit_offset);
    if (tlen >= nbits)
        return temp >> (tlen-nbits);
    while (tlen+8 <= nbits) {
        ++data;
        temp = (temp << 8) | (*data & 0xFFu);
        tlen += 8;
    }
    unsigned missing = nbits - tlen;
    if (missing) {
        ++data;
        temp = (temp << missing) | (*data >> (8-missing));
    }
    return temp;
}
 
template<unsigned BitOffset, unsigned BitLen, class MessageTag=void>
struct field
{
    typedef MessageTag message_tag;
    static const unsigned bit_offset = BitOffset;
    static const unsigned bit_len = BitLen;
};
 
template<class MessageTag=void>
struct message_ptr
{
    const unsigned char* data;
    unsigned length;
 
    explicit message_ptr(const unsigned char *ptr, unsigned len)
        : data(ptr), length(len)
    {}
 
    template<unsigned BitOffset, unsigned BitLen>
    std::uint32_t get(field<BitOffset,BitLen,MessageTag>) const
    {
        assert(BitOffset+BitLen <= 8*length);
        return get_bits_msbf(data,BitOffset,BitLen);
    }
};
 
//----------[ Anwendungsfall ]----------
 
namespace mp3_stuff {
 
struct frame_header_tag {};
const field<0,11,frame_header_tag> sync = {};
const field<11,2,frame_header_tag> mpegid = {};
const field<13,2,frame_header_tag> layer = {};
const field<15,1,frame_header_tag> protection_bit = {};
const field<16,4,frame_header_tag> bitrate_index = {};
const field<20,2,frame_header_tag> sampling_rate_index = {};
const field<22,1,frame_header_tag> padding_bit = {};
const field<23,1,frame_header_tag> private_bit = {};
const field<24,2,frame_header_tag> channel_mode = {};
const field<26,2,frame_header_tag> cm_extension = {};
const field<28,1,frame_header_tag> copyrighted_bit = {};
const field<29,1,frame_header_tag> original_bit = {};
const field<30,2,frame_header_tag> emphasis_mode = {};
 
static const char* const mpegid2str[] = {"MPEG 2.5", "reserved", "MPEG 2", "MPEG 1"};
static const char* const chanmodes[] = {"Stereo", "Joint Stereo", "Dual Channel", "Mono"};
static const long srate[] = {44100,48000,32000};
 
} // namespace mp3_stuff
 
void test()
{
    using namespace std;
    using namespace mp3_stuff;
    unsigned char data[] = {0xFF, 0xFB, 0xA0, 0x64};
    message_ptr<frame_header_tag> mptr (data,4);
    if (mptr.get(sync) == 0x7FF) {
        cout << "MPEG          : " << mpegid2str[mptr.get(mpegid)] << endl;
        cout << "Layer         : " << 4-mptr.get(layer) << endl;
        cout << "Bitrate index : " << mptr.get(bitrate_index) << endl;
        const int srdivisor = 4-mptr.get(mpegid);
        cout << "Sampling rate : " << srate[mptr.get(sampling_rate_index)]/srdivisor << endl;
        cout << "Channel mode  : " << chanmodes[mptr.get(channel_mode)] << endl;
    } else {
        cout << "Sync bits invalid\n";
    }
}
 
int main()
{
    test();
}