Software Experimente mit Linux

Musikwiedergabe über PC und Mac

Beitragvon Daihedz » 15.12.2017, 08:16

dietert hat geschrieben: ...Bei mir ist gestern so ein AVB-Testkit von MiniDSP eingetroffen, aber wenn ich das hier lese, und die Sachen bei "frankl's stereo pages", vielleicht geht das ja auch mit Ethernet ohne die AVB Echtzeit-Erweiterung.

Aktuell:
Server <-> Slave -> Soundkarte -> Von dort Audio Stereo Standard über NF-Koax weiterverteilt.

AVB wird wohl die Zukunft sein, mit garantierten, niedrigen Laufzeiten im Falle von
Server <-> Slave1 -> Soundkarte1
Server <-> Slave2 -> Soundkarte2
Server <-> Slave_n <-> Soundkarte_n

Mir geht es hier vor allem darum, die prinzipielle Lösung mit der .asoundrc zu zeigen. D.h., dass das gesamte Audio, welches in einem PC (=Server) produziert werden kann, an zentraler Stelle in einen Netzwerkstream geführt werden kann. Ob es dann auch Stereo mittels Standard-Ethernet weitergehen kann, muss sich dann noch weisen.

Es würde mich sehr interessieren zu einem späteren Zeitpunkt zu lesen, was Du mit Deinem DSP-AVB-Kit für Erfahrungen gemacht hast.

Beste Grüsse.
Simon
Bild
Daihedz
Aktiver Hörer
 
Beiträge: 541
Registriert: 25.06.2010, 15:09

Beitragvon Daihedz » 31.12.2017, 16:15

Ein Hallo in die Runde der experimentierwilligen und -freudigen Audio-Linuxer

Eine ALSA-Konfigurationsdatei /home/xyz-user/.asoundrc machts möglich: Laustärkeeinstellung, RACE, LoCo und DRC einfach und standardmässig für sämtliche Audio-Inhalte eines Linux-Rechners ... dies, ohne Pulseaudio und/oder Jackd, sondern ausschliesslich innerhalb des (untersten) ALSA-Layers mittels einer Pipe und, in den folgenden Beispielen mittels brutefir sowie volrace hübsch aufbereitet.

Zwischenzeitlich habe ich denn etwas weiter mit dem "file"-plugin der ALSA-Konfigurationsdateien http://www.alsa-project.org/alsa-doc/al ... ugins.html experimentiert und zwei Varianten ausprobiert, welche sämtliche Audioinhalte eines Linux-Rechners, welchen Formats (an dieser Stelle nochmals ein Danke an Frank(l) für die entsprechenden Tips) und welcher Herkunft auch immer ganz nach meinem Gusto defaultmässig weiterverarbeiten.

In einer ersten Variante für meine Zweit-Stereoanlage (2-Kanal mit passiven Cabasse Sampan Lautsprechern Bild "cabasseqws4s.jpg" anzeigen.) erfolgt die Ausgabe mit 96kHz über eine nach wie vor sehr brauchbare RME HDSP Multiface I (im Bild unterhalb der Logitech Touch) und deren SPDIF-Schnittstelle an ein Wolfson WM8741-Evalboard als DA-Wandler (im Bild das 19"-Gehäuse über dem Verstärker).

pcm.!default {
   type file
   file "| chrt -f 92 taskset -c 1 sox --buffer 1024 -b %b -c 2 -D -e signed-integer -r %r -t raw - -b 64 -c 2 -e floating-point -t raw - \
      | chrt -f 93 taskset -c 1 sox --buffer 4096 -b 64 -c 2 -D -e floating-point -r 44100 -t raw - -t raw - vol -2dB \
      | chrt -f 94 taskset -c 1 sox --buffer 4096 -b 64 -c 2 -D -e floating-point -r 44100 -t raw - -t raw - rate -v -I 192000 \
      | chrt -f 95 taskset -c 1 brutefir -nodefault /home/privat/_brutefir/Cabasse/brutefir_config_cabasse \
      | chrt -f 96 taskset -c 1 volrace --buffer-length=8192 --fading-length=24000 --param-file=/home/privat/_frankl/volrace.save --verbose \
      | chrt -f 97 taskset -c 1 sox --buffer 4096 -b 64 -c 2 -D -e floating-point -r 192000 -t raw - -t raw - rate -v -I 96000 \
      | chrt -f 98 taskset -c 1 sox --buffer 4096 -b 64 -c 2 -D -e floating-point -r 96000 -t raw - -b 32 -c 2 -e signed-integer -t raw - \
      | chrt -f 99 taskset -c 1 playhrt --buffer-size=4096 --device=hdsp_analog --extra-bytes-per-second=-10 --extra-frames-out=24 --hw-buffer=8192 --loops-per-second=1000 --max-bad-reads=100000  --non-blocking-write --number-channels=2 --sample-format=S32_LE --sample-rate=96000 --sleep=1000000 --stdin --verbose --verbose"
   format "raw"
   slave {
      pcm null
   }
}

pcm.hdsp {
#   HDSP: No --mmap option in case of multiface!
#   HDSP: Set soundcard to correct sample frequency, otherwise no hardware access possible
    type hw
    card 1
}

ctl.hdsp {
    type hw
    card 1
}

pcm.hdsp_analog {
   type plug
    slave {
      pcm hdsp
   }
}

pcm.null {
   type null
}

Audio wird zunächst über 3x Sox nach 192kHz/64Bit/Float hochtransformiert und als Clipping-Schutz um 2dB heruntergerechnet. Danach passiert es Brutefir, wo mittels einer geeigneten Config LoCo und die Hörplatz-Korrektur gerechnet wird. Danach kommt Volrace, wo die gleitende Lautstärkeeinstellung und RACE erfolgen kann. Danach wird es mit 2x Sox Soundkarten- und DA-Wandlertauglich nach 96kHz/32Bit/SignedInteger (S32_LE) zurückgerechnet. Und von der Multiface in den DA-Wandler eingespiesen.

Eine zeite, etwas einfachere "All-In-One"-Lösung für den dergestalt audiophil aufgehübschten Laptop im Solo-Betrieb ohne die RME Multiface sieht folgendermassen aus (merci nochmals an Frank(l) für die Tips mit seiner eigenen Laptop-Version):

pcm.!default {
   type file
   file "| chrt -f 92 taskset -c 1 sox --buffer 1024 -b %b -c 2 -D -e signed-integer -r %r -t raw - -b 64 -c 2 -e floating-point -t raw - \
      | chrt -f 93 taskset -c 1 sox --buffer 4096 -b 64 -c 2 -D -e floating-point -r 44100 -t raw - -t raw - vol -2dB \
      | chrt -f 94 taskset -c 1 sox --buffer 4096 -b 64 -c 2 -D -e floating-point -r 44100 -t raw - -t raw - rate -v -I 192000 \
      | chrt -f 95 taskset -c 1 brutefir -nodefault /home/privat/_brutefir/Cabasse/brutefir_config_W500 \
      | chrt -f 96 taskset -c 1 volrace --buffer-length=8192 --fading-length=24000 --param-file=/home/privat/_frankl/volrace.save --verbose \
      | chrt -f 97 taskset -c 1 sox --buffer 4096 -b 64 -c 2 -D -e floating-point -r 192000 -t raw - -t raw - rate -v -I 96000 \
      | chrt -f 98 taskset -c 1 sox --buffer 4096 -b 64 -c 2 -D -e floating-point -r 96000 -t raw - -b 32 -c 2 -e signed-integer -t raw - \
      | chrt -f 99 taskset -c 1 playhrt --buffer-size=4096 --device=hw:0,0 --extra-bytes-per-second=-10 --extra-frames-out=24 --hw-buffer=8192 --loops-per-second=1000 --max-bad-reads=100000  --non-blocking-write --number-channels=2 --sample-format=S32_LE --sample-rate=96000 --sleep=1000000 --stdin --verbose --verbose"
   format "raw"
   slave {
      pcm null
   }
}

pcm.null {
   type null
}

In beiden Beispielen ist die Pipe mit
<Audioquelle> -> sox | sox | sox | brutefir | volrace | sox | sox | playhrt
etwas langfädig, aber für meine Experimentierzwecke absichtlich so gewählt.

Einfacher wäre
<Audioquelle> -> sox | brutefir | volrace | sox | playhrt
in welcher pro eine Instanz sox sämtliche Transformationen in einem Rutsch gerechnet würden

Ich möchte hiermit keine Lösungen anpreisen, sondern vor allem auf die fantastischen Möglichkeiten hinweisen, innerhalb des ALSA-Layers mittels einer geeigneten Konfigurationsdatei praktisch beliebige Dinge mit Audiomaterial anstellen zu können, dies ganz nach Bedarf und/oder defaultmässig automatisiert.

Altjahresgrüsse
Simon
Bild
Daihedz
Aktiver Hörer
 
Beiträge: 541
Registriert: 25.06.2010, 15:09

Beitragvon Martin » 11.02.2018, 12:37

Hallo Frank,
Bisher verwendete ich mpd auf dem Raspi 3. Über die Pipe-Ausgabe von mpd ging es an brutefir, sox und bufhrt. Dann übers Ethernet zum Aria G25, auf dem playhrt läuft. So weit so gut. Nun habe ich mal aus Neugier mpd ersetzt durch ein etwas modifiziertes play_remote Script mit deinem neuen resample_soxr befehl. Obwohl mir auf dem rechten Ohr ein Tinnitus zu schaffen macht, ist vor allem bei klassischer Musik ein so deutlicher Unterschied zu hören, dass ich jetzt nicht mehr mit mpd hören mag. Mpd nutze ich jetzt nur noch gelegentlich für Internet-Streams (Youtube, Qobuz, Radio), aber nicht zum ernsthaften Musik hören.

Nun stellt sich die Frage der Bedienbarkeit. Ich verwende einen Laptop für die Bedienung. Der Laptop ist über WLAN mit dem Raspi 3 verbunden. Es ist mir gelungen, das play_remote Script in den Dateimanager Nemo (Linux Mint) zu integrieren. Meine Musiksammlung liegt auf einer Netzwerkplatte (SMB) und ist nach Genre, Künstler bzw. Komponist sortiert. Die CDs sind trackweise als Flac-Dateien abgespeichert. Wenn ich mit der Maus einen Rechtsklick auf einen Track mache, kann ich das play_remote Script starten. Das klappt auch mit mehreren markierten Tracks, die dann nacheinander abgespielt werden, aber leider nicht gapless. Die Lautstärke kann über die Tastatur gesteuert werden. Wenn das ganze gapless funktionieren würde, könnte ich damit leben.

Du hast mal erwähnt, dass du eine CD in einer einzigen Flac-Datei abspeicherst und mit einem Cue-Sheet arbeitest. Kannst du dazu etwas sagen, wie funktioniert das bei dir?

Viele Grüße
Martin

PS. Ich bin wirklich begeistert von "Frante" (Franks Audio Network Through Ethernet)
Bild
Martin
Aktiver Hörer
 
Beiträge: 75
Registriert: 15.03.2012, 15:23

Beitragvon frankl » 12.02.2018, 00:34

Hallo Martin,

danke für Deinen Bericht.

Martin hat geschrieben: Nun habe ich mal aus Neugier mpd ersetzt durch ein etwas modifiziertes play_remote Script mit deinem neuen resample_soxr befehl. Obwohl mir auf dem rechten Ohr ein Tinnitus zu schaffen macht, ist vor allem bei klassischer Musik ein so deutlicher Unterschied zu hören, dass ich jetzt nicht mehr mit mpd hören mag. Mpd nutze ich jetzt nur noch gelegentlich für Internet-Streams (Youtube, Qobuz, Radio), aber nicht zum ernsthaften Musik hören.

Das kann ich verstehen. Leider besteht mpd darauf, die eigentlichen Musikdaten selbst zu verarbeiten und die pipe Ausgabe ist nur eine Krücke, die vom Maintainer als nicht wichtig betrachtet wird. Das ist klanglich nicht optimal.

Martin hat geschrieben:Nun stellt sich die Frage der Bedienbarkeit.
[...]

Du hast mal erwähnt, dass du eine CD in einer einzigen Flac-Datei abspeicherst und mit einem Cue-Sheet arbeitest. Kannst du dazu etwas sagen, wie funktioniert das bei dir?

Ich wurde die letzte Zeit mehrfach zu meinem Setup und meinem Abspielskript gefragt. Es steht auf meiner TODO Liste, dass mal genauer zu dokumentieren und (aufgeräumte) Versionen meiner Skripte hochzuladen. Ich muss aber um ein wenig Geduld bitten, da ich gerade dabei bin, meine Anlage für 6 Wochen abzuschalten (bei interessanter Arbeit in fernen Landen halten sich die Entzugserscheinungen hoffentlich in Grenzen).

Ich denke aber, dass man mit den existierenden Programmen auch ein Skript hinbekommen sollte, das zumindest die Tracks eines Albums gapless abspielen kann. Ich werde mal überlegen.


Auf die Dauer schwebt mir vor, mal ein Webinterface zu programmieren mit ein paar grundlegenden Funktionen zur Musikauswahl, Lautstärke- und Filter-Regelung. Das sollte sich leicht auf individuelle Wünsche konfigurieren lassen, und darüber werden die Skripte gestartet, die ich jetzt auf der Kommandozeile starte. Damit könnte man dann jedes Gerät mit Webbrowser zur Bedienung verwenden.

Viele Grüße,
Frank
Bild
frankl
Aktiver Hörer
 
Beiträge: 390
Registriert: 20.01.2013, 02:43
Wohnort: Aachen

Beitragvon tovow » 12.02.2018, 01:34

Hallo Frank,

ich hatte vor längerer Zeit auch mal deine Anleitung für Ncat mit 2 RPI probiert.
Das hatte in der Testversion auch wunderbar Funktioniert, nur waren mir fast die Ohren weg geflogen. :oops:

Du weist schon warum, denke ich.

Frankl schrieb:
Auf die Dauer schwebt mir vor, mal ein Webinterface zu programmieren mit ein paar grundlegenden Funktionen zur Musikauswahl, Lautstärke- und Filter-Regelung.

das wäre Super für die Nicht-Linux Bewanderten. :cheers:

Frohes Schaffen in der Ferne.
Beste Grüße
Theo

PS. Hast du dich schon mal mit trx: Realtime audio over IP beschäftigt oder gearbeitet?
Oder was hältst du davon? Könnte man damit eine Art Dante AoIP System generieren?
Bild
tovow
Aktiver Hörer
 
Beiträge: 212
Registriert: 16.06.2012, 22:32
Wohnort: Rheingau

Beitragvon VoG » 12.02.2018, 19:47

Hallo,
nach langem Profitieren in diesem Forum möchte ich auch mal etwas zurückgeben und meine Skripte vorstellen. Ich benutze Mpd auf dem Computer, auf dem ein archlinux installiert ist. Als Frontend für mpd benutze ich Mpdroid auf meinem Tablet. Da paßt es ganz hervorraged in diesen Thread.
Mein Ansatz ist der:
Mpd ruft die Tools von Frank (VolRace und PlayHRT) nicht direkt über eine pipe auf. Stattdessen stellt Mpd die Daten in eine Fifo, über einen MPD Client (kurz: mpc) wird ein anderes Skripts aufgerufen, das wiederum den fifo ausliest. Der Vorteil ist der, daß das mpc-Skript Infos zu Lautstärke und Sampling Rate von mpd bekommt, die dann als Parameter weitergereicht werden können.

Zuerst die mpd-Konfiguration:
Im "/etc/mpd.conf" wird die Bitrate auf 32 float gesetzt, die SampleRate wird unverändert durchgelassen. Die Daten werden in die Fifo '/dev/shm/play.raw' geschrieben.
pid_file "/run/mpd/mpd.pid"
db_file "/home/mpd/mpd.db"
log_file "/tmp/mpd.log"

state_file "/var/lib/mpd/mpdstate"
playlist_directory "/NAS/playlists"
music_directory "/NAS/music"
user "mpd"
group "mpd"
# Buffer defaults to 4096 kB. but smaller sounds better.
audio_buffer_size "262"
buffer_before_play "16%"

filesystem_charset "UTF-8"
id3v1_encoding "UTF-8"

resampler {
   plugin "soxr"
   name "unused, zero padding only"
   quality "very high"
}

audio_output {
   type "fifo"
   name "shared memory"
   path "/dev/shm/play.raw"
   mixer_type "null"
#   samplerate unchanged, bitrate float (32 bit), 2 channels
   format "*:f:2"
   always_on "true"
}


Das mpc-Skript "mpc.py":
Das Skript lauscht als MPD client auf Events von mpd. Es tut 4 Dinge:
- beim Event "play" liest es die SampleRate aus und startet das playhrt-Skript "playFromFifo.sh" mit den passenden Parametern
- ‎bei Events "play" oder "pause" stoppt es das playhrt-Skript "playFromFifo.sh"
- ‎beim Event "volume" liest es die Lautstärke aus und setzt den passenden Wert in eine Datei /tmp/volrace.
- ‎Es ist noch ein Feature zum Spielen dabei. Wenn in Mpd UI der Parameter 'Verbrauchsmodus' gesetzt ist, wird der Lautstärke-Schieberegler zum Ändern des zweiten Volrace-parameters 'race coefficient' anstelle der Lautstärke benutzt.

Mein mpc-Skript "mpc.py" ist in Python geschrieben, es setzt auf die python-Library 'python-mpd2' auf.
#!/usr/bin/python
import subprocess
import signal
import os
import mpd
import time
import math

# Needed: mpd server
MPD_SERVER=u"localhost"
# Needed: Set the music directory as configured in mpd.conf
MUSIC_DIRECTORY = u"/NAS/music/"
# if you want set volume in a VOLRACE file on a remote server
VOLRACE_SERVER=u"mpd@192.168.1.16"

# with 3 parameters "samplerate" (e.g. "44100"), "bitdepth" (e.g. "32"), and the full file name
PLAY_CMD = u"/opt/scripts/playFromFifo.sh"

INITIAL_VOLUME = "0.1"
INITIAL_RACE_COEFF = "0"
volume=INITIAL_VOLUME
race_coeff = INITIAL_RACE_COEFF

client = mpd.MPDClient(use_unicode=True)
client.connect(MPD_SERVER, 6600)

with open("/tmp/VOLRACE", "w") as volumeFile:
   volumeFile.write("%s   53   %s" % (INITIAL_VOLUME, INITIAL_RACE_COEFF))
event = None
playProcess = None

while True:
   event = client.idle()

   print("Event is %s" % event)
   if event == ["mixer"]:
      
      value = float(client.status()["volume"])/100
      value = math.expm1(value)/1.72
      consume = client.status()["consume"]
      # for playing around with volrace: Set the race cofficient via MPD GUI
      # If comsumption mode is not checked, set volume between 0 and 1.0
      if consume == "0":
         volume = value
      # if consumption mode is checked, set race coeeficient between 0 and 0.25
      if consume == "1":
         race_coeff = value * 0.25
      print("Setting volume=%s and race coefficient=%s" % (volume, race_coeff))
      # set a local VOLRACE file
      with open("/tmp/VOLRACE", "w") as volumeFile:
         volumeFile.write("%s   53   %s" % (volume, race_coeff))

      # Optional
      # try to set volume in a VOLRACE file on a remote server VOLRACE_SERVER
      try:
         if not VOLRACE_SERVER is None:
            volraceCmd = ['ssh', VOLRACE_SERVER, 'echo "' + str(volume/4) + '" > /tmp/VOLRACE']
            print(volraceCmd)
            volraceProcess = subprocess.check_output(volraceCmd)
      except:
         print("Error connecting to %s" % VOLRACE_SERVER)
         volraceProcess = None
      
   if event == ["player"]:
      status = client.status()
      state = status["state"]
      currentsong = client.currentsong()

      try:
         file = MUSIC_DIRECTORY + currentsong["file"]
      except:
         file = None
      print("command: %s , currentsong: %s" % (state, file))
      if state == u"play":
         if not playProcess is None:
            os.killpg(os.getpgid(playProcess.pid), signal.SIGTERM)
         

         # audio should look like: "44100:24:2"
         audio = status["audio"]
         audioArray = audio.split(':')
         print("Sample rate and bit depth are: %s and %s" % (audioArray[0], audioArray[1]))
         if not file is None:
            playCmdList = [PLAY_CMD, audioArray[0], audioArray[1], file]
            playProcess = subprocess.Popen(playCmdList, shell=False, preexec_fn=os.setsid)

      if state == u"pause" or state == u"stop":
         if not playProcess is None:
            os.killpg(os.getpgid(playProcess.pid), signal.SIGTERM)
            playProcess = None


Das playhrt-Skript "playFromFifo.sh":
Dieses Skript ruft letzendlich playhrt auf. Die 2 Parameter Samplerate und Filename werden als Parameter übergeben. Mein Skript verzichtet auf Upsampling, stattdessen wird Brutefir parametrisiert abhängig von der SampleRate aufgerufen. Auch die Parameter für playhrt sind unterschiedlich je nach SampleRate.
Das Skript liest die Daten aus der Fifo, und schleust sie über verschiedene Zwischenstufen (Brutefir und volrace) weiter an playhrt, in meinem Fall läuft playhrt auf einem anderen Server, einem Beaglebone Green, auf dem ebenfalls archlinux läuft.
#!/bin/bash

CARD="default:CARD=UAC2"
EXTRABYTESBUF=0
EXTRABYTESPLAY=0
VERBOSE="--verbose --verbose"
AUDIOCOMPUTER="mpd@192.168.1.50"
# Sample format of DAC
SAMPLEFORMAT=S32_LE

HOST="192.168.1.102"
PORT=5570
PLAYHRTLOGFILE=/tmp/playhrt.log

ORIG_RATE=$1
ORIG_BITLENGTH=$2
FILENAME=$3
echo "Original Bitdepth is ${ORIG_BITLENGTH}"
echo "Original Sample rate is ${ORIG_RATE}"
echo "File name is ${FILENAME}"

# Overwrite the parameter. mpd reports the original bitlength. But in mpd.conf we set it to float (32 bit)
ORIG_BITLENGTH=32
# no oversampling
SAMPLERATE=${ORIG_RATE}

# For parameter HW_BUFFER, set playhrt parameter "--verbose --verbose"
# and see content of file PLAYHRTLOGFILE. Choose smallest value.

if [ "${ORIG_RATE}" = "96000" ]; then
# 96000 * 2 * 4
BYTESPERSECOND=768000
LOOPSPERSECOND=1000
BLOCKSIZE=768
HW_BUFFER=4096
BRUTEFIRCONFIG=/opt/filters/96000.txt

elif [ "${ORIG_RATE}" = "48000" ]; then
# 48000 * 2 * 4
BYTESPERSECOND=384000
LOOPSPERSECOND=1000
BLOCKSIZE=384
HW_BUFFER=2048
BRUTEFIRCONFIG=/opt/filters/48000.txt

elif [ "${ORIG_RATE}" = "88200" ]; then
  # 88200 * 2 * 4
  BYTESPERSECOND=705600
  LOOPSPERSECOND=1600
  BLOCKSIZE=441
  HW_BUFFER=7526
  BRUTEFIRCONFIG=/opt/filters/88200.txt

elif [ "${ORIG_RATE}" = "44100" ]; then
  # 44100 * 2 *4
  BYTESPERSECOND=352800
  LOOPSPERSECOND=800
  BLOCKSIZE=441
  HW_BUFFER=3763
  BRUTEFIRCONFIG=/opt/filters/44100.txt

elif [ "${ORIG_RATE}" = "192000" ]; then
# 192000 * 2 * 4
BYTESPERSECOND=1536000
LOOPSPERSECOND=1000
BLOCKSIZE=1536
HW_BUFFER=8192
BRUTEFIRCONFIG=/opt/filters/192000.txt
fi
echo "bytespersecond is ${BYTESPERSECOND}"

rm -f /dev/shm/bl{1,2,3} /dev/shm/sem.bl{1,2,3}*
rm -f /dev/shm/bl{A,B,C} /dev/shm/sem.bl{A,B,C}*

trap "trap - SIGTERM && kill -- -$$ " SIGINT SIGTERM EXIT

# mpd fills the fifo with format FLOAT_LE (32 bit)
cat /dev/shm/play.raw | \
  chrt -f 97 writeloop --block-size=${BLOCKSIZE} --file-size=36864 --shared /blA /blB /blC &

sleep 0.1

# volrace reads format FLOAT_LE (32 bit), outputs FLOAT64_LE.
# brutefir reads format FLOAT64_LE, and outputs S32_LE as needed by DAC
chrt -f 97 catloop --block-size=${BLOCKSIZE} --shared /blA /blB /blC | \
      chrt -f 98 volrace  --float-input  --param-file=/tmp/VOLRACE | \
      chrt -f 98 brutefir -quiet ${BRUTEFIRCONFIG} | \
      chrt -f 99 writeloop  --block-size=${BLOCKSIZE} --file-size=9216 --shared /bl1 /bl2 /bl3 &

sleep 0.3

REMOTE="nohup sleep 0.2 >/dev/null 2>/dev/null </dev/null ;\
   nohup chrt -f 99 playhrt ${VERBOSE} \
      --host=${HOST} --port=${PORT} \
                     --sample-rate=${SAMPLERATE} \
                     --sample-format=${SAMPLEFORMAT} \
                     --device=${CARD} \
                     --extra-bytes-per-second=${EXTRABYTESPLAY} \
           --loops-per-second=${LOOPSPERSECOND} \
           --hw-buffer=${HW_BUFFER} \
                     >/dev/null 2>${PLAYHRTLOGFILE} </dev/null "

REMOTE='sh -c "( (  '${REMOTE}' ) & )"'

ssh -f ${AUDIOCOMPUTER} "${REMOTE}"

chrt -f 99 bufhrt \
       --bytes-per-second=${BYTESPERSECOND} --loops-per-second=${LOOPSPERSECOND} \
       --input-size=${BLOCKSIZE}  --port-to-write=${PORT} \
       --extra-bytes-per-second=${EXTRABYTESBUF} \
       --shared /bl1 /bl2 /bl3 \
       ${VERBOSE}



Zur Verbindung zwischen Computer und Beaglebone benutze ich ssh. Das ist am einfachsten, wenn der User 'mpd' auf beiden Rechnern existiert und das mpc-Skript als User 'mpd' gestartet wird, dann wird auch das playhrt-Skript als User 'mpd' aufgerufen.

Bei mir wird mpd automatisch per Start-service gestartet. Das mpc-Skript starte ich zur Zeit noch manuell, um alle Konsolenausgaben überprüfen zu können. Wenn es völlig stabil läuft, wird es umgestellt und über einen Start-service gestartet werden.

Möge dieser Beitrag als Inspiration für andere Versuche nützlich sein.
Cheers, Volker.
Bild
VoG
Aktiver Hörer
 
Beiträge: 4
Registriert: 23.06.2016, 20:37

Beitragvon Martin » 13.02.2018, 23:23

Hallo Volker,
Vielen Dank, das ist ein interessanter Ansatz. Ich werde es demnächst mal damit versuchen.

Viele Grüße
Martin
Bild
Martin
Aktiver Hörer
 
Beiträge: 75
Registriert: 15.03.2012, 15:23

Beitragvon modmix » 02.04.2018, 01:15

Hallo,

für ein Proof-of-Concept möchte ich gerne zu einem Audiofile.wav etwas Rauschen hinzufügen (habe z.B. ein mit Arta erzeugtes rauschen.wav).

Geht soetwas mit sox o.ä.?
Wenn ja, wie?
Sehe den Wald vor lauter Bäumen nicht...

Dank im Voraus
Ulli
Bild
modmix
Aktiver Hörer
 
Beiträge: 2405
Registriert: 17.07.2010, 15:58

Beitragvon Martin » 02.04.2018, 09:28

Hallo Ulli,
mit audacity sollte es gehen:

https://manual.audacityteam.org/man/mixing.html

Grüße
Martin
Bild
Martin
Aktiver Hörer
 
Beiträge: 75
Registriert: 15.03.2012, 15:23

Beitragvon Koala887 » 13.04.2018, 22:08

Hallo zusammen,

mit Franks Playhrt hatte ich ja schon länger geliebäugelt, allerdings störte mich daran der mangelnde Bedienkomfort und die Möglichkeit alle Files ohne Upsampling abzuspielen. Da war ich durch Christophs AudioPE und Jplay Streamer schon etwas verwöhnt. :wink:

Volkers mpc-Skript gab dann den entscheidenden Ausschlag es doch mal zu versuchen. :cheers:
Ein Debian war schnell installiert und die ersten Versuche mit Franks playsimple Skript klangen schon sehr vielversprechend, allerdings hatte ich Anfangs Probleme mit jeder Menge delayed Loops und sehr hohen extra-bytes-per-second Werten, um den Puffer stabil zu bekommen. Also fing ich an alle möglichen Tuningtips umzusetzen und habe einen RT-Kernel installiert, die delayed Loops wurden zwar weniger, aber der Puffer war immer noch nicht besonders stabil.

Dann habe ich angefangen Franks Programme zu studieren und habe herausgefunden, dass man die loops-per-second so wählen sollte, dass die Samplerate durch loops-per-second teilbar ist. Bei 44,1kHz wären das z.B.: 980, 1050, 1225, usw.
Die 1050 Loops erwiesen sich als beste Wahl, damit hatte ich dann statt ca. 800 extra-bytes nur noch 8 und der Puffer schwankte nur noch um ein paar Frames. :D
Das blieb natürlich nicht ohne klangliche Folgen und gefiel mir inzwischen besser als das AudioPE.

Sobald die Audiodaten aber über den Mpd geliefert wurden, wurde der Klang wieder schlechter. :roll:
Das Schöne an Volkers mpc-Skript war, dass es den vollständigen Dateinamen mit Pfad angibt. Das funktioniert sogar mit Upnp Pfaden.
Also habe ich kurzer Hand den Mpd auf Null Ausgabe konfiguriert und das Audiofile direkt per Wget in den Shared Memory geladen, wo es dann von Sox decodiert und an writeloop übergeben wird.
#!/bin/bash

wget $3 -qO /dev/shm/play.wav &
CARD="hw:1,0"
# VERBOSE="--verbose --verbose"
SAMPLERATE=$1
BITLENGTH=$2
FILENAME=$3
#echo "Original Bitdepth is ${BITLENGTH}"
#echo "Original Sample rate is ${SAMPLERATE}"
#echo "File name is ${FILENAME}"

BITLENGTH=32
SAMPLEFORMAT=S32_LE
if [ "${SAMPLERATE}" = "96000" ]; then
  FILESIZE=10240
  LOOPSPERSECOND=1500
  BLOCKSIZE=256
  HW_BUFFER=8192
  EXTRABYTESPLAY=24

elif [ "${SAMPLERATE}" = "48000" ]; then
  FILESIZE=5120
  LOOPSPERSECOND=1500
  BLOCKSIZE=256
  HW_BUFFER=8192
  EXTRABYTESPLAY=12

elif [ "${SAMPLERATE}" = "88200" ]; then
  FILESIZE=6720
  LOOPSPERSECOND=1050
  BLOCKSIZE=336
  HW_BUFFER=16800
  EXTRABYTESPLAY=18

elif [ "${SAMPLERATE}" = "44100" ]; then
  FILESIZE=3360
  LOOPSPERSECOND=1050
  BLOCKSIZE=336
  HW_BUFFER=16800
  EXTRABYTESPLAY=9

elif [ "${SAMPLERATE}" = "192000" ]; then
  FILESIZE=15360
  LOOPSPERSECOND=1500
  BLOCKSIZE=256
  HW_BUFFER=16384
  EXTRABYTESPLAY=47
fi

rm -f /dev/shm/bl{1,2,3} /dev/shm/sem.bl{1,2,3}*

trap "trap - SIGTERM && kill -- -$$ " SIGINT SIGTERM EXIT

sleep 1
chrt -f 97 taskset -c 2 sox /dev/shm/play.wav -t raw -r ${SAMPLERATE} \
                        -c 2 -e signed -b ${BITLENGTH} - | \

chrt -f 98 taskset -c 2 writeloop --force-shm \
                        --block-size=${BLOCKSIZE} \
                        --file-size=${FILESIZE} \
                  --shared /bl1 /bl2 /bl3 &

chrt -f 99 taskset -c 3 playshm \
                  --device=${CARD} \
                        --sample-rate=${SAMPLERATE} \
                        --sample-format=${SAMPLEFORMAT} \
                        ${VERBOSE} \
                  --non-blocking-write \
                        --extra-bytes-per-second=${EXTRABYTESPLAY} \
                        --loops-per-second=${LOOPSPERSECOND} \
                        --hw-buffer=${HW_BUFFER} \
                        --shared /bl1 /bl2 /bl3


Der einzige Nachteil dabei ist, das Ganze spielt nicht gapless und bei Pause startet das Lied von vorne, was mich aber nicht besonders stört. Für den guten Klang macht man gerne ein paar Abstriche. 8)

Schöne Grüße
Daniel
Bild
Koala887
Aktiver Hörer
 
Beiträge: 518
Registriert: 27.12.2010, 18:23
Wohnort: Eltmann, Unterfranken

Beitragvon Koala887 » 14.04.2018, 09:55

Hallo,

hier noch ein paar Tips, welche ich hier noch nicht gefunden habe:

Wenn man ein Programm mit taskset einem bestimmten CPU-Kern zuordnet, sollte man vorher auch dafür sorgen, dass keine weiteren Programme auf dieser CPU laufen. Bei einem 4 Kern Prozessor kann man z.B. mit dem Bootparameter isolcpus=1,2,3 die Kerne 2-4 isolieren, sodass erstmal keine Prozesse darauf gestartet werden, und kann dann mittels taskset bestimmte Programme zuweisen. Das restliche Linuxsystem läuft dann nur noch auf dem ersten Kern.

Mitunter kann es sich lohnen dem Kernel eine andere Clockquelle zuzuweisen. Alsa bevorzugt (wenn vorhanden) den HPET Timer als Clock. Der Linuxkernel hingegen verwendete bei mir den TSC Timer, da dieser schneller ist. Mit dem Befehl:
# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
kann man die aktuell verwendete Clock auslesen und mit
# echo "hpet" > /sys/devices/system/clocksource/clocksource0/current_clocksource
im laufenden Betrieb die Clockquelle wechseln.
Mit folgendem Befehl kann man vorher prüfen, welche Clocks möglich sind:
# cat /sys/devices/system/clocksource/clocksource0/available_clocksource

In meinem Fall klang der HPET Timer angenehmer und ruhiger, obwohl ich mit dem TSC Timer deutlich bessere Latenzen hatte.
Hat man die passende Clock gefunden, kann man mit dem Bootparameter clocksource=hpet die Einstellung fest übernehmen.

Schöne Grüße
Daniel
Bild
Koala887
Aktiver Hörer
 
Beiträge: 518
Registriert: 27.12.2010, 18:23
Wohnort: Eltmann, Unterfranken

Beitragvon Daihedz » 15.04.2018, 20:55

Hallo Daniel
Koala887 hat geschrieben: ... Wenn man ein Programm mit taskset einem bestimmten CPU-Kern zuordnet, sollte man vorher auch dafür sorgen, dass keine weiteren Programme auf dieser CPU laufen. Bei einem 4 Kern Prozessor kann man z.B. mit dem Bootparameter isolcpus=1,2,3 die Kerne 2-4 isolieren, sodass erstmal keine Prozesse darauf gestartet werden, und kann dann mittels taskset bestimmte Programme zuweisen. Das restliche Linuxsystem läuft dann nur noch auf dem ersten Kern. ...

Super! Sehr schön!

Frage: Kann man die Funktionalität von isolcpus durch einen äquivalenten Befehl auch bei Bedarf dynamisch, d.h. im Ablauf eines Scripts schalten? Z.B. sinngemäss dergestalt:
...
$ AequivalentVonIsolcpus=2,3
$ taskset -c 2 ...
$ taskset -c 3 ..
...

oder so:
...
$ echo "0" > /sys/devices/system/cpu/cpu2/online
$ echo "0" > /sys/devices/system/cpu/cpu3/online
$ AequivalentVonIsolcpus=2,3
$ echo "1" > /sys/devices/system/cpu/cpu2/online
$ echo "1" > /sys/devices/system/cpu/cpu3/online
$ taskset -c 2 ...
$ taskset -c 3 ..
...
In der zweiten Variante wäre sichergestellt, dass die auf den Kernen 2 und 3 laufenden Prozesse mit dem Abschalten dieser Kerne zuerst auf die (noch) laufenden anderen Kerne umverteilt würden, bevor AequivalentVonIsolcpus wirksam wird - falls dies nötig wäre.

Hinwegbalanciert-nichtmehrschedulisierte Grüsse
Simon
Bild
Daihedz
Aktiver Hörer
 
Beiträge: 541
Registriert: 25.06.2010, 15:09

Beitragvon Koala887 » 16.04.2018, 06:39

Hallo Simon,

ein direktes Äquivalent kenne ich jetzt nicht, aber mit der Funktion cpuset sollte es funktionieren, habe ich aber noch nicht getestet. Näheres dazu gibt es hier.

Schöne Grüße
Daniel
Bild
Koala887
Aktiver Hörer
 
Beiträge: 518
Registriert: 27.12.2010, 18:23
Wohnort: Eltmann, Unterfranken

Beitragvon ZZTop » 16.04.2018, 22:23

Lauter Profis hier. Ich weiß nicht ob ich hier als Linux-Anfänger richtig bin, möchte aber dennoch berichten:

Da Win 10 alle für die Klangverbesserungen wesentlichen Einstellungen in der Registry ignoriert und nach belieben überschreibt (was tierisch nervt!) wollte ich mal Liniux ausprobieren.
Gibt ja nun auch JRiver für Linux. Die Installation der Demo bei Linux Mint per Klick und Maus war problemlos. Keinerlei Terminaleingaben nötig. :cheers:
Ich brauchte nichtmal einen extra Treiber für meinen Auralic Vega DAC zu installieren. Mint hat alles automatisch erkannt und in der Systemsteuerung angezeigt.
Was mich nur wundert sind die DEUTLICHEN !!!! Klangunterschiede zwischen Win 10 und Linux. Beides angeblich Bitidentisch da über ASIO bzw. ALSA.
Die eine Version klingt rund, schön und warm, die andere analytischer,kälter dafür dynamischer, lebendiger.
Was ist wohl "richtiger"? Ein OS klingt mit Gesang und natürlichen Instrumenten wie Streichern, Klavier, Kontrabass.... "besser", jedenfalls natürlicher.
Das andere Betriebssystem DEUTLICH !! spektakulärer und auflösender, besonders bei elektronisch erzeugter Musik.
Bei so deutlichen Unterschieden frage ich mich : was ist richtiger?
Hat irgendwer hier eigene Erfahrungen dazu gemacht?

greetz
US
Bild
ZZTop
Aktiver Hörer
 
Beiträge: 54
Registriert: 15.03.2012, 15:27

Beitragvon Koala887 » 17.04.2018, 12:45

Hallo Uwe,
ZZTop hat geschrieben:Bei so deutlichen Unterschieden frage ich mich : was ist richtiger?

Das was besser gefällt? :wink:

Meiner Erfahrung nach ist spektakulär und hochauflösend meist nicht langzeittauglich und man ermüdet schnell.
Für mich sollte eine gute Anlage ruhig und unauffällig spielen und gleichzeitig aber auch dynamisch sein. Details sollten nicht hervorstechen, aber bei genauem Hinhören doch alle vorhanden sein.
Das ein oder andere zu erreichen ist leicht, aber alles unter einen Hut zu bekommen die Kunst. :wink:

Elektronische Musik halte ich zum Testen allerdings für völlig ungeeignet. Es muss ja nicht unbedingt Klassik sein, aber zumindest natürliche Instrumente.

Schöne Grüße
Daniel
Bild
Koala887
Aktiver Hörer
 
Beiträge: 518
Registriert: 27.12.2010, 18:23
Wohnort: Eltmann, Unterfranken

VorherigeNächste

Zurück zu Computer-HiFi

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste