23 Stimmen

Wie definiert man einen 24-Bit-Datentyp in C?

Ich werde viel mit 24-Bit-Audiodaten arbeiten müssen. Was ist nur unsigned int aber statt 32bit, es ist 24bit. Also, was ist der einfachere Weg zu definieren und arbeiten mit 24-Bit-Daten in C?

17voto

Michael Foukarakis Punkte 37819

Je nach Anforderung würde ich dafür entweder ein Bitfeld verwenden:

struct int24{
    unsigned int data : 24;
};

Oder, wenn eine Trennung einfacher ist, verwenden Sie einfach 3 Bytes ( unsigned char s). Sie können erzwingen, dass die Struktur gepackt wird, wenn Sie nicht wollen, dass sie aufgefüllt wird.

[edit: Ich sehe die C++ Tag wurde entfernt, aber ich lasse es trotzdem hier] Wenn Sie sich mit C++ besser auskennen, können Sie etwas wie das Folgende verwenden:

const int INT24_MAX = 8388607;

class Int24
{
protected:
    unsigned char value[3];
public:
    Int24(){}

    Int24( const Int24& val )
    {
        *this   = val;
    }

    operator int() const
    {
        /* Sign extend negative quantities */
        if( value[2] & 0x80 ) {
            return (0xff << 24) | (value[2] << 16)
                                | (value[1] <<  8)
                                |  value[0];
        } else {
            return (value[2] << 16)
                 | (value[1] <<  8)
                 |  value[0];
        }
    }

    Int24& operator= (const Int24& input)
    {
        value[0]   = input.value[0];
        value[1]   = input.value[1];
        value[2]   = input.value[2];

        return *this;
    }

    Int24& operator= (const int input)
    {
        value[0]   = ((unsigned char*)&input)[0];
        value[1]   = ((unsigned char*)&input)[1];
        value[2]   = ((unsigned char*)&input)[2];

        return *this;
    }

    Int24 operator+ (const Int24& val) const
    {
        return Int24( (int)*this + (int)val );
    }

    Int24 operator- (const Int24& val) const
    {
        return Int24( (int)*this - (int)val );
    }

    Int24 operator* (const Int24& val) const
    {
        return Int24( (int)*this * (int)val );
    }

    Int24 operator/ (const Int24& val) const
    {
        return Int24( (int)*this / (int)val );
    }

    Int24& operator+= (const Int24& val)
    {
        *this   = *this + val;
        return *this;
    }

    Int24& operator-= (const Int24& val)
    {
        *this   = *this - val;
        return *this;
    }

    Int24& operator*= (const Int24& val)
    {
        *this   = *this * val;
        return *this;
    }

    Int24& operator/= (const Int24& val)
    {
        *this   = *this / val;
        return *this;
    }

    Int24 operator>> (const int val) const
    {
        return Int24( (int)*this >> val );
    }

    Int24 operator<< (const int val) const
    {
        return Int24( (int)*this << val );
    }

    operator bool() const
    {
        return (int)*this != 0;
    }

    bool operator! () const
    {
        return !((int)*this);
    }

    Int24 operator- ()
    {
        return Int24( -(int)*this );
    }

    bool operator== (const Int24& val) const
    {
        return (int)*this == (int)val;
    }

    bool operator!= (const Int24& val) const
    {
        return (int)*this != (int)val;
    }

    bool operator>= (const Int24& val) const
    {
        return (int)*this >= (int)val;
    }

    bool operator<= (const Int24& val) const
    {
        return (int)*this <= (int)val;
    }

    /* Define all operations you need below.. */

5voto

Der saubere und portable Weg, vorausgesetzt, Ihre Samples sind Little Endian und unsigned:

static inline uint32_t getsample(uint8_t *buf, size_t pos)
{
    return buf[3*pos] + 256UL*buf[3*pos+1] + 65536UL*buf[3*pos+2];
}

static inline void putsample(uint8_t *buf, size_t pos, uint32_t sample)
{
    buf[3*pos]=sample;
    buf[3*pos+1]=sample/256;
    buf[3*pos+2]=sample/65536;
}

Die Anpassung an die Signaturwerte erfordert etwas mehr Arbeit, vor allem, wenn Sie das System portabel halten wollen. Beachten Sie, dass die Leistung viel besser sein könnte, wenn Sie ein ganzes Fenster von Samples in ein vernünftigeres Format konvertieren, bevor Sie es verarbeiten, und dann zurück konvertieren, wenn Sie fertig sind.

1voto

datenwolf Punkte 154484

Verwenden Sie einen Datentyp, der groß genug ist, um 24 Bit an Daten zu speichern. Das sind int32_t o uint32_t beide definiert in stdint.h

Da Sie mit Audiodaten arbeiten, wollen Sie, dass die Addition funktioniert (Sie brauchen sie zum Mischen). Außerdem ist es nicht schlecht, einige zusätzliche 8 Bit zur Verfügung zu haben, da man dadurch etwa 24 dB zusätzlichen Dynamikbereich erhält, den man beim Mischen mehrerer Quellen benötigt, die den 24-Bit-Dynamikbereich voll ausnutzen.

Beachten Sie, dass Sie gerade nach einem Datentyp für 24-Bit-Samples gefragt haben. Wenn Sie einen dicht gepackten Strom von 24-Bit-Sample-Frames lesen wollen, müssen Sie diesen aufteilen. Zuerst müssen Sie wissen, ob der Stream Big Endian o Low-Endian . Dann können Sie den Datenstrom mit einer ähnlichen Methode in Samples umwandeln:

uint32_t bitstream_BE_to_sample(uint8_t bits[3])
{
    return (bits[0] << 16) | (bits[1] << 8) | (bits[2]);
}

uint32_t bitstream_LE_to_sample(uint8_t bits[3])
{
    return (bits[2] << 16) | (bits[1] << 8) | (bits[0]);
}

uint8_t *bitstream;
uint32_t *samples;
for(;;) {
    *samples = bitstream_XX_to_sample(bitstream);
    samples++;
    bistream += 3;

    if(end_of_bitstream())
         break;
}

-1voto

Maxim Egorushkin Punkte 125210

Etwas in dieser Art:

struct Uint24
{
    unsigned char bits[3]; // assuming char is 8 bits

    Uint24()
        : bits()
    {}

    Uint24(unsigned val) {
        *this = val;
    }

    Uint24& operator=(unsigned val) {
        // store as little-endian
        bits[2] = val >> 16 & 0xff;
        bits[1] = val >> 8 & 0xff;
        bits[0] = val & 0xff;
        return *this;
    }

    unsigned as_unsigned() const {
        return bits[0] | bits[1] << 8 | bits[2] << 16;
    }
};

-3voto

Dan Punkte 12047

Sie könnten etwa so vorgehen;

union u32to24 {
    unsigned int i;
    char c[3];
};

Geben Sie in Ihrem Code die Werte mit u32to24.i zum Beispiel

u32to24 val = //...

val.i += foo
val.i -= bar
// etc

dann die Zeichen ausgeben, um die 24 Bits zu erhalten

fprintf("%c%c%c",val.c[0],val.c[1],val.c[2]);

Vorbehalt: Dies ist das erste, was mir in den Sinn kommt, daher kann es Fehler geben und es gibt vielleicht bessere Methoden, dies zu tun.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X