6 Stimmen

Wie konvertiert man manuell 8,24-Bit deinterleaved LPCM in 16-Bit LPCM?

Ich habe einen Datenblock (void*), der 2 ch, 44100 Hz, 'lpcm' 8.24-Bit little-endian signed integer, entzerrt ist. Ich muss diesen Block als 2 ch, 44100 Hz, 'lpcm' 16-Bit little-endian signed integer auf einer Datei aufzeichnen.

Wie konvertiere ich die Daten? Ich kann mir vorstellen, dass ich etwas Ähnliches machen muss:

uint dataByteSize = sizeof(UInt32) * samplesCount;
UInt32* source = ...;
UInt32* dest = (UInt32*)malloc(dataByteSize);
for (int i = 0; i < samplesCount; ++i) {
    UInt32 sourceSample = source[i];
    UInt32 destSample = sourceSample>>24;
    dest[i] = destSample;
}

Aber wie konvertiere ich von entzerrt zu interleaved?

11voto

Alexey Punkte 6830

Ok, ich habe einige Zeit damit verbracht, das Problem zu untersuchen und festgestellt, dass die Frage zu wenige Informationen enthält, um beantwortet zu werden =) Also hier ist die Erklärung:

Zuerst, zum Thema nicht-interleaved: Ich dachte zunächst, es würde so aussehen: l1 l2 l3 l4...ln r1 r2 r3 r4...rn Aber es stellte sich heraus, dass im meinen Daten der rechte Kanal fehlte. Es stellte sich heraus, dass es sich nicht um nicht-interleaved-Daten handelte, sondern um einfache Monodaten. Und ja, es sollte immer mehrere Puffer geben, falls die Daten tatsächlich nicht-interleaved sind. Wenn sie interleaved sind, sollte es so sein: l1 r1 l2 r2 l3 r3 l4 r4...

Zweitens, zur tatsächlichen Transformation: alles hängt vom Bereich der Stichproben ab. In meinem Fall (und in jedem Fall, in dem Core Audio involviert ist, wenn ich mich nicht irre) sollten fixe 8.24-Werte im Bereich von (-1, 1) liegen, während 16-Bit-vorzeichenbehaftete Werte im Bereich von (-32768, 32767) liegen sollten. Ein 8.24-Wert hat also immer seine ersten 8 Bits auf 0 gesetzt (falls er positiv ist) oder auf 1 (falls er negativ ist). Diese ersten 8 Bits sollten entfernt werden (das Vorzeichen natürlich beibehalten). Außerdem können beliebig viele nachfolgende Bits entfernt werden - es wird nur die Qualität des Klangs verringern, aber den Klang nicht ruinieren. Wenn man zum 16-Bit-vorzeichenbehafteten Format konvertiert, werden die Bits 8-22 (15 Bits also) tatsächlich die Daten enthalten, die wir für SInt16 verwenden müssen. Bit 7 kann als das Vorzeichenbit verwendet werden. Um also von 8.24 auf SInt16 zu konvertieren, müssen Sie einfach 9 Bits nach rechts verschieben (9, weil das Vorzeichen erhalten bleiben muss) und in SInt16 umwandeln

11111111 10110110 11101110 10000011 - > 11111111 11111111 (11011011 01110111)
00000000 01101111 00000000 11000001 - > 00000000 00000000 (00110111 10000000)

Das ist alles. Nichts weiter als das Durchlaufen des Arrays und das Verschieben der Bits nach rechts. Hoffentlich spart das jemandem ein paar Stunden.

3voto

Tim Wu Punkte 2027

Ich habe den folgenden Clip in Audiograph gelesen https://github.com/tkzic/audiograph

/* Konvertiere Sample-Vektor von Festkomma 8.24 nach SInt16 */
void fixedPointToSInt16( SInt32 * source, SInt16 * target, int length ) {    
    int i;

    for(i = 0;i < length; i++ ) {
        target[i] =  (SInt16) (source[i] >> 9);        
    }    
}

0voto

Brian Cannard Punkte 816

Die beste Beschreibung finden Sie unter http://lists.apple.com/archives/coreaudio-api/2011/Feb/msg00083.html

Also,

Die 8.24 Zahlen werden im Bereich von -128.000000000000 bis +127.999999940393 interpretiert

Aber!

Die Konvention in iOS/CoreAudio ist es, -1.000000000000 bis +0.999969482421875 als nicht geclippte Werte zu behandeln, die den Full Scale für die 16-Bit-Analog-Audio-Wandler nicht überschreiten.

Verstanden?

0voto

Orph Punkte 145

Ich habe die beliebte Methode mit dem Verschieben von 9 Bits getestet und aus irgendeinem Grund funktioniert sie bei mir nicht, da ich das Ergebnis weiter zum Codieren von ogg verwende. Das resultierende ogg war sehr laut. Was funktioniert hat, ist diese Funktion, basierend auf einer Methode, die ich in audiograph gefunden habe https://github.com/tkzic/audiograph

void ConvertInputToInt16(AudioStreamBasicDescription inFormat, void *buf, void *outputBuf, size_t capacity) {
    AudioConverterRef converter;
    OSStatus err;

    size_t bytesPerSample = sizeof(SInt16);
    AudioStreamBasicDescription outFormat = {0};
    outFormat.mFormatID = kAudioFormatLinearPCM;
    outFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    outFormat.mBitsPerChannel = 8 * bytesPerSample;
    outFormat.mFramesPerPacket = 1;
    outFormat.mChannelsPerFrame = 1;
    outFormat.mBytesPerPacket = bytesPerSample * outFormat.mFramesPerPacket;
    outFormat.mBytesPerFrame = bytesPerSample * outFormat.mChannelsPerFrame;
    outFormat.mSampleRate = inFormat.mSampleRate;

    NSLog(@"Beschreibung für das Eingabeformat: %@", descriptionForAudioFormat(inFormat));
    NSLog(@"Beschreibung für das Ausgabeformat: %@", descriptionForAudioFormat(outFormat));

    UInt32 inSize = capacity*sizeof(SInt32);
    UInt32 outSize = capacity*sizeof(SInt16);

    // Dies ist der berühmte Audiokonverter

    err = AudioConverterNew(&inFormat, &outFormat, &converter);
    if(noErr != err) {
        NSLog(@"Fehler beim AudioConverterNew: %d", (int)err);
    }

    err = AudioConverterConvertBuffer(converter, inSize, buf, &outSize, outputBuf);
    if(noErr != err) {
        NSLog(@"Fehler beim AudioConverterConvertBuffer: %d", err);
    }

}

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