Lisp, functies, macros en expressieve code

Development Consulting Articles

News

Ik ben jaren geleden al eens begonnen aan een Perl module om (onder andere) modulaire synthesizers te emuleren. En dat werkte wel, maar mooi was het niet:

Maak wat processors….

    my $net = Audio::LADSPA::Network->new();
    my $sine = $net->add_plugin( label => 'sine_fcac' );
    my $delay = $net->add_plugin( label => 'delay_5s' );
    my $play = $net->add_plugin('Audio::LADSPA::Plugin::Play');

verbind ze met mekaar en zet parameters…

    $net->connect($sine,'Output',$delay,'Input');
    $net->connect($delay,'Output',$play,'Input');
    
    $sine->set('Frequency (Hz)' => 440); # set freq
    $sine->set(Amplitude => 1);   # set amp

    $delay->set('Delay (Seconds)' => 1); # 1 sec delay
    $delay->set('Dry/Wet Balance' => 0.2); # balance - 0.2

en draaien maar!

    for ( 0 .. 100 ) {
        $net->run(100);
    }

Allemaal leuk, maar veel te veel typ werk en behoorlijk complex.

Op vakantie heb ik laatst Practical Common Lisp doorgelezen en dan ga je natuurlijk denken dat dat beter kan als je functies gebruikt ipv complexe objecten en dat het er in Lisp veel beter uit kan zien.

Dat is dus ook zo :-)

; ik ga hier processors gebruiken
(with-processors
    ; maak een paar processors
    ((sine (sine-processor))   
     (delay (delay-processor))
     (m (stream-mixer))
     (mlt (stream-mult)))
  (with-audio-stream stream 0 1 ()  ; gebruik 1 audio output
    (dotimes (i 400)
      (write-audio stream
                   (

Ik gebruik

(<- ... )

als een macro die de juiste output van een processor selecteerd:
:output bij default, anders scrijf je

(

En definieren van een processor is ook erg versimpeld:

(defprocessor mult-processor
    ((output :stream)) 
    ((input :stream) (factor :scalar))
    ()
  (dotimes (i *num-frames*)
    (setf (aref output i) (* (aref input i) factor))))