Jackd
template jackd
Most often a computer has multiple soundcards with independent clocks sources.
They drift with respect to each other, so trying to group them all in a single jack instance fails.
In some cases this can even apply to multiple devices on the same mainboard or PCB, there may be multple crystals
providing clocking.
The Resolution found is to run separate jackd instances, creating a plesiochronous bridge between the synchronous jackd islands.
We define a environment based pcm in ~/.asoundrc to allow separate jackd instances to be steered to their soundcard by environment variable. I have called it jds as short for "jack default server"
This can call hw: pcms set in the environment or others defined in asoundrc if useful to shuffle audio channels to put them in order.
- pcm.jds { @func getenv vars [ JACK_DEFAULT_SERVER ] default "defaults.pcm.card" }
- ctl.jds {
- @args.CTL {
- type string
- default {
- @func getenv vars [ JACK_DEFAULT_SERVER ] default "defaults.ctl.card"
- }
- }
- @func refer
- name {
- @func concat
- strings [ "ctl." $CTL ]
- }
- }
Edit ~/.jackdrc so that it uses the environment
- /usr/bin/jackd -dalsa -djds -r192000 -p1024 -n2
If using qjackctl that can be made to call jds as the input and output alsa device and then
different jacks will use their respective alsa hardware.
Define a sub-pcm for the p9d ws onboard...
For the best analogue sound quality use the fastest rate, however toslink attached equipment may not cope with that so downsample if needed,
Upon first attempt a p9d pcm is defined to handle analogue and digital
- pcm.p9d {
- type asym
- playback.pcm {
- type multi
- slaves {
- analogue.pcm "surround71:PCH"
- analogue.channels 8
- digital.pcm {
- type rate
- slave {
- pcm "iec958:PCH,AES0=0x04,AES1=0x82,AES2=0x00,AES3=0x0a"
- rate 96000
- # fast
- converter "samplerate_order"
- }
- digital.channels 2
- }
- bindings.0.slave digital
- bindings.0.channel 0
- bindings.1.slave digital
- bindings.1.channel 1
- bindings.2.slave analogue
- bindings.2.channel 0
- bindings.3.slave analogue
- bindings.3.channel 1
- bindings.4.slave analogue
- bindings.4.channel 2
- bindings.5.slave analogue
- bindings.5.channel 3
- bindings.6.slave analogue
- bindings.6.channel 4
- bindings.7.slave analogue
- bindings.7.channel 5
- bindings.8.slave analogue
- bindings.8.channel 6
- bindings.9.slave analogue
- bindings.9.channel 7
- master 1
- }
- capture.pcm {
- type multi
- slaves {
- analogue.pcm "hw:PCH,0"
- analogue.channels 2
- analogue2.pcm "hw:PCH,2"
- analogue2.channels 2
- }
- bindings.0.slave analogue
- bindings.0.channel 0
- bindings.1.slave analogue
- bindings.1.channel 1
- bindings.2.slave analogue2
- bindings.2.channel 0
- bindings.3.slave analogue2
- bindings.3.channel 1
- master 0
- }
- }
... and an m-audio m2496 pci card. Here shuffle the digital outputs to the beginning for ease of use.
- pcm.sp2dif {
- type asym
- # playback.pcm "hw:0"
- playback.pcm {
- slave.pcm "hw:CARD=M2496,DEV=0,SUBDEV=0"
- type route
- ttable {
- 0.8= 1
- 1.9= 1
- 2.0= 1
- 3.1= 1
- 4.2= 1
- 5.3= 1
- 6.4= 1
- 7.5= 1
- 8.6= 1
- 9.7= 1
- }
- }
- capture.pcm "hw:CARD=M2496,DEV=0,SUBDEV=0"
- }
- # http://www.alsa-project.org/main/index.php/Asoundrc
- # test with alsamixer -Dsp2dif
- ctl.sp2dif {
- @func refer
- name "ctl.hw:M2496"
- }
Lets now startup some jackd. The use of promiscuous mode is useful as then jackd does not include uid in files used to communicate with jack clients.
This may enable clients to run in other user accounts in future, for 2019 that does not work well and pulseaudio can be opened up in this way instead.
- export JACK_PROMISCUOUS_SERVER=
- env JACK_DEFAULT_SERVER=p9d `<~/.jackdrc`
- env JACK_DEFAULT_SERVER=sp2dif `<~/.jackdrc`
Suppose alsaplayer connects to the p9d jackd, since subsequenct jackd attached to a running pulseaudio misbehaved, next best things is to loopback the sound between the clocking islands:
At the time of exploring this pulseaudio does not also cope well with being linked to multiple jack instances,
so it is probably best to link it to a primary jackd2 that provides clocking, then bridge audio between jacks with jack-record
- alsa3 ()
- {
- JACK_DEFAULT_SERVER=p9d jack-record -f 0x030006 -n 2 -p alsaplayer-`pidof alsaplayer`:out_%d /dev/stdout | pv | JACK_DEFAULT_SERVER=sp2dif JACK_PLAY_CONNECT_TO=system:playback_%d jack-play /dev/stdin
- }
It is possible to swap p9d with sp2dif in the examples if the latter sounds better.
p9d errors
- ERROR: ALSA: could not complete playback of 1024 frames: error = -32
- Mon Aug 8 21:05:48 2022: ERROR: ALSA: could not complete read of 1024 frames: error = -32
- Mon Aug 8 21:05:48 2022: ERROR: JackAudioDriver::ProcessSync: read error, stopping...
Subsequently it is discovered that PCH pcms drift or something despite being on the same card.
Therefore, instead of using various alsa plugins with PCH, try to make the hardware do it.
- pcm.p9d {
- type hw
- card PCH
- }
Use hda-verb to issue instructions to Realtek ALC892
- hda-verb /dev/snd/hwC2D0 0 PARAMETERS VENDOR
- value = 0x10ec0892 # as in realtek ALC892 codec
- hda-verb /dev/snd/hwC2D0 0 PARAMETERS NODE_COUNT
- find out how many nodes come off the root 0x00ff00ff (first node index, second node count) = 0x1001, one node
- hda-verb /dev/snd/hwC2D0 1 PARAMETERS FUNCTION_TYPE
- Find out the function of node 1, 0x101 = audio
- hda-verb /dev/snd/hwC2D0 1 PARAMETERS NODE_COUNT
- find out how many nodes come off the one at index 1, 0x20025, meaning nodes from 2 to 38 inclusive
- Typical default is feeding off sub pcm 3: for ac3 output
- hda-verb /dev/snd/`basename /sys/devices/pci0000:00/0000:00:1b.0/sound/card*/hw*` 0x6 0x706 0x60
- However I need uncompressed audio, so set the SPDIF output to copy the green rear jack
- The 0x50 could be substituted for 0x52 or 0x54 or 0x56 to get grey black and orange jacks
- However I need uncompressed audio, so set the SPDIF output to copy the green rear jack
- hda-verb /dev/snd/`basename /sys/devices/pci0000:00/0000:00:1b.0/sound/card*/hw*` 0x6 0x706 0x50
- The default output 48000Hz, 24-bit, dual channel, is 0x31
- hda-verb /dev/snd/`basename /sys/devices/pci0000:00/0000:00:1b.0/sound/card*/hw*` 0x6 GET_STREAM_FORMAT 0
- Dual channel, 24-bit 96000Hz output
- hda-verb /dev/snd/`basename /sys/devices/pci0000:00/0000:00:1b.0/sound/card*/hw*` 0x6 SET_STREAM_FORMAT 0x831
- Dual channel, 32-bit 96000Hz output, the best mode supported by Sennheiser RS220
- hda-verb /dev/snd/`basename /sys/devices/pci0000:00/0000:00:1b.0/sound/card*/hw*` 0x6 SET_STREAM_FORMAT 0x841
- 192000Hz output, Sennheiser RS220 does not support this so get silence, but it can be put back to 96000Hz
- hda-verb /dev/snd/`basename /sys/devices/pci0000:00/0000:00:1b.0/sound/card*/hw*` 0x6 SET_STREAM_FORMAT 0x1831
It is also useful to mention programmability of VREFOUT, that is the electrical backfeed of between 2 and 4 volts present on the pc microphone jack, intended to power a preamplifier in a pc microphone, and said to be able to sink upto 5 milliamp of current.
I ended up with a systemd unit to automate that
- [Unit]
- Description=setup PCH hda
- [Service]
- ExecStart=/bin/sh -c '\
- hda-verb /dev/snd/$(basename /sys/*/*0000:00/0000:00:1b.0/*/*/hw*) 0x6 SET_CHANNEL_STREAMID 0x50\
- hda-verb /dev/snd/$(basename /sys/*/*/0000:00:1b.0/*/*/hw*) 0x6 SET_STREAM_FORMAT 0x841\
- '
- [Install]
- WantedBy=sound.target
Enjoy music with sound effects
Debian used to package jack-rack, that has been dropped though it can be still be compiled from source.
Debian also carries jconvolver for an even more realistic virtual concert experience,
however not all the impulse response files ship with it, probably for copyright reasons.
- First one was quite easy, author's page
- porihall, redirected. The files have a copyright restriction so could apply to derived works such as audio rendered via jconvolver with them.
- The "spacenet" was eventually found by good chance at york
Users may replace /var/local/union with the actual path of unpacked downloads.
- #!/bin/sh
- N=/var/local/union/http/kokkinizita.linuxaudio.org/linuxaudio/downloads/jconvolver-reverbs.tar.bz2/reverbs
- R=/var/local/union/http/legacy.spa.aalto.fi/projects/poririrs/wavs/porihall
- S=/usr/share/jconvolver/config-files/demo-reverbs/street
- C=$(readlink -f $1)
- < $C sed -s '
- s_/audio/reverbs/spacenet_/net/stat/mirror/https/webfiles.york.ac.uk/OPENAIR/IRs_g;
- s+HM2_000_WXYZ_48k.amb+hamilton-mausoleum/b-format/hm2_000_bformat_48k.wav+g;
- s+Lyd3_000_WXYZ_48k.amb+st-andrews-church/b-format/lyd3_000_bformat_48k.wav+g;
- s+MH3_000_WXYZ_48k.amb+maes-howe/b-format/mh3_000_bformat_48k.wav+g;
- s+Minster1_000_WXYZ_48k.amb+york-minster/b-format/minster1_bformat_48k.wav+g;
- s_/home/fons/acoustics/impresp/xtc_/usr/share/jconvolver/config-files/xtalk-cancel_g;
- s_/audio/reverbs/porihall_'$R'_g;
- s_/audio/reverbs_'$N'_g;
- s_street_'$S'_g;
- ' | jconvolver -s "${JACK_DEFAULT_SERVER}" /dev/stdin
Jackd for OpenAL (Such as ut2004)
Two files in the home directory allow openal applications like unreal tournament 2004
to be used with jack, and so with ALSA cards that do not really have their own mixer.
cat >> ~/.openalrc << EOF
(define devices '(alsa native))
(define alsa-device "plug:SLAVE=jack")
EOF
cat >> ~/.asoundrc << EOF
pcm.jack {
type jack
playback_ports {
0 alsa_pcm:playback_1
1 alsa_pcm:playback_2
}
capture_ports {
0 alsa_pcm:capture_1
1 alsa_pcm:capture_2
}
}
EOF
Use Jack / ALSA for festival output
(Parameter.set 'Audio_Method 'Audio_Command)
(Parameter.set 'Audio_Required_Format 'riff)
(Parameter.set 'Audio_Command "aplay -q -D plug:SLAVE=jack $FILE")
Goes in /etc/festival.scm
#!/bin/sh
mkfifo ~/.ut2004/System/speech
while true
do
cat ~/.ut2004/System/speech | while read
do
echo -ne "(SayText \""
echo -n $REPLY | sed 's/\\/\\\\/g
s/\"/\\"/g'
echo -e ".\")"
done
done | festival
This can now be used to provide a speech device
instead of the other
method involving a speechd for ut2004