Skip to content

how do I output to Csound or some other system?

Michael Edwards edited this page Jun 1, 2024 · 1 revision

Csound (by Ruben Philipp)

As of March 2023, slippery chicken is capable of generating Csound scores and rendering sound files via the methods write-csound-score and csound-play. The following example should provide a quick overview of how to incorporate sound synthesis using Csound. More thorough explanation and insights are to be found in the code documentation.

(let ((mini
        (make-slippery-chicken
         '+mini+
         :ensemble '(((pno (piano :midi-channel 1))
                      (vln (violin :midi-channel 2))))
         :set-palette '((1 ((f3 g3 as3 a3 bf3 b3 c4 d4 e4 f4 g4 a4 bf4 cs5))))
         :set-map '((1 (1 1 1 1 1 1 1))
                    (2 (1 1 1 1 1 1 1))
                    (3 (1 1 1 1 1 1 1)))
         :tempo-map '((1 (q 60)))
         :rthm-seq-palette '((1 ((((4 4) h (q) e (s) s))
                                 :pitch-seq-palette ((1 (2) 3))))
                             (2 ((((4 4) (q) e (s) s h))
                                 :pitch-seq-palette ((1 2 3))))
                             (3 ((((4 4) e (s) s h (q)))
                                 :pitch-seq-palette ((2 3 3))))
                             (4 ((((4 4) (s) s h (q) e))
                                 :pitch-seq-palette ((3 1 (2))))))
         :rthm-seq-map '((1 ((pno (1 2 1 2 1 2 1))
                             (vln (1 2 1 2 1 2 1))))
                         (2 ((pno (3 4 3 4 3 4 3))
                             (vln (3 4 3 4 3 4 3))))
                         (3 ((pno (1 2 1 2 1 2 1))
                             (vln (1 2 1 2 1 2 1))))))))
  (csound-play mini
               '(pno vln)
               '(1 2)
               "mini-orchestra.orc"
               :comments nil))
                   

This basic example assumes you have a Csound orchestra file (mini-orchestra.orc) prepared which includes two instrument definitions (instr 1 and 2) interpreting p4 as frequency and p5 as amplitude. However, it is possible to implement custom value allocations and assignments via the :p-fields argument csound-play respectively write-csound-score, illustrated as follows.

(defun csound-p-fields-custom (event event-num cs-instrument)
  (case cs-instrument
    (1 (csound-p-fields-simple event
                               event-num
                               cs-instrument))
    (2 (let* ((amplitude (get-amplitude event))
              ;; num of available samples in Csound
              ;; instrument definition / orchestra
              (num-samples 10)
              ;; get the id of the sample to be played
              ;; for this event
              (current-sample (1+ (mod (1- event-num)
                                       num-samples))))
         (list current-sample
               amplitude)))))
    
(let* ((mini
         (make-slippery-chicken
          '+mini+
          :ensemble '(((vln (violin :midi-channel 1))
                       (vlc (cello :midi-channel 2))))
          :tempo-map '((1 (q 60)))
          :set-palette '((1 ((f3 g3 a3 b3 c4 d4 e4 f4 g4 a4 b4 c5)))
                         (2 ((f3 g3 a3 b3 c4 d4 e4 f4 g4 a4 b4 c5)))
                         (3 ((f3 g3 a3 b3 c4 d4 e4 f4 g4 a4 b4 c5))))
          :set-map '((1 (1 1 1 1 1))
                     (2 (2 2 2 2 2))
                     (3 (3 3 3 3 3)))
          :rthm-seq-palette '((1 ((((4 4) h q e s s))
                                  :pitch-seq-palette ((1 2 3 4 5))))
                              (2 ((((4 4) q e s s h))
                                  :pitch-seq-palette ((1 2 3 4 5))))
                              (3 ((((4 4) e s s h q))
                                  :pitch-seq-palette ((1 2 3 4 5)))))
          :rthm-seq-map '((1 ((vln (1 3 2 1 2))
                              (vlc (3 1 1 2 2))))
                          (2 ((vln (3 1 1 2 2))
                              (vlc (1 3 1 2 2))))
                          (3 ((vln (1 1 3 2 2))
                              (vlc (2 1 1 2 3))))))))
  (write-csound-score mini
                      '(vln vlc)
                      '(1 2)
                      :chords nil
                      :delimiter #\tab
                      :p-fields #'csound-p-fields-custom
                      :comments t))

Here, a custom function – csound-p-fields-custom – is defined. This renders different p-field-sets for each player. Player vln is associated with the (hypothetical) Csound instrument 1, which generates – just as in the former example – a tone of pitch p4 and amplitude p5. Again, player vlc calls the Csound instrument 2, which might be a simple sampler capable of playing one out of ten pre-loaded sound files. These are identified by an index (1 <= i <= 10) which is expected to be p4. p5 determines the amplitude of the playback. The samples, in this example, will be selected cyclically, while each event of the player is allocated one of the ten available samples. As there is one sound file per event, chords will be treated as pitches, i.e. every chord results in a list instead of a list of lists of p-fields.

If you encounter any inconvenience or would like to come up with suggestions for improvement, feel free to create an issue, write some code or reach out to ruben.philipp@folkwang-uni.de.

Other systems

Besides being able to deal with Csound-scores (see above), slippery chicken generates scores in CMN, Lilypond, Music XML, and antescofo; it writes MIDI files and sound files; but this is not everything of course. Some of you might want to output to other text based file formats. In this case, after generating your slippery-chicken object (e.g. via make-slippery-chicken) you can interrogate the slots of the event objects. The structure of a slippery-chicken object is pretty complex but an easy way to access events is to sort by time all the events of a piece (i.e. for every instrument) then loop through them, access the slots you need, and write the necessary data in the required format:

(loop for e in (get-events-sorted-by-time slippery-object) do
     (format t "~&~a ~a" (start-time e) (frequency (pitch-or-chord e)))))

An extension would be to write to a file instead of the Lisp window by using the with-open-file Lisp macro.

Clone this wiki locally