SetBfree Hammond Organ (8)

Een Hammond Organ voor iedereen!

Tekst: Marjan Waldorp
Artikel uit Turning Wheel 2025-3

Nu de sound infrastructuur stevig staat, wordt het tijd de blik op SetBfree zelf te richten. In deel 1 hebben we het concept van SetBfree besproken. SetBfree is een digitale software synthesizer. Je stopt er toetsaanslagen van een klavier in (MIDI) en je krijgt er digitaal geluid (PCM) uit. Het hart van SetBfree vormen de 91 digitale oscillatoren, één voor elk toonwiel. Het uitgangssignaal van deze oscillatoren wordt gemixt, vergelijkbaar met het drawbar systeem van het echte Hammond orgel. Maar hoe moeten we ons zo’n digitale oscillator nu voorstellen? Oscilleren betekent slingeren, schommelen. Wat slingert hier? De sleutel naar het antwoord vinden we, wanneer we kijken naar wat er van zo’n digitale software synthesizer verwacht wordt. Stel dat SetBfree in een Jack/Pipewire graph zit met een quantum van 512 frames. Dan moet SetBfree dus elke cyclus 512 frames leveren. Die frames zijn samengesteld op basis van de output van de digitale oscillatoren. Een digitale oscillator is dus een leverancier van frames. Het is een software functie, die op verzoek een aantal frames genereert. We komen hier op het terrein van de Digital Signal Processing.


Digital Signal Processing

Digital Signal Processing (DSP) is het softwarematig bewerken van digitale signalen. Laten we een eenvoudige software sinusoscillator bouwen om te onderzoeken hoe dit werkt. 1 Als programmeertaal gebruiken we de scripttaal Perl. Perl is op vrijwel elk Linux systeem standaard aanwezig.

Als we een sinusoscillatie beschouwen als een cyclisch fenomeen, dan kunnen we een sinusoscillatie ook voorstellen als een vector, die in een circel ronddraait rond zijn as. (Een vector heeft een richting en een grootte.) Een hele omwenteling is 1 periode. De omtrek van een circel is 2Pi * r. Een hele omwenteling is 360° of 2Pi radialen. Wanneer de oscillator loopt met een frequentie van f perioden per seconde, is de hoekfrequentie van de vector: ω = 2Pi * f (radialen per seconde). In deel 2 hebben we gezien dat de sample-frequentie minimaal 2x de hoogste frequentie van het analoge signaal moet zijn. Stel dat we een sample-frequentie van 48.000 Hz toepassen, dan is de hoogst mogelijke oscillator frequentie dus 24.000 Hz. Wanneer we 5.000 Hz als oscillator frequentie kiezen, nemen we 48.000 / 5.000 = 9,6 samples per periode. Na iedere sample draait de vector dan 2Pi / 9,6 = 0,655 radialen (37,5 °). In Perl gecodeerd:

    my $f_osc= 5000;             # Oscillator frequency
   my $fs = 48000;              # Sample frequency
   my $N = 10;                  # Number of samples

   my $pi = 22 / 7;
   my $w = 2 * $pi * $f_osc;    # Angular frequency
   my $dw = $w / $fs;           # Angular sample step size
   my $phi = 0;                 # Vector angle position
   my $out = 0;                 # Oscillator output

Nu kunnen we de samples genereren. De “for” lus wordt 11x doorlopen (0 .. 10). Elke keer wordt “sin ($phi)” berekend. Omdat het berekenen van een sinuswaarde veel rekenkracht vraagt, wordt in de praktijk de sinus vaak opgezocht via een vooraf aangelegde sinustabel. Dit werkt uiteraard vele malen sneller! Na de berekening verhogen we “$phi” met de staphoek “$dw”. Als “$phi” groter is dan 2Pi, trekken we er 2Pi vanaf, zodat “$phi” altijd ligt tussen 0 en 2Pi. De “printf” opdracht heeft Perl ontleend aan de programmeertaal “C”. Het eerste argument is een formaat specificatie. Daaropvolgend staan de op het scherm af te drukken variabelen. (Zie: man 3 printf)

    for my $n ( 0 .. $N ) {
       $out = sin ( $phi );
       printf "% 3.0ft% 5.3ft% 5.3fn", $n, $phi, $out;
       $phi = $phi + $dw;    # Next sample
       if ( $phi > 2 * $pi ) {
           $phi = $phi - 2 * $pi;
       }
   }

Dit programma laat de volgende uitvoer zien:

     n  rad      out
    0 0.000    0.000
    1 0.655    0.609
    2 1.310    0.966
    3 1.964    0.924
    4 2.619    0.499
    5 3.274   -0.132
    6 3.929   -0.708
    7 4.583   -0.992
    8 5.238   -0.865
    9 5.893   -0.380
   10 0.262    0.259

Het is aan de filtering in de DAC om hiervan een nette sinus te maken (deel 2).


Sinusoscillator in de praktijk

Nu ziet dit er in theorie prachtig uit, maar werkt dit ook echt in de praktijk? Het programmeren van een Jack-applicatie is misschien wat ingewikkeld, maar we zouden de samples in een audiobestand kunnen schrijven en dit bestand afspelen. Echter, hoe schrijven we samples in bijv. een WAV-audiobestand? Dat is nog niet zo eenvoudig! Daarvoor hebben we kennis nodig van de WAV standaard, zodat we op een correcte wijze om kunnen gaan met de architectuur van een WAV-bestand. Hier komt CPAN ons te hulp. CPAN (Comprehensive Perl Archive Network, 1993) is een software database, waarin Perl programmeurs hun software modules kunnen onderbrengen. Inmiddels telt CPAN meer dan 220.000 modules! Om via CPAN modules te kunnen installeren hebben we “cpanminus” nodig. We installeren dus eerst “cpanminus”. Vervolgens downloaden en installeren we met “cpanm” de Perl module “Audio::Wav”:

$ sudo apt-get install cpanminus

$ sudo cpanm Audio::Wav

Een korte toelichting bij het programma. De eerste regel is de “shebang” of “hash-pling” regel. Wanneer de eerste regel van een script begint met “#!”, voert Linux het hierachter vermelde programma uit met als eerste argument de padnaam van het script. De opzet is dat het betreffende programma het script interpreteert. Hash-pling maakt het makkelijk om scripts in diverse programmeertalen te kunnen schrijven.

$ ./digosc-wav.pl

Wordt uitgevoerd als:

$ /usr/bin/perl digosc-wav.pl

De WAV-standaard ondersteunt diverse sample formaten. We gebruiken het CD audio formaat 16-bit signed (-32767 - +32767). Eventueel kunnen we het volume wat dempen door de maximale waarde te vermenigvuldigen met “$atten”, zodat het geluid niet volle kracht door de luidsprekers zal schallen (regel 17, 23-24).

In regel 32 wordt een nieuw “Audio::Wav” object gecreëerd onder de referentie “$wav”. Een object is een structuur van variabelen, ingekapseld door “methods” (functies). Dat klinkt ingewikkeld, maar het werkt eigenlijk min of meer hetzelfde als bij gewone functies. Als programmeur gebruik je de functionaliteit, die het object biedt. De interne werking is een black box. Een van de voordelen van object georiënteerd programmeren (OO) is dat het zo eenvoudig is om via een nieuw object een set variabelen te creëren.

In regel 33 wordt het WAV-bestand geopend (sinus-880.wav). Regel 47 schrijft de samples in het bestand. In regel 56 worden de headers (zoals de bestandsgrootte) bijgewerkt en het bestand gesloten. Het resulterende WAV-bestand kunnen we afspelen met elke audiospeler, bijv. “paplay” (PulseAudio) of “pw-play” (Pipewire):

 $ pw-play sinus-880.wav

We horen een mooie ronde fluittoon van “a” 880 Hz. Wow! We hebben onze eigen digitale sinusoscillator gebouwd!

     1 #!/usr/bin/perl
    2
    3 # digosc-wav.pl
    4 # Digital oscillator
    5 # W20250519
    6
    7 use warnings;
    8 use strict;
    9
   10 use Audio::Wav;
   11
   12 my $f_osc= 880;              # Oscillator frequency
   13 my $fs = 48000;              # Sample frequency
   14 my $length = 4;              # Length in seconds
   15 my $N = $length * $fs;       # Number of samples
   16 my $outfile = 'sinus-'  . $f_osc . '.wav'; # Wav filename
   17 my $atten = 0.25;            # Max output volume
   18
   19 print "   f_osc: $f_oscn";
   20 print "   fs : $fsnn";
   21
   22 # Open Audio::Wav object
   23 my $bits_sample = 16;
   24 my $max_no = $atten * ( 2 ** $bits_sample ) / 2 - 1; # Signed max sample value
   25
   26 my $wav_opts = {
   27 'bits_sample' => $bits_sample,
   28 'sample_rate' => $fs,
   29 'channels' => 1,
   30 };
   31
   32 my $wav = new Audio::Wav;
   33 my $write = $wav -> write( $outfile, $wav_opts );
   34
   35 # Generate samples
   36 my $pi = 22 / 7;
   37 my $w = 2 * $pi * $f_osc;    # Angular frequency
   38 my $dw = $w / $fs;           # Angular sample step size
   39
   40 my $out = 0;                 # Oscillator output
   41 my $phi = 0;                 # Vector angle position
   42
   43 for my $n ( 0 .. $N ) {
   44
   45     $out = sin ( $phi );
   46
   47     $write -> write( $out * $max_no );
   48
   49     $phi = $phi + $dw; # Next sample
   50
   51     if ( $phi > 2 * $pi ) {
   52         $phi = $phi - 2 * $pi;
   53     }
   54 }
   55
   56 $write -> finish();


SetBfree installatie

Wanneer Jack/Pipewire correct is geconfigureerd, is het installeren van SetBfree nog maar één commandoregel:

$ sudo apt-get install setbfree

Het Debian pakket “setbfree” komt met drie uitvoeringsvormen:

  • commandline applicatie (/usr/bin/setBfree)
  • GUI-applicatie (/usr/bin/setBfreeUI)
  • LV2-plugin

De GUI-applicatie is een grafische schil bovenop de commandline applicatie. Voor zelfstandig gebruik is de GUI-applicatie de aangewezen optie. De GUI toont een compleet virtueel Hammond B3 orgel op het beeldscherm dat volledig met de muis te bedienen is. Op de klavieren kan met de muis een eenvoudige 1-vinger melodie worden gespeeld. Praktisch is dat de GUI-applicatie een visuele feedback geeft van de MIDI controls. Je kunt dus de actuele instelling van de drawbars, vibrato, etc. zien op het beeldscherm.

De commandline applicatie is een z.g. “headless” applicatie. Er is geen interactie met de gebruiker en er is geen beeldscherm nodig. De besturing vindt uitsluitend plaats via MIDI. Dit maakt de commandline applicatie uitermate geschikt voor gebruik in bijv. een Zynthian synth box. De commandline applicatie vraagt bovendien veel minder CPU power dan de GUI-applicatie! Waar de GUI-applicatie minimaal een Rasperry Pi4 nodig heeft, loopt de commandline applicatie probleemloos op een Pi3!

De derde uitvoeringsvorm, de LV2-plugin is bedoeld voor gebruik in studio software (Digital Audio Workstations), zoals MusE of Ardour. LV2 (LADSPA V2) is een open source plugin standaard, functioneel vergelijkbaar met de commerciële VST standaard.

Het SetBfree software synthesizer Hammond orgel emuleert met zijn 91 digitale oscillatoren het volledige toonbereik van de Hammond B3 van C0 (32,7Hz) t/m F#7 (5920Hz)! Merk op dat SetBfree ook keurig de “foldback” emuleert van de 16-voet op het onderste octaaf van de klavieren!

Volgende keer: MIDI


  1. https://dspguru.com/dsp/howtos/how-to-create-oscillators-in-software/