Next: Tempo und Dauer , Previous: Zwei Patterns mit Verschiebung , Up: Steve Reich: Piano Phase , Home: Allgemeine Einführung

Algorithmische Komposition mit Common Lisp

Vereinfachung des Codes

Der Code des letzten Abschnitts ist etwas unübersichtlich. Er enthält viele Codeverdopplungen, da wesentliche Teile des Codes beider Klaviere gleich sind. In einer solchen Situation macht es Sinn, die wiederholten Teile des Codes zu verallgemeinern und in eine separate Funktion auszulagern, die dann für die Erzeugung der Listen beider Klaviere mit den entsprechenden Parametern aufgerufen wird. Dazu dient die folgende Funktionsdefinition collect-pno-events, die die sfz Instanzen einer Sektion in einem Klavier als Liste zurückgibt.

(defun collect-pno-events (pattern num-repeats dtime shift pan)
  (let* ((pattern-length (length pattern))
         (num-notes-no-shift (* pattern-length num-repeats))
         (num-notes-shift (+ shift num-notes-no-shift))
         (real-dtime (* dtime (/ num-notes-no-shift num-notes-shift))))
    (loop
      for i below num-notes-shift
      collect (new sfz
                :time (* i real-dtime)
                :keynum (elt pattern (mod i pattern-length))
                :duration dtime
                :amplitude -6
                :preset :yamaha-grand-piano
                :pan pan))))

Die Funktion erhält als Parameter das Pattern in Form einer Liste von MIDInoten, die Anzahl von Wiederholungen, den Rhythmus bezogen auf das Grundtempo, die Verschiebung am Ende der Wiederholungen in 1/16 Noten und den Wert für das Stereopanorama (0=links, 1=rechts).

Im let​* Ausdruck werden zunächst die Werte für die Länge des Patterns (pattern-length), die Anzahl der gespielten Noten (num-notes-shift) und den Rhythmus (real-dtime) während des Abschnitts errechnet.

Der loop Ausdruck ist dann sehr einfach: Er erzeugt sämtliche Instanzen von sfz Ereignissen mit den errechneten Parametern und gibt sie in einer Liste zurück.

Damit reduziert sich der Code für den Abschnitt des letzten Kapitels auf 4 Zeilen:

(sprout
 (append
  (collect-pno-events '(64 66 71 73 74 66 64 73 71 66 74 73) 10 0.139 0 0)
  (collect-pno-events '(64 66 71 73 74 66 64 73 71 66 74 73) 10 0.139 1 1)))

Auch hier gibt es Verdopplungen bei den Patterns, der Anzahl Wiederholungen und der dtime. Eine weitere Vereinfachung fasst beide Klaviere zusammen:

(defun collect-section-events (pattern num-repeats dtime shifts)
       (loop
         for shift in shifts
         for pan from 0 by (/ 1 (1- (length shifts)))
         append (collect-pno-events pattern num-repeats dtime shift pan)))

Der Parameter shift der Funktion collect-pno-events ist nun verändert durch den Parameter shifts, eine Liste von Shift Werten für die zwei Pianos. Der Wert für das Stereopanorama wird im loop Ausdruck der Funktion so berechnet, dass für eine beliebige Anzahl von shift Werten die Panorama die Werte von 0 bis 1 gehen. Insofern wäre es möglich, diese Funktion für mehr, als zwei Klaviere zu verwenden.

Damit wird der Aufruf für eine Sektion auf folgenden Ausdruck reduziert:

(sprout (collect-section-events '(64 66 71 73 74 66 64 73 71 66 74 73) 10 0.139 '(0 1)))