Jump to content

Klangreihen Study


Recommended Posts

Here is my study about the klangreihen: 

 

(defparameter tempo 60)
(defparameter title "Klangreihen Study")


;;; This object takes care of setting and getting of parts

(defclass study-score () 
  ((instruments
    :initarg :instruments
    :initform 0)

   (duration
    :initarg :duration
    :initform 0)

   (parts)))


;;; When initializing, fill it with an empty model for parts (array of size N)

(defmethod initialize-instance :after ((score study-score) &key)
  (let ((instruments (slot-value score 'instruments )))

      (setf (slot-value score 'parts) 
            (make-array instruments 
                        :initial-element '(-w)'
                        :fill-pointer instruments))))

;;; Getter and setter methods

(defun get-part (score n)
  (elt (slot-value score 'parts) n ))

(defun (setf part) (part score n) 
  (let ((previous-value (elt (slot-value score 'parts) n)))
    (setf (elt (slot-value score 'parts) n) (concatenate 'list previous-value part))))



;;; Instance of the object

(defparameter study (make-instance 'study-score
                        :instruments 16
                        :duration tempo))


;;; Main procedure

(let* ;; Main local variables

    ((12tone '(0 2 4 5 7 9 6 8 10 11 1 3))
     (variants (list (row-variant 0 'r4 12tone)
                     (row-variant 0 '4 12tone)))
     
     (total-parts (slot-value study 'instruments))
     
     (bases (apply #'append (map 'list #'(lambda (v) (klangreihen 0 '(3 3 3 3) v)) variants)))
     (lengths 
      (subseq (gen-divide total-parts
                          (gen-length (distributive-cube (interference2 '(3 2 2))) 16))
              0 (length bases))))
  
  (loop
    for base in bases
    for length in lengths


    do (labels ;; Local transformative functions 
           
           ((amount-of (n) (/ 1 (nth n length)))
            
            (vel-scale (v) (+ 0.2 (* 0.6 v) ))
            (vel-format (v) (get-velocity (list v) :type :symbol))
            (velocity-for (n) (vel-format (vel-scale (/ (amount-of n) 16))))
            
            
            (length-for (n) (list (nth n length )))
            
            (octave-of (n) 
              (let ((low-bound (- 12 (* 12 (round (* (/ 1 total-parts) n 3.4)    )))))
                (list low-bound (+ low-bound 12))))             
            (pitch-for (n) 
              (let* ((rolled (gen-surround base :size (amount-of n) :start n)))
                (ambitus (octave-of n) rolled))))
        
         
         (loop 
           for n from 0 to (- total-parts 1)

           do (destructuring-bind 
                  (&key length pitch velocity)
                  
                  ;; Example of handling on a case-by-case basis. No extra cases configured now.
                  (case n
                    (otherwise
                     (list 
                      :length (length-for n)
                      :velocity (velocity-for n)
                      :pitch (pitch-for n)
                      )))
                
                (setf (part study n) (make-omn :length length :pitch pitch :velocity velocity :span :pitch)))))))


;;; Retrieve parts and save score

(let ((partnum -1)) 
  (def-score Study 
             (:title title
                     :composer "A. Jacomet"
                     :key-signature 'atonal
                     :time-signature '(4 4)
                     :tempo tempo
                     :layout 
                     (string-ensemble-layout 
                      '(vn11 vn12 vn13 vn14 vn21 vn22 vn23 vn24) 
                      '(vla1 vla2 vla3 vla4) 
                      '(vlc1 vlc2) 
                      '(ctb1 ctb2)))
  (vn11
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 1) 
  (vn12
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 2)
  (vn13
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 3) 
  (vn14
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 4)
  (vn21
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 5)
  (vn22
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 6)
  (vn23
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 7) 
  (vn24
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 8)
  (vla1
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 9)
  (vla2
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 11)
  (vla3
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 12)
  (vla4
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 13)
  (vlc1
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 14)
  (vlc2
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 14)
  (ctb1
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 15)
  (ctb2
   :omn (get-part study (incf partnum))
   :sound 'gm
   :program 'Acoustic-Grand-Piano :channel 15)))


(live-coding-midi (compile-score 'Study))
(display-musicxml 'Study)

;;;---------------------------------------------------------
;;; ANNOTATION
;;;---------------------------------------------------------
#!

This study is about the LISP languages and the possibilities
of working with object oriented programming and loops. 

The first important part of this study is the 'study-score' 
class defined at the top of the file.

(defclass study-score () 
  ((instruments
    :initarg :instruments
    :initform 0)

   (duration
    :initarg :duration
    :initform 0)

   (parts)))

On initialization, that object will create and save in one
of it's properties, a model of the parts, which is an array
of lists. 


(defmethod initialize-instance :after ((score study-score) &key)
  (let ((instruments (slot-value score 'instruments )))

      (setf (slot-value score 'parts) 
            (make-array instruments 
                        :initial-element '(-w)'
                        :fill-pointer instruments))))


It is important to note that this can be extended to an
N-dimensional array supporting Parts, Pitches, Velocities, 
Lengths, and more information. 

We then define trivial functions that are intended to help 
in adding and retrieving parts.


(defun get-part (score n)
  (elt (slot-value score 'parts) n ))

(defun (setf part) (part score n) 
  (let ((previous-value (elt (slot-value score 'parts) n)))
    (setf (elt (slot-value score 'parts) n) (concatenate 'list previous-value part))))


This will eventually help keep our program free of code
redundancy, and we can adapt the parts in any way we like 
in a global way. 

The rest is a simple example of utilizing a klangreihen base
and looping over it. The loop starts with a LET clause that
sets all the basic parameters:


(let* ;; Main local variables

    ((12tone '(0 2 4 5 7 9 6 8 10 11 1 3))
     (variants (list (row-variant 0 'r4 12tone)
                     (row-variant 0 '4 12tone)))
     
     (total-parts (slot-value study 'instruments))
     
     (bases (apply #'append (map 'list #'(lambda (v) (klangreihen 0 '(3 3 3 3) v)) variants)))
     (lengths 
      (subseq (gen-divide total-parts
                          (gen-length (distributive-cube (interference2 '(3 2 2))) 16))
              0 (length bases)))) 

  ..... )


Looping over these global parameters, we start to build our
theme sequentially, making all parts for each base. 

(loop
    for base in bases
    for length in lengths


    do (labels 
           
           ... ))


The LABELS special operator allows us to define local functions
for our loop body, that will be helpful in transforming the data.
Within it's function body, we have the actual loop that loops
over the parts:

(loop 
           for n from 0 to (- total-parts 1)
  ...)

The DESTRUCTURING-BIND macro allows us to keep our syntax clean
and succint, because we can handle different cases using CASE,
while setting Length, Velocity and Pitch, and then in a single
line, retrieve those values and use them to set that particular
omn in the parts array: 

(destructuring-bind 
    (&key length pitch velocity)
    
    ;; Example of handling on a case-by-case basis. No extra cases configured now.
    (case n
      (otherwise
       (list 
        :length (length-for n)
        :velocity (velocity-for n)
        :pitch (pitch-for n)
        )))
  
  (setf (part study n) (make-omn 
                        :length length 
                        :pitch pitch 
                        :velocity velocity 
                        :span :pitch)))


!#

 

Link to comment
Share on other sites

Impressive study and great score!

I see you have found your own way to create the score dynamically.

I am sure many OPMO users will love to study the score and the technique.

 

This score would be great with annotation.

I like how you use the Schillinger interference functions to generate the length series.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

Terms of Use Privacy Policy