2.3.5. Ausgabefunktionen
Common Musik stellt verschiedene Formen für die Ausgabe von Ereignissen bereit.
2.3.5.1. output
Die direkteste Form wird durch die Funktion output
bereitgestellt. output
gibt immer genau ein Ereignis aus, das der Funktion als Argument übergeben werden muss. Wird die Funktion im 'top-level' evaluiert, wird der :time
Slot des Ereignisses von der Funktion ignoriert und das Ereignis direkt ausgegeben. Über das Keywort :to
besteht die Möglichkeit, den output-stream zu spezifizieren. Wenn das Keywort :to
nicht verwendet wird, erfolgt die Ausgabe auf den Stream, der an das Symbol *rts-out*
gebunden ist.
Zusätzlich besteht die Möglichkeit, die Ausgabe mit dem Keywort :at
zu verzögern. Der Wert von at wird in Sekunden angegeben, die auf den Moment, an dem der Ausdruck evaluiert wird, bezogen sind. Negative Werte für :at
sollten vermieden werden.
;; realtime output einer Note: (output (new midi)) (output (new midi :keynum 62 :duration 4)) (output (new midi :keynum (+ 48 (random 24)) :duration 4)) ;; Ausgabe 1 Sekunde nach Auswertung: (output (new midi) :at 1) (* 3 4 5) ;;; -> 60 (sprout (process repeat 10 output (new midi :time (now)) wait 0.2))
Sollen mehrere Ereignisse ausgegeben werden, ist es möglich, mehrere Aufrufen von output
mit der special form progn
zu einem Block zusammenzufassen. Sämtliche output
Ausdrücke in dem progn
Block werden dabei simultan ausgeführt. Rhythmen lassen sich durch die Verwendung des Keyworts :at
realisieren:
;; Ausgabe eines simultanen Durdreiklangs mit output: (progn (output (new midi :keynum 60)) (output (new midi :keynum 64)) (output (new midi :keynum 67))) ;; Ausgabe eines Arpeggios mit output: (progn (output (new midi :keynum 60)) (output (new midi :keynum 71) :at 0.5) (output (new midi :keynum 66) :at 2))
2.3.5.2. sprout
Eine allgemeinere Form der Ausgabe stellt die Funktion sprout
bereit. sprout
kann sowohl einzelne Ereignisse, als auch eine Liste von Ereignissen oder einen Prozess (siehe nächstes Kapitel) ausgeben. Wenn sprout ein einzelnes Ereignis oder eine Liste von Ereignissen ausgeben soll, ist darauf zu achten, dass der :time
Slot der auszugebenden Ereignisse gesetzt sein muss. Auch der Wert dieses Slots bezieht sich auf den Moment der Auswertung des Ausdrucks.
(sprout (new midi :time 0)) ;;; Ausgabe 1 Sekunde nach Auswertung: (sprout (new midi :time 1))
Wenn sprout
im 'top-level' evaluiert wird, erfolgt die Ausgabe, wie bei output
unmittelbar in Echtzeit. Auch bei sprout
ist es möglich, den Ausführungszeitpunkt durch das Keywort :at
zu beeinflussen. Hier ist allerdings darauf zu achten, dass der Wert von :at
nicht relativ zum Auswertungszeitpunkt, sondern in absoluter Zeit seit Start der Echtzeitverarbeitung angegeben werden muss. Den aktuellen Wert der absoluten Zeit kann man mit der Funktion (now)
ermitteln. Auf diese Weise lässt sich eine relative Verzögerung folgendermaßen darstellen:
;;; Ausgabe 1 Sekunde nach Evaluation: (sprout (new midi :time 0) :at (+ 1 (now))) ;;; Kombination von :time und :at ;;; Ausgabe 2 Sekunden nach Evaluation: (sprout (new midi :time 1) :at (+ 1 (now)))
Wenn mehrere Ereignisse ausgegeben werden sollen, können die Ereignisse in Form einer Liste an sprout
übergeben werden:
;; Ausgabe eines simultanen Durdreiklangs mit sprout: (sprout (list (new midi :keynum 60 :time 0) (new midi :keynum 64 :time 0) (new midi :keynum 67 :time 0))) ;; Ausgabe eines Arpeggios mit sprout: (sprout (list (new midi :keynum 60 :time 0) (new midi :keynum 71 :time 0.5) (new midi :keynum 66 :time 2)))
2.3.5.3. events
events
ist eine Form der Ausgabe von Ereignissen, die in Common Music implementiert wurde, bevor die Echtzeitausgabe von Ereignissen mit Computern möglich war.
Ähnlich, wie bei sprout
ist es mit der events
Funktion möglich, einzelne Ereignisse, Listen von Ereignissen, Prozesse oder andere cm Typen, wie <sequence> auszugeben. Auch bei der Ausgabe durch events
muss bei allen auszugebenden Ereignissen der :time
Slot gesetzt sein.
Als drittes Argument wird der events
Funktion das Ziel (englisch 'destination') übergeben.
Wenn dieses Argument eine Zeichenkette (englisch 'string') ist, wird diese als Dateiname interpretiert und die Ereignisse in eine Datei ausgegeben, deren Typ sich nach der Endung des Dateinamens richtet. Die wichtigsten Endungen sind in der nachfolgenden Tabelle aufgeführt
Dateinamenendung | Typ der Ausgabedatei |
---|---|
".midi", ".mid" | MIDI-Datei |
".ly" | Lilypond Datei |
".cmn" | CMN Datei |
".clm" | CLM Datei |
".aiff", ".snd", ".wav" | CLM Audiodatei |
Je nach Ausgabeformat existieren Zusatzoptionen, zur genaueren Steuerung des Ausgabeformats, die der events
Funktion mit Hilfe von Keywortargumenten übergeben werden. Eine Auflistung der Optionen findet sich im Common Music Dictionary unter midi-file, fomus-file, cmn-file, clm-file und audio-file.
Wenn anstelle einer Zeichenkette ein <incudine-stream> angegeben wird, so werden die Ereignisse ähnlich wie bei sprout
auf die Echtzeitausgänge geleitet.
Wird das dritte Argument ausgelassen, wird das Ausgabeformat des letzten Aufrufs der events
Funktion verwendet.
;;; Ausgabe in die Midi Datei "/tmp/test.midi": (events (list (new midi :keynum 60 :time 0) (new midi :keynum 62 :time 0.5) (new midi :keynum 64 :time 1)) "/tmp/test.midi") ;; realtime output einer Note mit der events Funktion: (events (new midi :time 0) *rts-out*) ;; wird das zweite Argument weggelassen, wird die zuletzt verwendete ;; Ausgabemethode benutzt: (events (new midi :time 0))
Der Unterschied zwischen events
und sprout
besteht darin, dass events
direkt bei Auswertung sämtliche Ereignisse generiert und dem Echtzeitscheduler mit den entsprechenden Zeitinformationen übergibt, während im Falle von sprout
ein process
nur das jeweils nächste Element generiert und sich über den scheduler zeitverzögert wiederholt aufruft, bis der Prozess beendet ist. Solch eine Form der schrittweisen, sukzessiven Auswertung erst zu dem Zeitpunkt, an dem ein neues Element benötigt wird, ist eine Programmiertechnik, die unter dem Begriff 'Lazy Evaluation' bekannt ist. Ein Vorteil dieser Technik besteht darin, dass man einen Prozess definieren und starten kann, der prinzipiell unendlich ist. Von aussen kontrolliert werden solche Prozesse dann durch das Setzen einer globalen Variable, die vom Prozess zur Ausführungszeit überprüft wird, und über die er sich, wenn sie gesetzt ist, selbst stoppt.
Für solche eine Methode kann events
nicht eingesetzt werden, da ein solcher Prozess sofort einen Überlauf erzeugt, da unendlich viele Werte unmittelbar generiert werden müssten.
Um in eine Lilypond Datei zu exportieren, muss zuvor das Paket "cm-fomus" geladen worden sein.
;;; Ausgabe in eine Lilypond Datei: (ql:quickload "cm-fomus") (events (list (new midi :keynum 60 :time 0) (new midi :keynum 62 :time 0.5) (new midi :keynum 64 :time 1)) "/tmp/test.ly")
Nach Evaluation des obenstehenden Ausdrucks sollte sich die Datei "test.ly" im Ordner "/tmp" befinden. Sie lässt sich anschließend mit dem Programm lilypond setzen und ergibt die untenstehende Notengrafik.