2.3.7. Prozesse

Prozesse sind in Common Music Abstraktionen zur Steuerung zeitlicher Abläufe, vergleichbar mit einem Midi-Sequencer der Midi- bzw. Klangereignisse im Zeitverlauf steuert.

In Common Music ist das process Makro der zentrale Baustein, um zeitliche Ereignisfolgen zu definieren. Dieses Makro hat eine sehr ähnliche Struktur und Syntax, wie das loop Makro von Common Lisp. Beide Makros definieren Iterationen, d.h. Wiederholungen, deren Parameter (Anzahl der Wiederholungen, Variablen, Rückgabewerte, Abbruchbedingungen, etc.) über spezielle Symbole, sogenannte 'Klauseln' definiert werden können. Diese Klauseln ermöglichen sehr mächtige und flexible Steuerungsmechanismen und bilden eine eigene, in Common Lisp eingebettete Sprache zur Beschreibung von Iterationen. Es erfordert einige Zeit, mit den Feinheiten vertraut zu werden, lohnt aber die Mühe und den Zeitaufwand des Lernens. Neben dem oben verlinkten Kapitel zu loop aus dem Sprachstandard (cltl2) gibt es in dem Kapitel Loop for Black Belts in Peter Seibel’s Buch 'Practical Common Lisp' eine sehr empfehlenswerte Einführung in das loop Makro 12:

Im process Makro von Common Music sind über die von loop bekannten Klauseln hinaus vor allem die Schlüsselwörter output und wait wichtig, da sie die Voraussetzung für die zeitlich strukturierte Ausgabe von Ereignissen bilden. output erzeugt die Ausgabe eines Ereignisses und wait bezeichnet die Zeitdifferenz zwischen den Iterationen. Die Klausel repeat gibt die Anzahl der Iterationen an.

;; Definition eines Prozesses mit zwei Midiereignissen mit 1 Sekunde Zeitabstand

(process
  repeat 2
  output (new midi)
  wait 1)

Das process Makro 'definiert' dabei lediglich den Prozess, ohne irgendwelche Ereignisse zu erzeugen. Um die Ereignisse eines Prozesses tatsächlich auszulösen, werden die Funktionen sprout oder events verwendet:

;; Verschiedene Ausgabemöglichkeiten eines Prozesses mit zwei
;; Midiereignissen mit 1 Sekunde Zeitabstand

;;; Echtzeit (rts muss zuvor gestartet worden sein):

(sprout
 (process
   repeat 2
   output (new midi)
   wait 1))

;;; Echtzeit unter Verwendung der events funktion:

(events
 (process
   repeat 2
   output (new midi)
   wait 1)
 *rts-out*)

;;; Ausgabe in eine Midi-Datei:

(events
 (process
   repeat 2
   output (new midi)
   wait 1)
 "/tmp/test.midi")

;;; Ausgabe in eine Lilypond Datei:

(events
 (process
   repeat 2
   output (new midi)
   wait 1)
 "/tmp/test.ly")

Die Klausel output hat eine ähnliche Funktionsweise, wie die oben beschriebene Funktion output, allerdings eine andere Syntax: Hinter der Klausel output muss ein Ausdruck stehen, dessen Wert ein Ereignis ist. Im Unterschied hierzu steht die Funktion output in Klammern und erwartet als 'Argument' einen Ausdruck, dessen Wert ein Ereignis ist, das ausgegeben werden kann.

Die Funktion output kann allerdings in Verbindung mit der do Klausel auch innerhalb des process Makros verwendet werden. Das nachfolgende Beispiel beschreibt den gleichen Prozess wie zuvor mit Hilfe der Klausel do und der Funktion output.

(sprout
 (process
   repeat 2
   do (output (new midi))
   wait 1))

Auch innerhalb eines process ist es möglich, die Ausgabe von output auf einen speziellen Stream/Port umzuleiten. Hierzu dient die Klausel to:

;;; Erzeugung eines incudine-streams mit 4-Kanal channel-tuning

(make-mt-stream *mt-out01* *midi-out1* '(4 0))

;;; Umleitung von output in einem process mit der Klausel "to"

(sprout
 (process
   repeat 2
   output (new midi :keynum 60.5)
   to *mt-out01*
   wait 1))

;;; Alternative Lösung mit der Funktion output, der Klausel "do" und
;;; dem Keywort :to:

(sprout
 (process
   repeat 2
   do (output (new midi :keynum 60.5) :to *mt-out01*)
   wait 1))

2.3.7.1. Prozesse als Funktionen

Die Definition von Prozessen als Funktionen ermöglicht die Abstraktion eines bestimmten formalen Ablaufs mit Hilfe eines Namens. Über Funktionsargumente lassen sich diese Abläufe parametrisieren.

Die nachfolgende Funktion definiert ein Arpeggio. Funktionsargumente sind der arpeggierte Akkord, die Anzahl von Durchläufen und die Geschwindigkeit des Arpeggios.

(defun arpeggio (chord dtime)
  (process
    for keynum in chord
    output (new midi :keynum keynum)
    wait dtime))

;; Abspielen dieses Prozesses mit sprout bzw. events:

(sprout (arpeggio '(60 66 71 77) 0.1))

2.3.7.2. Verschachtelte Prozesse

Besonders hervorzuheben ist die Möglichkeit, Prozesse als Bestandteile anderer Prozesse zu verwenden.

Das oben definierte Arpeggio lässt sich beispielsweise als Bestandteil eines Prozesses definieren, der eine wiederholte Repetition von Arpeggios erzeugt.

(defun arpeggio-repeat (chord numrepeats dtime)
  (process
    repeat numrepeats
    sprout (arpeggio chord dtime)
    wait (* (length chord) dtime)))

;; Abspielen dieses Prozesses mit sprout bzw. events:

(sprout (arpeggio-repeat '(60 66 71 77) 4 0.2))

Diese Funktion wiederum kann in einer Funktion verwendet werden, die eine rhythmisierte Akkordfolge arpeggiert.

(defun arpeggio-akkordfolge (akkordfolge wiederholungen dtime)
  (process
    for chord in akkordfolge
    for repeats in wiederholungen
    sprout (arpeggio-repeat chord repeats dtime)
    wait (* (length chord) repeats dtime)))

;; Abspielen dieses Prozesses:

(sprout
 (arpeggio-akkordfolge
  '((60 66 71 77)
    (60 65 73)
    (62 68 73 81)
    (61 69 71 74 77 83)
    (55 61 66 72 67 63 57)
    (41 43 47 51 57 63 65 71 74 80 82))
  '(4 2 3 1 1 1) 0.1))

(sprout
 (arpeggio-akkordfolge
  '((60 64 67 72 76 67 72 76)
    (60 62 69 74 77 69 74 77)
    (59 62 67 74 77 67 74 77)
    (60 64 67 72 76 67 72 76))
  '(2 2 2 2) 0.12))
12: Es sollte an dieser Stelle allerdings erwähnt werden, dass process nicht den vollen Umfang von loop implementiert. So fehlen beispielsweise die Iteration über Hash-Tables, argument-destructuring und anderes mehr.

results matching ""

    No results matching ""