AudioTrack - kurzes Array-zu-Byte-Array-Verzerrung mit Jlayer (Java-mp3-Decoder)

8

Ich benutze jLayer, um MP3-Daten mit diesem Aufruf zu dekodieren:

%Vor%

Dieser Aufruf, der die dekodierten Daten zurückgibt, gibt ein Array von short [] zurück.     output.getBuffer();

Wenn ich AudioTrack write () mit dieser Methode aufruft, spielt es gut, während ich die Datei durchlaufe:

%Vor%

Wenn ich jedoch das Array short [] in das Array byte [] umwandle, verwende ich eine der Methoden in dieser Antwort: Ссылка der Ton wird verzerrt und nervös:

%Vor%

wird zu:

%Vor%

Mache ich irgendetwas falsch und was kann ich tun, um es zu reparieren? Leider brauche ich die PCM-Daten in einem Byte-Array für eine andere 3rd-Party-Bibliothek, die ich verwende. Die Datei ist 22kHz, wenn das wichtig ist und so at wird instanziiert:

%Vor%

Vielen Dank im Voraus.

Bearbeiten: So stelle ich jetzt die AudioTrack-Variable instanziieren. Bei 44 kHz-Dateien beträgt der Wert 44100, bei 22-kHz-Dateien 22050.

%Vor%

Dies ist eine Dekodiermethode:

%Vor%

So klingt es (ein paar Sekunden warten): Ссылка (und das ist die eigentliche Datei: Ссылка )

Edit: Ich hätte das Kopfgeld gerne aufgeteilt, aber stattdessen habe ich Bill das Kopfgeld und Neil die akzeptierte Antwort gegeben. Beide waren eine enorme Hilfe. Für diejenigen, die sich wunderten, schrieb ich am Ende den Sonic-Code neu, der mir dabei half, den Prozess voranzutreiben.

    
StackOverflowed 27.02.2013, 22:49
quelle

2 Antworten

4

Wie @ Bill Pringemeir sagt, besteht das Problem darin, dass Ihre Konvertierungsmethode nicht wirklich konvertiert wird. Ein Short ist eine 16-Bit-Nummer; Ein Byte ist eine 8-Bit-Nummer. Die Methode, die Sie gewählt haben, konvertiert nicht den Inhalt der Kurzschlüsse (dh geht von 16 Bits zu 8 Bits für den Inhalt), es ändert die Art und Weise, in der dieselbe Sammlung von Bits gespeichert wird. Wie du sagst, brauchst du so etwas:

%Vor%

@Bill Pringemeirs Ansatz entspricht dem Teilen aller Kurzschlüsse durch 256, um sicherzustellen, dass sie in den Byte-Bereich passen:

%Vor%

Das wird funktionieren, wird Ihnen aber wahrscheinlich sehr ruhige, kantige Töne geben. Wenn Sie sich die Bearbeitungszeit leisten können, wird ein Zwei-Pass-Ansatz wahrscheinlich bessere Ergebnisse bringen:

%Vor%

Achten Sie erneut auf das signierte / nicht signierte Problem. Die oben genannten Werke signiert- & gt; signed und unsigned- & gt; unsigned; aber nicht zwischen den beiden. Es kann sein, dass Sie signierte Kurzschlüsse (-32768-32767) lesen, aber nicht signierte Bytes (0-255) ausgeben müssen, ...

Wenn Sie sich die Bearbeitungszeit leisten können, wäre ein präziserer (glatterer) Ansatz, über Floats zu gehen (dies gilt auch für das signierte / unsignierte Problem):

%Vor%     
Neil Townsend 03.03.2013, 17:05
quelle
3

Das Problem tritt bei der Umwandlung von short in byte auf. Der Linkkonvertierung Link behält alle Informationen einschließlich der hohen und niedrigen byte Anteile bei. Bei der Konvertierung von 16-Bit- zu 8-Bit PCM-Beispielen müssen Sie das untere Byte verwerfen. Meine Java-Fähigkeiten sind schwach, daher funktioniert das folgende möglicherweise nicht wörtlich. Siehe auch: Konvertierung von Kurz zu Byte.

%Vor%

Das ist die folgende Umwandlung,

%Vor%

A ist ein Bit, das beibehalten wird. B ist ein verworfenes Bit und S ist ein Bit, das Sie zum Runden verwenden möchten. Die Rundung wird nicht benötigt, aber es kann ein wenig besser klingen. Grundsätzlich ist 16 Bit PCM eine höhere Auflösung als 8 Bit PCM. Sie verlieren diese Bits, wenn die Konvertierung abgeschlossen ist. Die Routine short to byte versucht, alle Informationen zu speichern.

Natürlich müssen Sie der Soundbibliothek mitteilen, dass Sie 8-bit PCM verwenden. Meine Vermutung,

%Vor%

Wenn Sie 16bit PCM nur zum Abspielen von Audio verwenden können, müssen Sie die Umkehrung durchführen und das 8bit PCM von der Bibliothek in 16bit PCM für die Wiedergabe konvertieren. Beachten Sie auch, dass 8bit samples oft NICHT direkt PCM sind, aber u- Gesetz oder a-law kodiert. Wenn die 3 rd Party-Bibliothek diese Formate verwendet, ist die Konvertierung anders, aber Sie sollten in der Lage sein, sie aus den Wikipedia-Links zu programmieren.

HINWEIS: Ich habe den Rundungscode nicht als overflow eingefügt und sign handling wird die Antwort komplizierter machen. Sie müssen nach overflow suchen (Ie, 0x8f + 1 ergibt 0xff oder 255 + 1 ergibt -1). Ich vermute jedoch, dass die Bibliothek nicht gerade 8bit PCM ist.

Siehe auch: Alsa-PCM-Übersicht , Multimedia-Wiki-Eintrag auf PCM - Letztendlich verwendet Android ALSA für Sound.

Andere Faktoren, die für einen PCM-Rohpuffer stimmen müssen, sind Abtastrate, Anzahl der Kanäle (Stereo / Mono), PCM-Format einschließlich Bits, Kompandierung , Little / Big Endian und Sample Interleaving.

BEARBEITEN: Nach einigen Untersuchungen gibt der JLayer-Decoder normalerweise big endian 16bit-Werte zurück. Der Sonic-Filter benötigt byte , bedroht sie jedoch als 16bit little endian darunter. Schließlich erwartet die AudioTrack Klasse 16 bit little endian darunter. Ich glaube, dass der JLayer mp3 Decoder aus irgendeinem Grund 16bit little endian Werte zurückgibt. Die decode() -Methode in der Frage führt einen Byte-Tausch der 16-Bit-Werte durch. Außerdem klingt das angezeigte Audio so, als ob die Bytes vertauscht wären.

%Vor%

Für 44k mp3s rufen Sie die Routine mit swap = true; auf. Für die 22k mp3 swap = false . Dies erklärt alle berichteten Phänomene. Ich weiß nicht, warum der JLayer mp3 Decoder manchmal big endian und andere Male little endian ausgeben würde. Ich stelle mir vor es hängt von der Quell-mp3 ab und nicht von der Samplerate.

    
artless noise 03.03.2013 16:19
quelle

Tags und Links