SetBfree Hammond Organ (6)

Een Hammond Organ voor iedereen!

Tekst: Marjan Waldorp
Artikel uit Turning Wheel 2025-1

In deel 5 hebben we gezien hoe geluid, met name gedreven door gaming, zijn intrede deed in de computerwereld en hoe de geluidskaart en -chip snel een standaard onderdeel werden van elke computer. Ook zagen we hoe het direct door de applicatie aansturen van de geluidskaart plaats maakte voor een model van sound device drivers in de kernel. Met de toename van geluidsapplicaties, zoals muziek- en video players, onstond echter de behoefte aan een geluidsserver tussen de device drivers en de applicaties in, die:

  • het digitale geluid van de applicaties mixt
  • routeert naar het gewenste device
  • zonodig de resampling verzorgt naar de bitrate van het device
  • het volume centraal regelt (master volume)
  • via het netwerk het geluid naar een andere computer zendt

Een van de eerste geluidsservers was de Enlightened Sound Daemon (ESD, 1999), geschreven voor de Enlightenment desktop in Linux en UNIX systemen. OSS (deel 5) liet niet toe om het sound device file meer keren tegelijk te openen. Dus als één geluidsapplicatie het device file opende, hadden andere geluidsapplicaties geen toegang. ESD loste dit probleem op! Vandaag zijn alle desktop besturingssystemen uitgerust met een geluidsserver of -service. In Linux is PulseAudio (2004) nu de standaard voor de desktop omgeving. Daarnaast is er de Jack Audio Connection Kit (2002) voor professioneel geluid oftewel het werken met muziekinstrumenten. De nieuwste ontwikkeling is Pipewire, die beide werelden probeert te vereningen en bovendien video streams ondersteunt.

PulseAudio

PulseAudio is een geluidsserver voor consumenten toepassingen, zoals mediaspelers, webbrowsers, recorders, audio/video chat, enz. PulseAudio verbindt geluidsapplicaties automatisch met het gewenste audio device. PulseAudio is ontworpen voor een dynamische werkomgeving, waar applicaties gestart en gestopt worden, en waar zomaar de hardware verandert doordat de gebruiker bijv. een bluetooth hoofdtelefoon inschakelt. De doelstelling van PulseAudio is om de gebruiker optimaal te ondersteunen zonder hem met de techniek lastig te vallen. PulseAudio doet zijn werk soepel en automatisch. Zo start de PulseAudio daemon automatisch, wanneer een applicatie de socket (een soort device file) opent.

De belangrijkste beheertool is "PulseAudio Volume Control" (pavucontrol), waarmee o.a. het master volume, de volumes van de in- en uitvoerpoorten en het profiel van elk audio device ingesteld kan worden. In de taakbalk van de desktop is vaak een subset van pavucontrol terug te vinden. Voor de screenshot is een USB geluidskaart (adapter) ingeplugd als extra device:

Op de commandoregel is PulseAudio echter nog veel uitgebreider te beheren. We kunnen bijv. een lijst van alle uitgangen (sinks) opvragen:

 $ pactl list short sinks 
0 alsa_output.platform-sound.stereo-fallback module-alsa-card.c s16le 2ch 44100Hz IDLE

We zien de uitgangen van de in de ODROIDN2 ingebouwde geluidschip. Alhoewel, uitgangen? We zien er maar één! De PulseAudio module "module-udev-detect", die automatisch alle audio hardware zou moeten detecteren, is er niet in geslaagd om de andere twee uitgangen te vinden. Er gaat blijkbaar iets mis in de communicatie met de axg-sound-card driver. Vervelend, want zo kunnen we de audio DAC uitgang niet gebruiken. Gelukkig is dat probleem eenvoudig op te lossen door een module bij te laden. Dat kan met "pactl" in een draaiend systeem:

 $ pactl load-module module-alsa-sink device=hw:0,1 
21 [PulseAudio module number]

Wanneer we opnieuw de sinks opvragen, zien we wel de sink van de audio DAC:

 $ pactl list short sinks 
0 alsa_output.platform-sound.stereo-fallback module-alsa-card.c s16le 2ch 44100Hz IDLE
1 alsa_output.hw_0_1 module-alsa-sink.c s16le 2ch 44100Hz IDLE

Deze toevoeging gaat echter na een herstart verloren! We kunnen deze wijziging permanent maken door het PulseAudio opstartscript "/etc/pulse/default.pa" aan te passen. Als alternatief kunnen we in de gebruikersomgeving een nieuw opstartscript ".config/pulse/default.pa" creëren:

 # user default.pa 
.include /etc/pulse/default.pa
load-module module-alsa-sink device=hw:0,1

Door hierna PulseAudio opnieuw op te starten, wordt de nieuwe configuratie actief:

 $ systemctl --user restart pulseaudio.service

Desgewenst kunnen we de default sink op de audio DAC instellen:
(Deze instelling blijft na een herstart behouden.)

 $ pactl set-default-sink 1 
$ pactl get-default-sink
alsa_output.hw_0_1

Voor meer informatie over PulseAudio zie de Archlinux wiki en de PulseAudio gebruikers documentatie. 1 2

Latency

Responstijd (latency) is een belangrijke parameter bij het spelen op muziekinstrumenten. De verschillen tussen de diverse instrumenten zijn groot! Een gitaar reageert vrijwel direct op het tokkelen van de snaren. Bij een piano is de "travel time" (de tijd tussen het aanraken van de toets en het contact van de hamer met de snaren) 20-200 ms, afhankelijk van de aanslag. 3 Bij een pijporgel kan de responstijd aanzienlijk groter zijn! Allereerst is er de latency tussen het indrukken van de toets en het openen van de ventielen naar de pijpen. Dit is sterk afhankelijk van de toegepaste techniek: mechanisch, pneumatisch (tot 500 ms!) of elektrisch. Vervolgens moet de luchtkolom in de pijpen op gang komen. Tot slot dient het geluid van de pijpen de weg af te leggen naar de oren van de organist. De geluidssnelheid door de lucht is ca. 343 m/s oftewel 2,92 ms/m. Stel dat de pijpen op 10 meter afstand staan van de speeltafel, dan bedraagt die latency nog eens 29 ms. Ook bij digitale op software synthesizers gebaseerde muziekinstrumenten, zoals SetBfree, is de totale responstijd de som van alle latencies van de keten, dus van de mechanische traagheid van het MIDI-keyboard t/m de latency van de speakers naar de oren van de muzikant. Die totale responstijd moet zodanig zijn dat de muzikant die vertraging niet waarneemt. Uitgaande van de minimale travel time van een piano zou de totale responstijd dus niet veel meer dan ca. 20 ms moeten zijn.

Aan welke knoppen kunnen we draaien om de totale responstijd te beïnvloeden? Een heel belangrijke knop is hier de instelling van de framebuffer van de audio card driver. (Een frame is één sample van alle geluidskanalen bij elkaar.) Die framebuffer is een cruciaal element voor het functioneren van het gehele systeem! Zonder die buffer zouden alle processen voortdurend actief moeten zijn om real-time frames te genereren, verwerken en aan elkaar door te geven. Met de computers, zoals we die nu kennen, is dat echter technisch onmogelijk! Dat vele applicaties tegelijk actief zijn, is de illusie van de gebruiker. In werkelijkheid kunnen op een CPU met bijv. vier processorkernen maximaal vier processen tegelijkertijd actief zijn. Alle andere processen wachten op uitvoering of slapen. De processen in een digitaal audio systeem verwerken chunks van een aantal frames en leveren die uiteindelijk af bij de framebuffer van de audio card driver. De audio card driver voedt de DAC vanuit deze buffer met als resulaat een continu analoog signaal aan de uitgang. Hoe minder samples we bufferen, des te kleiner is de latency. Stellen we de buffer echter te klein in, dan bestaat het risico dat de processen de buffer niet op tijd bij kunnen vullen (buffer underrun). De DAC loopt dan "droog" met als gevolg korte onderbrekingen in de analoge geluidsstroom.

Wanneer we de framebuffer kleiner instellen, verandert dat niets aan het aantal te verwerken frames per tijdseenheid. Die factor wordt bepaald door de sample frequentie. Een sample frequentie van 96 kHz i.p.v. 48 kHz verdubbelt het aantal te verwerken frames per seconde en verdubbelt dus de systeembelasting! Verkleinen van de framebuffer heeft als gevolg dat alle processen in de keten vaker actief moeten worden om de buffer bij te vullen. De process schedular in de kernel (deel 3) moet dus sneller processen wisselen op de CPU. Zo'n "context switch" is een arbeidsintensieve operatie. Onnuttige arbeid! Het verhogen van het aantal context switches per seconde, verhoogt de overhead van het systeem. Mede vanuit dit perspectief zijn CPU's met meer processorkernen aantrekkelijk. Met meer processorkernen is er niet alleen meer verwerkings capaciteit, maar ook kan de schedular de processen verdelen over de kernen, waardoor er minder context switches nodig zijn. Een CPU met meer processorkernen verlaagt dus de overhead!

De framebuffer is opgebouwd uit minimaal twee blokken van een aantal frames, zodat wanneer de DAC alle frames van een blok heeft gelezen, dit door een nieuw blok met frames kan worden vervangen, terwijl de DAC het andere blok leest. De default instelling van PulseAudio is 4 "fragments" (de OSS term voor framebuffer blok) van 25 ms. De default latency van PulseAudio is dus 100 ms. Dat is een heel veilige instelling, prima geschikt voor consumenten toepassingen, maar te traag voor muziekinstrumenten. Weliswaar kan de default instelling gewijzigd worden, maar PulseAudio gebruikt deze default slechts als uitgangspunt en wijzigt de framebuffer instelling vervolgens dynamisch. Je kunt in PulseAudio dus geen vaste latency afdwingen, waardoor PulseAudio minder geschikt is voor professioneel geluid. Dat is het werkterrein van de Jack Audio Connection Kit!

Jack Audio Connection Kit

Jack Audio Connection Kit (2002) is een geluidsserver voor professioneel geluid oftewel het werken met muziekinstrumenten. Naar de gebruiker presenteert Jack zich als een patchpaneel. De gebruiker kan willekeurig verbindingen leggen tussen in- en uitgangen van de hardware en/of applicaties. Met Jack kan dus ook eenvoudig een keten van applicaties gemaakt worden, door de uitgang van een applicatie door te verbinden naar de ingang van een volgende applicatie. Jack is de software implementatie van de professionele opnamestudio!

Jack werkt met een vast in te stellen driver-latency, die niet automatisch wordt aangepast bij buffer under- of overruns. Jack voegt tijdens het verwerken van de pcm-streams geen extra latency toe. 4 De Jack clients (applicaties) kunnen uiteraard wel latency toevoegen. Bij Jack verwerken de clients de frame chunks synchroon op basis van een gemeenschappelijk kloksignaal, de "word clock", die wordt afgeleid van de sample clock van de geluidskaart. 5 6

Kunnen we met Jack geheel afzien van PulseAudio? In principe wel, alleen niet alle toepassingen (bijv. Firefox) ondersteunen Jack. Maar, geen probleem, met "pulseaudio-module-jack" kan PulseAudio als Jack client geconfigureerd worden. (Zie screenshot beheertool Qjackctl: PulseAudio Jack Sink)

Jack installatie en configuratie

1. Jack is niet standaard geïnstalleerd, dus installeren we Jack met apt-get:

 $ sudo apt-get install jackd2 qjackctl jack-tools jack-mixer jack-keyboard pulseaudio-module-jack audacious

2. Alvorens Jack te configureren, maken we het audio device vrij voor Jack:

 $ pactl list short cards 
0 alsa_card.platform-sound module-alsa-card.c
$ pactl set-card-profile 0 off
$ pactl list short sinks
2 auto_null module-null-sink.c s16le 2ch 44100Hz IDLE

3. Jack configureren

In tegenstelling tot de meeste Linux applicaties, werkt Jack niet met configuratiebestanden. De Jack daemon wordt eenvoudigweg opgestart met alle configuratieparameters als argumenten. Dat kan direct op de commandoregel (test), danwel via een opstartscript of met de grafische beheertool "Qjackctl" (qjackctl). Vanuit het desktop menu starten we Qjackctl en komen in het hoofdscherm:

We klikken op de "Setup" button en zien het configuratiescherm:

Aanbevolen instellingen:

  • Driver: alsa
  • Realtime: ✓
  • Interface: hw:ODROIDN2
  • Sample Rate: 48000
  • Frames/Period: 256
  • Periods/Buffer: 2

Wat betreft de sample rate zijn we afhankelijk van wat de hardware ondersteunt. De meeste geluidskaarten ondersteunen 44.100 en 48.000 Hz. Hoger gaan is voor ons project zinloos en leidt slechts tot onnodige cpu-belasting. Bij een sample rate van 48 kHz is de frametijd 1/48 ms = 0,0208 ms. Wanneer we de buffer opbouwen uit 2 periods (de ALSA term voor framebuffer blok) van 256 frames elk, is de latency: 0,0208 ms x 256 x 2 = 10,67 ms. Als alternatief zouden we 128 frames per periode kunnen instellen. De latency wordt dan 5,33 ms. Merk op dat dit de cpu-belasting aanzienlijk opjaagt! Alle Jack clients zullen nu twee maal zo vaak door de kernel gescheduled moeten worden. Omdat USB minder stabiel is, wordt geadviseerd bij USB-geluidskaarten 3 periods in te stellen.

Onder het subtabblad "Advanced" stellen we het output device in op de audio DAC: "hw:ODROIDN2,1"

Indien we de ouput van PulseAudio automatisch willen doorsturen naar Jack, vinken we in het tabblad "Misc" de optie "Enable JACK D-Bus interface" aan:

4. jackd starten

We sluiten het setup menu en starten de "jackd" daemon door in het hoofdmenu op "Start" te drukken.

Als Jack loopt, kunnen we de goede werking van Jack en PulseAudio testen met bijv. de Audacious mediaspeler (desktop menu). Audacious ondersteunt zowel Jack als PulseAudio. Wanneer we echter proberen via Jack een muziekbestand af te spelen, krijgen we een foutmelding dat de sample rate van het muziekbestand (44.100) niet past op de sample rate van het audio device (48.000). We moeten de Sample Rate Converter plugin van Audacious gebruiken en die handmatig op 48.000 Hz instellen. Dat is niet zo gebruikersvriendelijk als PulseAudio, die automatisch de sample rate converteert! Ja, Jack is voor de professionele audio gebruiker en die wordt geacht verstand van digitale audio te hebben!

Voor meer informatie over de Jack Audio Connection Kit zie jackaudio.org 7

Volgende keer meer over Pipewire!


  1. https://wiki.archlinux.org/title/PulseAudio

  2. https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/

  3. https://www.researchgate.net/publication/7603558_Touch_and_temporal_behavior_of_grand_piano_actions

  4. https://jackaudio.org/faq/no_extra_latency.html

  5. https://manual.ardour.org/synchronization/on-clock-and-time/

  6. https://jackaudio.org/faq/multiple_devices.html

  7. https://jackaudio.org