Like Common Music and SmOKe, Score’s internal design is backend agnostic. This means that the representation of data is not tied to a single target music system. Users can use mapping functions to convert note lists generated by Score into a format that works with another system. This may be for use with other computer music systems but may also be used for visualisation or other purposes.
The following shows an example use of Score and Csound. It uses the
gen-notes2 function to generate a note list from time 0 to 5.0 using 5 fields. The first field is a constant field that will always generate 1. The rest of the p-fields of the Csound score is generated using the values provided by within the
(def notes (gen-notes2 0 5.0 1 (gauss 0.5 0.1) (heap [0.1 0.2 0.4]) (rand-range 0.1 0.25) (rand-item ["8.00" "8.03" "8.02"]))) (def csound-sco (format-sco notes)) (println notes) (println csound-sco)
The results of printing the output are shown below:
;; output from (println notes) [[1 0.0 0.1 0.1455446063675899 8.02] [1 0.07388877495229043 0.2 0.11487888605849467 8.00] [1 0.2684591839186033 0.4 0.12170487899979296 8.00] [1 1.0558572506209922 0.4 0.13304255988624555 8.03] [1 1.554791683668857 0.2 0.16436113185377213 8.00] [1 1.9392915161730429 0.1 0.11907587313489418 8.02] [1 2.3410899943560195 0.2 0.21996317376289015 8.03] [1 2.787924993057282 0.4 0.2119026696996974 8.00] [1 3.7580 770774079575 0.1 0.12327608647786711 8.00] [1 4.199933807980773 0.2 0.23620482696864334 8.00]] ;; output from (println csound-sco) i1 0.0 0.1 0.1455446063675899 8.02 i1 0.07388877495229043 0.2 0.11487888605849467 8.00 i1 0.2684591839186033 0.4 0.12170487899979296 8.00 i1 1.0558572506209922 0.4 0.13304255988624555 8.03 i1 1.554791683668857 0.2 0.16436113185377213 8.00 i1 1.9392915161730429 0.1 0.11907587313489418 8.02 i1 2.3410899943560195 0.2 0.21996317376289015 8.03 i1 2.787924993057282 0.4 0.2119026696996974 8.00 i1 3.7580770774079575 0.1 0.12327608647786711 8.00 i1 4.199933807980773 0.2 0.23620482696864334 8.00
The first printout shows the results of running
gen-notes2, which produces a Clojure list of lists. The second printout shows the result of using the
format-sco function, provided by Score for formatting note lists into Csound SCO text format. The
csound-sco text may then be further sent to a running Csound instance for live score performance or written to disk and later read by Csound as a SCO file.
At this time, Score only provides output mapping for Csound. However, Score’s generated note lists are usable as-is with Pink, as both systems are written in Clojure. In track1.clj,
growing-line defines a note list using both features from Score and Pink. The code first uses two note lists generated using the
gen-notes function that are concatenated together. This is then mapped over and the
growl audio function is prepended as the first field of each note in the note list. The
e argument given to
gen-notes is itself a Pink audio function – the
env function – that is wrapped using the
!*! operator. The result is that for each note, the 6th field will be an instance of
env used as the amplitude argument to the
;; from music-examples.track1 example file (def growing-line (let [e (!*! env [0.0 400 0.11 5000]) starts (range 0 1.8 (/ 1.0 3.0)) amps (range 0.05 5 0.05) space (range 0.75 -1.0 -0.25)] (map #(into [growl] %) (concat (gen-notes starts 0.1 :G5 amps e 0.75 space) (gen-notes starts 0.1 :G3 amps e 0.75 space) ))))
From here, the
growing-line note list is then reused as a part of a larger measured-score.
convert-measured-score is used to prodcue to the total score, which is then mapped into Pink events using the
sco->events function provided in the
(defn apply-afunc-with-dur "Applies an afunc to given args within the context of a given duration. with-duration will bind the value of dur to the *duration* Pink context variable." [afunc dur & args] (with-duration (double dur) (apply!*! afunc args))) (defn i "Csound style note events: audio-func, start, dur, & args." [afunc start dur & args] (apply event apply-afunc-with-dur start afunc dur args)) (defn sco->events "Converts Csound-style note list into a list of Pink Events." [notes] (map #(apply i %) notes))
The above shows the code for
sco->events. Given a list of notes,
sco->event maps an anonymous function that applies the
i function to the values found in each note. The
i function in turn applies the
event function to each note, using
apply-afunc-with-dur as the event’s function – the one that will fired by Pink’s event processor – with the given arguments. Finally, when
apply-afunc-with-dur is called, it fires by processing the values found in the original note, applying the first field – the audio function – to the rest of the fields.
In the full track1.clj example, these Pink events are further passed to the
add-audio-events function from
pink.simple. This is a convenience function that wraps events with another event that uses the
add-afunc function to attach audio functions to the root node of the engine. At runtime, when an event is fired, the nested event will generate an audio function and the top-level event will add it to the engine for processing.
The mapping of note lists is the technique by which the generated data from Score is connected to other systems. Score currently provides a mapping function for Csound and works out of the box with Pink, as shown in the example code. In the future, more mappings could be provided with Score, such as MIDI, OSC, and MusicXML. As the data generated from Score is plain Clojure list data, users can create their own mappings relatively simply.