Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Easy Analog Data Compression


Listing 2: Partial listing of decoder.cpp

Listing 2: Partial listing of decoder.cpp

class TDecoder
{
    private: TDecoder(); 
    // no default constructor wanted
    
    public: TDecoder(vector<int> &tiDestination);
    // init the TDecoder and pass a vector whereto decoded data shall
    // be written;

    public: void Decode(WORD wCode);
    // decode the word wCode and push_back the result into tiDestination

    private: int DeltaDecode(int iDelta); 

    int miXsample;      
    // the untouched fraction of the last 16-bit code passed to Decode()

    int miXbitsTaken; 
    // denotes what number of bits are valid in miXsample

    int miBitWidthOfCode; 
    // holds the bit width of the code

    int miAbsValueCoded;
    // this holds the number of WORDs left that code an absolute value

    int mpiLastSamplesDiv3[3];
    // usually holds the last 3 decoded samples

    int miSamples2MSBidentical;
// this counter is used for the reduction of the bit width (in
    // the adaption)

    vector<int> *mptiDestination;
    // pointer to the result vector

    static const int mpiABSCODE[17];        
    static const int mpiOVFLCODE[16];       
    static const int mpiALIGNCODE[16];      
    static const int mpiSIGNEXTENSION[16];
};


const int TDecoder::mpiABSCODE[17] = { ... }; // as in listing 1
const int TDecoder::mpiOVFLCODE[16] = { ... }; // as in listing 1
const int TDecoder::mpiALIGNCODE[16] = { ... }; // as in listing 1

const int TDecoder::mpiSIGNEXTENSION[16] =
{
    // the value at index i denotes a bitmask for 32-bits sign extension 
    // for an i-bits value
    0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, 0xFFFFFFF0,
    0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, 0xFFFFFF00,
    0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800, 0xFFFFF000,
    0xFFFFE000, 0xFFFFC000, 0xFFFF8000, 0xFFFF0000
};


TDecoder::TDecoder(vector<int> &tiDestination):
    miXsample(0), 
    miXbitsTaken(0), 
    miBitWidthOfCode(6), 
    miAbsValueCoded(0),
    miSamples2MSBidentical(0),
    mptiDestination(&tiDestination) 
{
    assert( sizeof(int) >= 4 ); // TDecoder does not run on 16-bit
                                // platforms
    for(int i = 0; i < 3; i++) mpiLastSamplesDiv3[i] = 0;
}


int TDecoder::DeltaDecode(int iDelta)
{
    int iPrediction = 4 * mpiLastSamplesDiv3[2] + mpiLastSamplesDiv3[1] - 
                        2 * mpiLastSamplesDiv3[0];

    int iDecodedSample = iPrediction + iDelta;
    mpiLastSamplesDiv3[0] = mpiLastSamplesDiv3[1];
    mpiLastSamplesDiv3[1] = mpiLastSamplesDiv3[2];
    mpiLastSamplesDiv3[2] = iDecodedSample / 3;
    return iDecodedSample;
}


void TDecoder::Decode(WORD wCode)
{
    unsigned uiCode = wCode; // use full 32-bit register width

    if( miAbsValueCoded == 1 )
    {
        miXsample = uiCode;
        if (uiCode & 0x8000) miXsample -=0x10000;  // unsigned -> int16
                                                   // conversion
        (*mptiDestination).push_back(miXsample);
        mpiLastSamplesDiv3[0] = miXsample/3;       // update for
                                                   // delta encoding
        mpiLastSamplesDiv3[1] = miXsample/3;
        mpiLastSamplesDiv3[2] = miXsample/3;
        miAbsValueCoded--;                   // switch back to delta
                                             // encoding
        miXsample = 0x0000;                  // reset buffered sub-word
    }
    else 
    {
        // a delta encoded value, not necessarily aligned with a word
        // boundary has been received
        uiCode <<= miXbitsTaken;  // shift it left to and combine it with
        miXsample |= uiCode;      // a buffered rest of preceding iCode:s
        miXbitsTaken += 16;       // 16 new bits to decode were passed

        while( miXbitsTaken >= miBitWidthOfCode )
        {
            // cut out a complete code; reduce contents of the buffer by
            // the code cut out; reduce number of valid bits accordingly
            int iSubword = miXsample & mpiABSCODE[miBitWidthOfCode]; 
            int iSignBitMask = 1 << (miBitWidthOfCode - 1);
            miXsample >>= miBitWidthOfCode;
            miXbitsTaken -= miBitWidthOfCode;

            int iMaxBitMask = 3 << (miBitWidthOfCode - 2);

            if( iSignBitMask & iSubword)
            {
                // a negative number was coded; sign extension is needed
                // as well for the comparison to mpiALIGNCODE[] as for
                // delta decoding
                iSubword |= mpiSIGNEXTENSION[miBitWidthOfCode - 1];
            }                
        
            if( iSubword == mpiOVFLCODE[miBitWidthOfCode - 1] )
            {
                miBitWidthOfCode++;  // increase bit width of code
                miSamples2MSBidentical = 0;
            }
            else if( iSubword == mpiABSCODE[miBitWidthOfCode - 1] )
            {
                miAbsValueCoded = 1;
                miXbitsTaken = 0;
                miXsample = 0;
            }
            else if( iSubword == mpiALIGNCODE[miBitWidthOfCode - 1] )
            {
                miXbitsTaken = 0;
                miXsample = 0;
            }
            else
            {
                if( (iSubword & iMaxBitMask) == 0x0000 || 
                    (iSubword & iMaxBitMask) == iMaxBitMask)
                {
                    miSamples2MSBidentical++;
                    if ((miSamples2MSBidentical == BIT_REDUCTION_LENGTH) &&
                        (miBitWidthOfCode > MIN_BIT_WIDTH))  
                    {
                        miBitWidthOfCode--;
                        miSamples2MSBidentical = 0;
                    }
                }
                else
                {
                    miSamples2MSBidentical = 0;
                }

                int iNewSample = DeltaDecode( iSubword );
                (*mptiDestination).push_back( iNewSample );
             }
        } // while
    }
} // TDecoder::Decode()


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.