Hilfestellung bei sox-Konfiguration über alsa gesucht

Antworten
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Hilfestellung bei sox-Konfiguration über alsa gesucht

Beitrag von Buschel »

Hallo zusammen,

bisher habe ich über den Thread DSP - Best Practice bei Formatumwandlung und Faltung? leider keine Lösung für mein Problem gefunden. Daher gehe ich jetzt den Weg über diesen dedizierten Thread.

Ich würde gerne mit Sampleratekonvertierung über sox (anstatt der in meinem DAC integrierten) experimentieren. Bisher scheitere ich an der Anbindung über alsa. In meinem jetzigen Setup läuft die Faltung über brutefir mit der fest eingestellten Samplingfrequenz von 44,1 kHz. Dabei gibt brutefir über ein alsa-device an USB-Audio aus, und nimmt Daten über zwei alsa-devices an. Das eine alsa-device ist mit USB-Audio verbunden, das andere ist ein sogenanntes "alsa loopback" device, an das mein Softwareplayer (kodi) angeschlossen ist.

Mein Ziel ist es, brutefir und den USB-DAC mit 96 kHz laufen zu lassen. Für USB-Audio ist dies einfach umsetzbar, da der gesamte USB-Audio Pfad einfach darauf konfiguriert wird. Aber wie wandle ich die von kodi kommenden Daten (typischerweise 44,1 kHz) auf 96 kHz um? Ich hoffe, dass ihr mir hierbei ein wenig Hilfestellung geben könnt. Kann ich die Sampleratenkonvertierung per sox-SRC in eines der vorhandenen alsa-devices einbinden? Oder muss ich ein neues alsa-device definieren und dem loopback device vorschalten?

Als Referenz hier noch die aktuelle alsa Konfiguration mit
- "usbaudio" = USB-Audio in/out
- "aloopp" = alsa loopback playback (kodi gibt hierhin die Daten aus)
- "aloopc" = alsa loopback capture (brutefir holt hier die Daten von kodi ab)
- ""brutefir_44k1_32b" = dmix device, um kodi zu korrekten Auswahlmöglichkeit zu bringen

Code: Alles auswählen

#
# USB audio (DAC)
#
pcm.usbaudio {
   type hw
   card 2
   device 0
   format S32_LE
   channels 2
}

#
# ALSA loopback (capture/playback)
#
pcm.aloopc {
   type hw
   card Loopback
        device 1
   format S32_LE
   channels 2
}

pcm.aloopp {
   type hw
   card Loopback
        device 0
}

# KODI needs "dmix" to list both brutefir devices
pcm.brutefir_44k1_32b {
   type dmix
   ipc_key 1024
   slave {
      pcm "aloopp"
      format S32_LE
      rate 44100
      period_size 512
      buffer_size 8192
   }
}

#
# Default (TV HDMI)
#
pcm.!default {
   type hw
   card 0
   device 3
}

ctl.!default {
   type hw
   card 0
   device 3
}
Grüße,
Andree
Bild
Daihedz
Aktiver Hörer
Beiträge: 793
Registriert: 25.06.2010, 15:09

Beitrag von Daihedz »

Hallo Andree

Die .asoundrc ist für mich nach wie vor ein Buch mit fünf relativen Siegeln, und dennoch, einiges habe ich damit schon zum Laufen gebracht. Schau vielleicht in den Faden "Software Experimente mit Linux" hinein, dort habe ich ein (schon überholtes) Beispiel eingestellt, wie mittels einer .asoundrc eine Pipe gestartet werden könnte, welche in etwa das leisten könnte, was Dir vorschwebt. Hier ein Beispiel eines Auszugs einer etwas aktuelleren, funktionalen .asoundrc:

Code: Alles auswählen

pcm.Audio_out_piped {
	type file
	file "| sox -b 16 -c 2 -D -e signed-integer -q -r 44100 -t raw - -b 64 -c 2 -e float -t raw - | \
	resample_soxr --band-width=91.09 --buffer-length=8192 --channels=2 --inrate=44100 --outrate=96000 --phase=25 --volume=0.75 --verbose | \
 	brutefir -nodefault /home/privat/_brutefir/Cabasse/brutefir_config_cabasse | \
	volrace --buffer-length=8192 --volume=1.3 --max-volume=2.0 --verbose | \
	volrace --buffer-length=8192 --fading-length=24000 --param-file=/home/privat/_frankl/volrace.save --verbose | \
	sox -b 64 -c 2 -D -e float -q -r 96000 -t raw - -b 32 -c 2 -e signed-integer -t raw - | \
	playhrt --device=Analog_out_96000 --hw-buffer=512 --loops-per-second=1500 --max-bad-reads=100000 --mmap --non-blocking-write --number-channels=2 --sample-format=S32_LE --sample-rate=96000 --sleep=1000000 --stdin" ;
	format "raw"
	slave {
		pcm null
	}
}

### COMMON ###
pcm.null {
	type null
}
Die Funktionalität dieses .asoundrc-Moduls steht und fällt natürlich mit der Voraussetzung, dass kodi am Ausgang stets und ausschliesslich 16/44100 ausgibt.

Da mir diese Lösung etwas allzu unflexibel erschien (es macht bei wechslenden sampling rates z.B. keinen Sinn, 96kHz nach 96kHz zu konviertieren), habe ich stattdessen ein bash-script geschrieben. Damit kann ich unterschiedliche Eingangsformate bestmöglichst verarbeiten. Ich habe darin zwar (noch) kein kodi implementiert. Aber es ist beim aktuellen Stand der Dinge immerhin schon fähig, entweder eine wav-Datei beliebigen Formats einzulesen, oder aber sich auch (mittels einer dedizierten, separaten SPDIF/AES - Input-Soundkarte) automatisch auf einen potenziell stets wechselnden SPDIF-Input zu reagieren, und 44.1kHz/16, 48kHz/16 oder auch 96kHz/24 einzulesen. Brutefir faltet immer bei/mit 96kHz/64Bit, ausgegeben wird immer mit 96kHz/32Bit: Die Input-Soundkarte hat taktet somit unterschiedlich, die Output-Soundkarte immer gleich bei 96kHz.

Eine automatische Adaptation auf wechselnde In-Samplingraten setzt voraus, dass das Format des eingehenden Signals irgedwie aus Variablen für das script einlesbar ist. Das ist bei wav-Dateien aus deren Infos im header gegeben, und bei der RME9632, welche bei mir als SPDIF-Eingangsteil dient, aus dem kernel interface (/proc/asound/card[0...9]/... gegeben. Bei kodi weiss ich hingegen (noch) nicht, wie und wo das Format auszulesen wäre, da ich kodi bislang nicht ausprobiert habe.

Last not least: Für die sample-rate Konversion würde ich ausschliesslich das von frank(l) geschriebe Programm resample_soxr verwenden, und nicht etwa sox. Denn resample_soxr rechnet tiefer als sox.

Scriptophile Grüsse
Simon
Bild
frankl
Aktiver Hörer
Beiträge: 486
Registriert: 20.01.2013, 01:43
Wohnort: Aachen

Beitrag von frankl »

Hallo Andree,

ich habe nie kodi benutzt und nur gelegentlich auf meinem Notebook mit den ALSA Konfigurationen gespielt.

Solltest Du nicht mit ALSA und einem Device

Code: Alles auswählen

... {
   type rate
   converter samplerate_best
   ...
}
schon eine recht gute Samplerate-Konversion bekommen?

Wenn Du ein externes Programm verwenden willst (sox, resampler_soxr?) musst/kannst Du wohl ein Plugin vom 'type file' wie in Simons Beispiel verwenden (wenn das Programm mit "|" beginnt, dann wird eine Pipe geöffnet). In dem Programmtext kannst Du dann etwa '%b' und '%r' verwenden für die aktuelle Bittiefe und Samplerate (suche nach 'Plugin: file' in der ALSA Dokumentation).

Aber das war Dir vermutlich eh schon klar.

Viele Grüße,
Frank
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo Frank, Simon,

vielen Dank schon mal für eure Hinweise. Ich schaue mal, ob ich kodi zu einer pipe-Ausgabe bewegen kann, und werde ansonsten das „rate“-device ausprobieren. Ich würde allerdings gerne die Möglichkeiten von sox nutzen.

Grüße,
Andree
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo zusammen,

kurzes Zwischenfazit: Der einfache Weg über die SRC innerhalb alsa scheint zu funktionieren. Ich sehe auch unterschiedliche CPU loads, wenn ich zwischen "samplerate" und "samplerate_best" wechsele und per aplay abspiele. Bei Verwendung von kodi sehe ich allerdings keinen Unterschied und bin mir auch nicht 100%ig sicher, ob kodi wirklich weiterhin in 44,1 kHz ausgibt und alsa die SRC rechnet, oder ob kodi die SRC rechnet und direkt 96 kHz ausgibt. Sicherheit bekomme ich nur über aufwändige Mitschnitte von wav-Dateien mit Sweepsignalen, zu denen ich mich gerade nicht motivieren kann. Ich genieße deswegen erstmal weiter mit dem 44,1 kHz Setup und entspanne mich lieber. :cheers:

Trotzdem nochmal vielen Dank für die Tipps. Das Thema verfolge ich weiter.

Grüße,
Andree
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo zusammen,

es hat jetzt doch etwas länger gedauert. :mrgreen:

Mit eurer Hilfe habe ich es jetzt geschafft, in der asound.conf einige pipes in alsa für die Wiedergabe über kodi zu definieren. Der Riesenvorteil daran ist, dass ich jetzt keine alsa-loop mehr benötige, um das PCM-Signal von kodi in brutefir zu bekommen. Damit entfallen die Probleme mit auseinanderlaufenden Clocks, die ich per Skript lösen musste (Lösung für Aussetzer).

Mit den unterschiedlichen pipes kann ich jetzt das FLOAT32-Signal direkt von kodi abgreifen und weiter prozessieren. Wichtig ist, dass die Puffergröße richtig gewählt wird. Bei anderen Puffergrößen als den gewählten 4096 kommt es in Kombination mit kodi zu häufigen buffer overruns. Zum Probieren habe ich vier pipes definiert:

Code: Alles auswählen

pcm.pipe_src44k1_dither24 {
	type file
	file "| sox -v 0.8 -r 44100 -b 32 -c 2 -e float -t raw - --buffer 4096 -t alsa usbaudio dither -p 24"
	format "raw"
	slave {
		pcm null
	}	
}
Die erste pipe wandelt nur zu INT32 um, wendet Dither für 24 Bit Tiefe an und gibt die Daten an den DAC. Die 24 Bit entsprechen der Auflösung, die mein DAC verarbeitet. Zu Beginn wird der Pegel auf 0.8 (um etwa 2 dB) abgesenkt, um Clipping durch Sample Rate Conversion, Dithering und FIR-Filterung zu verhindern.

Code: Alles auswählen

pcm.pipe_src96k_dither24 {
	type file
	file "| sox -v 0.8 -r 44100 -b 32 -c 2 -e float -t raw - --buffer 4096 -t alsa usbaudio rate -v 96000 dither -p 24"
	format "raw"
	slave {
		pcm null
	}	
}
Die zweite pipe führt zusätzlich vor dem Dithering eine Sample Rate Conversion (sox very high quality) nach 96 kHz aus. Diese Samplingfrequenz ist von den technischen Daten her der sweet spot meines DACs.

Code: Alles auswählen

pcm.pipe_src96k_brutefir {
	type file
	file "| sox -v 0.8 -r 44100 -b 32 -c 2 -e float -t raw - --buffer 4096 -t raw - rate -v 96000 | brutefir /home/buschel/Convolver/DRC_96k_eq_stdin.conf"
	format "raw"
	slave {
		pcm null
	}	
}
Die dritte pipe führt eine SRC nach 96 kHz aus und gibt die Daten in FLOAT32 and brutefir weiter. Dort werden Raumkorrektur und EQ durchgeführt und die Daten direkt als INT32 an den DAC geschrieben.

Code: Alles auswählen

pcm.pipe_src96k_brutefir_dither24 {
	type file
	file "| sox -v 0.8 -r 44100 -b 32 -c 2 -e float -t raw - --buffer 4096 -t raw - rate -v 96000 | brutefir /home/buschel/Convolver/DRC_96k_eq_stdin_stdout.conf | sox -t raw -r 96000 -b 32 -c 2 -e float - -t alsa usbaudio dither -p 24"
	format "raw"
	slave {
		pcm null
	}	
}
Die vierte pipe fügt nach der Verarbeitung in brutefir noch ein abschließendes Dithering mit 24 Bit Tiefe aus. Die Daten gehen von dort in den DAC.


Viele Grüße,
Andree

PS: Noch eine Frage an die Spezialisten. Wie genau ist die Wirkung von "rate -b x" bei sox definiert? Ist x die Bandbreite, bei der -3 dB Dämpfung erreicht wird? Mein Ziel ist, dass bei 20 kHz noch keine nennenswerte Dämpfung (<0,1 dB), aber bei 22,05 kHz bereits volle Sperrdämpfung vorhanden ist -- bei möglichst kurzer Impulsantwort des sich ergebenden Filters.
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo zusammen,

selbst ist der Mann. :mrgreen:

Bild
Passband sox -r 44100 rate -v 96000 (-b 91, -b 93, -b 94, -b 95)

Default entspricht "-b 95". Bis "-b 93" erfüllt der Graph meine Anforderung von kleiner -0,1 dB Dämpfung bei 20 kHz.

Grüße,
Andree
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo zusammen,

mich hatte noch interessiert wie lang die Filter in den unterschiedlichen Varianten werden. Mit Acourate lässt sich sehr schön erkennen wie viele taps die Filter haben, wenn man den RMSLog View benutzt.

Bild
Impulse response sox -r 44100 rate -v 96000 (-b 91, -b 92, -b 93, -b 94, -b 95)

Filterlängen bei 96 kHz Zielfrequenz:
  • -b 95 -> etwa 600 taps
  • -b 94 -> etwa 500 taps
  • -b 93 -> etwa 430 taps
  • -b 92 -> etwa 380 taps
  • -b 91 -> etwa 330 taps
Viele Grüße,
Andree
Bild
Antworten