Eine Audio -Probenrate -Konvertierungsbibliothek für Rost.
Diese Bibliothek bietet Resamplher, um Audio in Stücken zu verarbeiten.
Das Verhältnis zwischen Eingangs- und Ausgangsprobenraten ist vollständig frei. Implementierungen sind verfügbar, die eine Eingabe mit fester Länge akzeptieren, während eine Ausgabe einer variablen Länge zurückgegeben wird, und umgekehrt.
Rubato kann in Echtzeitanwendungen ohne Allokation während der Verarbeitung verwendet werden, indem ein [Resampler] und die Methoden "Input_buffer_allocation und Ausgabe_Buffer_allocation vor Beginn der Verarbeitung verwendet werden. Die Funktionsfunktion für die Protokollfunktion sollte für die Echtzeitanwendung deaktiviert werden (sie ist standardmäßig deaktiviert).
Eingangs- und Ausgangsdaten werden in einem nicht interleierten Format gespeichert.
Eingangs- und Ausgangsdaten werden als Referenzschnitte gespeichert, &[AsRef<[f32]>]
oder &[AsRef<[f64]>]
. Die inneren Referenzen ( AsRef<[f32]>
oder AsRef<[f64]>
) halten die Stichprobenwerte für jeweils einen Kanal.
Da normale Vektoren das AsRef
-Merkmal implementieren, kann Vec<Vec<f32>>
und Vec<Vec<f64>>
sowohl für Eingabe als auch für die Ausgabe verwendet werden.
Die asynchronen Resamplher sind mit und ohne Anti-Aliasing-Filter erhältlich.
Das Resampling mit Anti-Aliasing basiert auf bandbegrenzten Interpolation unter Verwendung von SINC-Interpolationsfiltern. Die SINC -Interpolation belastet um einen einstellbaren Faktor, und dann werden die neuen Probenpunkte durch Interpolieren zwischen diesen Punkten berechnet. Das Resampling -Verhältnis kann jederzeit aktualisiert werden.
Resampling ohne Anti-Aliasing lässt die CPU-stehende Sinc-Interpolation weg. Dies läuft viel schneller, führt aber ein Ergebnis von geringerer Qualität.
Synchrones Resampling wird über FFT implementiert. Die Daten sind FFT: ED, das modifizierte Spektrum und dann umgekehrte FFT: ED, um die Resampfdaten zu erhalten. Diese Art von Resampler ist erheblich schneller, unterstützt jedoch nicht die Änderung des Resampling -Verhältnisses.
Die von dieser Bibliothek bereitgestellten Resamplher sollen Audio in Stücken verarbeiten. Die optimale Chunk -Größe wird durch die Anwendung bestimmt, wird jedoch wahrscheinlich zwischen einigen hundert bis ein paar tausend Frames enden. Dies gibt einen guten Kompromiss zwischen Effizienz und Speicherverbrauch.
Rubato eignet sich für Echtzeitanwendungen bei der Verwendung der Methode Resampler::process_into_buffer()
. Dies speichert die Ausgabe in einem vorab assoziierten Ausgangspuffer und führt keine Zuordnungen oder anderen Operationen durch, die den Thread blockieren können.
Ein vorgeschlagener einfacher Prozess zum erneuten Abtastung eines Audioclips mit bekannter Länge zu einer neuen Stichprobenrate ist wie folgt. Hier wird davon ausgegangen, dass die Quelldaten in einem VEC oder einer anderen Struktur gespeichert sind, die das Lesen der beliebigen Anzahl von Frames gleichzeitig unterstützt. Der Einfachheit halber wird die Ausgabe während des Resamplings in einem temporären Puffer gespeichert und anschließend an das Ziel kopiert.
Vorbereitungen:
Resampler::output_delay()
auf, um zu wissen, wie viele Rahmen der Verzögerung, die der Resampler gibt. Speichern Sie die Nummer als delay
.new_length = original_length * new_rate / original_rate
.Jetzt ist es Zeit, den Großteil des Clips durch wiederholte Prozessanrufe zu verarbeiten. Schleife:
Resampler::input_frames_next()
auf, um zu erfahren, wie viele Rahmen der Resampler benötigt.Resampler::process()
an oder Resampler::process_into_buffer()
.Der nächste Schritt besteht darin, die letzten verbleibenden Frames zu verarbeiten.
Resampler::process_partial()
auf oder Resampler::process_partial_into_buffer()
. Zu diesem Zeitpunkt wurden alle Frames an den Resampler gesendet, aber aufgrund der Verzögerung durch den Resampler kann es immer noch einige Frames in seinen internen Puffern haben. Wenn alle gewünschten Frames erzeugt wurden, sollte die Länge des temporären Ausgangspuffers mindestens new_length + delay
sein. Wenn dies nicht der Fall ist, rufen Sie Resampler::process_partial()
auf, oder Resampler::process_partial_into_buffer()
None
als Eingabe und fügen Sie die Ausgabe an den temporären Ausgabepuffer hinzu. Bei Bedarf wiederholen Sie, bis die Länge ausreicht.
Kopieren Sie schließlich die Daten aus dem temporären Ausgangspuffer zum gewünschten Ziel. Überspringen Sie die ersten delay
und kopieren Sie new_length
Frames.
Wenn mehr als ein Clip von und zu den gleichen Stichprobenraten wiederholt werden kann, sollte derselbe Resampler wiederverwendet werden. Das Erstellen eines neuen Resastrlers ist eine teure Aufgabe und sollte nach Möglichkeit vermieden werden. Starten Sie den Verfahren von Anfang an, aber anstatt einen neuen Resampler zu erstellen, rufen Sie Resampler::reset()
auf dem vorhandenen auf, um ihn für einen neuen Job vorzubereiten.
Bei der Wiederholung eines Streams wird der Prozess normalerweise in Echtzeit durchgeführt, und entweder ist der Ausgangseingang eine API, die Frames zu einer bestimmten Geschwindigkeit bereitstellt oder konsumiert.
Audio -APIs wie Coreaudio auf MacOS oder die CPAL -Kiste der Cross -Plattform verwenden häufig Rückruffunktionen für den Datenaustausch.
Ein komplettes
Bei der Erfassung von Audioen gibt die Anwendung eine Funktion an die Audio -API. Die API ruft diese Funktion dann regelmäßig auf, wobei ein Zeiger auf einen Datenpuffer mit neuen Audio -Frames enthält. Die Datenpuffergröße ist bei jedem Aufruf normalerweise gleich, aber das variiert zwischen APIs. Es ist wichtig, dass die Funktion nicht blockiert wird, da dies eine interne Schleife der API blockiert und einen Verlust einiger Audiodaten verursacht. Es wird empfohlen, das Rückruffunktionslicht zu halten. Idealerweise sollte es die bereitgestellten Audiodaten aus dem von der API bereitgestellten Puffer lesen und optional eine leichte Verarbeitung durchführen, z. B. die Umwandlung des Beispielformats. Hier sollte keine starke Verarbeitung wie Resampling durchgeführt werden. Anschließend sollten die Audiodaten in einem gemeinsam genutzten Puffer gespeichert werden. Der Puffer kann ein Arc<Mutex<VecDeque<T>>>
oder etwas Fortgeschritteneres wie Ringbuf.
Eine separate Schleife, die entweder im Haupt oder in einem separaten Thread ausgeführt wird, sollte dann aus diesem Puffer lesen, wiederproben und in Datei speichern. Wenn die Audio -API eine feste Puffergröße liefert, ist diese Anzahl von Frames eine gute Wahl für die Ressampler -Chunk -Größe. Wenn die Größe variiert, kann der gemeinsame Puffer verwendet werden, um die Stücke der Audio -API und des Resamplers anzupassen. Ein guter Ausgangspunkt für die Ressampler -Chunk -Größe ist die Verwendung eines "einfachen" Werts in der Nähe der durchschnittlichen Stücke der Audio -API. Stellen Sie sicher, dass der gemeinsam genutzte Puffer groß genug ist, um nicht voll zu werden, falls die Schleife blockiert wird. Warten Sie zum Beispiel auf den Zugriff auf Festplatten.
Die Schleife sollte einem Prozess folgen, der einem Clip ähnelt, aber der Eingang ist jetzt der gemeinsame Puffer. Die Schleife muss warten, bis die erforderliche Anzahl von Frames im Puffer verfügbar ist, bevor sie an den Resampler gelesen und weitergegeben werden.
Es wäre auch angemessen, den temporären Ausgangspuffer wegzulassen und die Ausgabe direkt an das Ziel zu schreiben. Die Houndkiste ist eine beliebte Wahl zum Lesen und Schreiben unkomprimierter Audioformate.
Der asynchrone Resampler unterstützt SIMD unter x86_64 und auf AARCH64. Die SIMD -Funktionen der CPU werden zur Laufzeit bestimmt. Wenn kein unterstützter SIMD -Befehlssatz verfügbar ist, fällt er auf eine skalare Implementierung zurück.
Auf x86_64 wird versucht, AVX zu verwenden. Wenn AVX nicht verfügbar ist, wird es stattdessen SSE3 versuchen.
Auf AARCH64 (64-Bit-Arm) verwendet es Neon, falls verfügbar.
Die synchronen Resamplher profitieren von der SIMD -Unterstützung der Rustfft -Bibliothek.
fft_resampler
: Aktivieren Sie die FFT -basierten synchronen ResampllerDiese Funktion ist standardmäßig aktiviert. Deaktivieren Sie es, wenn die FFT -Resamplher nicht benötigt werden, um die Kompilierungszeit zu sparen und die resultierende binäre Größe zu verringern.
log
: Protokollierung aktivieren Diese Funktion ermöglicht die Protokollierung über die log
. Dies ist für Debugging -Zwecke gedacht. Beachten Sie, dass die Ausgabetlogs eine [STD :: STRING :: STRING] zuweisen und die meisten Protokollierungsimplementierungen verschiedene andere Systemaufrufe umfassen. Diese Anrufe können einige (unvorhersehbare) Zeit in Anspruch nehmen, in denen die Anwendung blockiert ist. Dies bedeutet, dass die Protokollierung vermieden werden sollte, wenn diese Bibliothek in einer Echtzeitanwendung verwendet wird.
Die log
kann beim Ausführen von Tests aktiviert werden, was beim Debuggen sehr nützlich sein kann. Die Protokollierungsstufe kann über die RUST_LOG
-Umgebungsvariable festgelegt werden.
Beispiel:
RUST_LOG=trace cargo test --features log
Proben Sie einen einzelnen Stück einer Dummy -Audio -Datei von 44100 bis 48000 Hz erneut. Siehe auch das Beispiel "process_f64", mit dem eine Datei von der Festplatte verarbeitet werden kann.
use rubato :: { Resampler , SincFixedIn , SincInterpolationType , SincInterpolationParameters , WindowFunction } ;
let params = SincInterpolationParameters {
sinc_len : 256 ,
f_cutoff : 0.95 ,
interpolation : SincInterpolationType :: Linear ,
oversampling_factor : 256 ,
window : WindowFunction :: BlackmanHarris2 ,
} ;
let mut resampler = SincFixedIn :: < f64 > :: new (
48000 as f64 / 44100 as f64 ,
2.0 ,
params ,
1024 ,
2 ,
) . unwrap ( ) ;
let waves_in = vec ! [ vec! [ 0.0f64 ; 1024 ] ; 2 ] ;
let waves_out = resampler . process ( & waves_in , None ) . unwrap ( ) ;
Das examples
enthält einige Beispielanwendungen zum Testen der Resamplher. Es gibt auch Python -Skripte, um einfache Testsignale zu generieren und die Resampfeergebnisse zu analysieren.
Die Beispiele lesen und schreiben Roh-Audio-Daten im 64-Bit-Float-Format. Sie können verwendet werden, um die Dateien zu verarbeiten, wenn die Dateien zuerst in das richtige Format konvertiert werden. Verwenden Sie sox
, um ein .wav in Rohproben zu konvertieren:
sox some_file.wav -e floating-point -b 64 some_file_f64.raw
Nach der Verarbeitung kann das Ergebnis wieder in ein neues .wav konvertiert werden. Diese Beispiele wandeln sich auf 16 Bit bei 44,1 kHz um:
sox -e floating-point -b 64 -r 44100 -c 2 resampler_output.raw -e signed-integer -b 16 some_file_resampled.wav
Viele Audio -Redakteure, beispielsweise Audacity, können auch die Rohproben direkt importieren und exportieren.
Die rubato
-Kiste benötigt RustC Version 1.61 oder neuer.
fft_resampler
.log
.input/output_buffer_allocate()
optional mit Nullen Puffer vorzuführen lassen.Lizenz: MIT