All posts by Owen Green

Owen 's Symposium Reflections

DiskClav

Things That Came Up

The topics that seemed to stand out during Saturday’s discussions were (i) the interoperability of Slippery Chicken with Other Things and (possibly related) (ii) more gentle ways in to the system for the New of Lisp. There was some discussion of things like porting and GUIs, but I don’t have much to say about them.

Interoperability seems to be a straightforwardly desirable thing. Dan’s been working on communication with OpenMusic. Meanwhile, though, things like reading in MIDI files and making the OSC facilities more apparent would open up all sorts of possibilities.

There were lots of useful ideas about how to augment the existing docs. Adam, for instance, has a number of cunning thoughts on what could be done with a wiki to develop more basic examples for n00bs and to point people towards Lisp resources.

One thought is also that, because this is Lisp, a compact domain specific language could be implemented on top of SC that allows for more terse (and less intimidating) expression of basic functionality.

I certainly began to get a firmer grasp on both the design of the system and what standard usage might look like as a result of these discussions. Compared with my starting point a couple of months ago, I’ve got a much firmer understanding of what SC is for and, crucially, how to interrogate the existing code base to find out what it can do.

What Did I Do?

My entry in to all this had been starting to implement some of Joseph Schillinger’s basic techniques in Lisp as part of the ground work for a project with Sileni, my improv/hip-hop/doomnoise group:
Codex Teuthis by Sileni

Part of what I was looking for was a better way of chucking around rhythms and of working out larger scale structures. Schillinger’s techniques have the attraction of being both simple and quite productive (see Arden, J. (2011). Old Tricks New Media: Schillinger Techniques are Relevant to All Kinds of Contemporary Music Irrespective of Style. Contemporary Music Review, 30(2) for an overview).

The outcome of this first burst of work was that I produced a fair amount of code that works with lists of durations and intervals in quite a flexible way, but that still needed some wrangling if they were to slot in with Slippery Chicken’s core functionality. Whilst the original idea had been just to use some of SC’s more peripheral features to help with things like MIDI output, I ended up doing quite a bit of interfacing work between my stuff and SC in order to take advantage of the pitch selection functions and quick large-scale structuring.

The piece itself uses Schillinger’s technique of interference patterns (or ‘resultants’) for much of the initial material, for instance:

  • The basic rhythmic cells (‘rthm-seqs’)
  • The pitch sets (by producing variations and extensions of basic three-note scales)
  • The pitch selection curves (using JS’s ideas about melody as a combination of directional axes and intervals)
  • Patterns of accents and rests

I produced a set of basic 40-unit rhythmic cells, as two bars of semiquavers in 5 /4, and produced a structure for the piece spread over five independent parts for the piano. My first pitch selection curves were pretty arbitrary but got the job done in terms of producing a starting block of three-ish minutes with which to work.

The main musical problem to contend with at this point was how to relieve the monotony of the results. My seeding rhythms had no rests, so when a voice was in for a section, is was going all the time. I ended up implementing three different passes of post-generation code to turn selected notes to rests, first to everything and then in a more targeted way to particular voices at particular times.

It was then that I returned to my pitch curves to try and widen the range of notes that SC was selecting. I felt that my exciting scales should be yielding richer results; part of the problem was that I hadn’t thought very deeply about how my instrument limits for the various voices related to what was available in the sets (especially for sparser variations of the scales), but also that the curves themselves had little variety (in some cases they where just binomial oscillations because I hadn’t thought through my original code). The second try yielded much more satisfying results, although more attention here would certainly develop the piece more.

The final things I had time for before performance were massaging the dynamics to make things less robotic, and putting in short drops to half-time in the middle / end of certain bars to vary the pace a bit. This latter thing seemed like a simple undertaking at first, rather than re-scoring the bars in question to have, e.g., an extra beat. However, it turned out to be a slightly fiddly thing to do in the end as I hadn’t left myself the time to make a nice tidy abstraction and instead have a lot of quite repetitive (and therefore breakable) code.

How Do I Feel About My Piece?

S’alright. It certainly feels considerably more like music than the ‘raw’ output from make-slippery-chicken did, but still could benefit from some sculpting, especially in the middle where things drag a wee bit. Moreover, I could ease up on the aggressive stripping out of material in places and let it burst forth a bit more. If I were really going to town then I’d cook up some new contrasting materials (and perhaps condense the existing pool a bit) and develop a structure with some stronger contrasts. Something I didn’t get around to coding was to force some all-voice pauses in to the flow to break it up a bit.

And About Slippery Chicken?

I hadn’t imagined going in that I would have much use for the full make-slippery-chicken approach when it comes to the Sileni project. However, now that I feel like I can exercise a bit more agency on its behaviour, the possibilities seem richer. More generally – treating SC as more of a library of useful functionality for musical purposes – there’s a great deal of really valuable stuff there that I’ll certainly be using, although some of it needs to be dug for.

I plan to keep on developing Lisp implementations of Schillinger stuff, and to make sure that there’s ways of slotting this in to SC. If I make any sort of serious dent on the 1200+ of Schillinger’s System of Musical Composition then that will be a lot of material, that I should probably document as a separate project, given the possible wider interest and application to beat making.

Post Generation Event-By-Event Processing

A helper function for processing events post-processing (e.g. for setting dynamics)

 
;; Process a set of events over pattern  with function
;; pattern is a list of durations (events to skip over), which will be looped over the returned events
;; provided function should take event as argument (so if you need player etc., figure it out)
(defun process-events (sc player pattern  function &optional (attacks t) (start-bar 1)  (end-bar nil))
  (next-event sc player attacks start-bar);initialise slurping
  (loop
     for ne = (next-event sc player attacks nil end-bar)
     while ne
     for i from 0
     with patt-pointer = 0
     with next-e = (nth patt-pointer pattern)
     do
       (when (equalp i next-e)
	 (funcall function ne)
	 (setf patt-pointer (mod (1+ patt-pointer) (length pattern)))
	 (incf next-e (nth patt-pointer pattern)))))

The point of the pattern thing is that I can use it to apply arbitrarily complex patterns on which events to select for the given player, e.g.

 
 (loop for ins in '(p1 p2 p3 p4 p5)
     for patt in '((5) (15 10) (10 5 10) (5 10 10) (5 20))
     do (process-events opus ins patt 
			#'(lambda (ne) (setf (amplitude ne) (min 1 (* 2 (amplitude ne))))) nil))

Which will select every 5th event in p1, every 5th then every 10th (then the next 5th etc.) for p2, and so on.

rthm-seq-bar::get-nth-event: index = -1!

I’m having weirdness with sc-force-rest2, which throws the error above when I call it from this loop

 (loop
    ;;get instruments
    for ins in '(p1 p2 p3 p4 p5)
    ;;different numbers of cycles over activity curve for each part
    for cycles in '(1 2 13 2 15)
    ;;get total notes for scaling activity curve
    for notes =  (total-notes (get-data ins (ensemble opus)))
     do
       (next-event opus ins t 1);start slurping events
       (loop
	  for ne = (next-event opus ins t)
	  for i from 1
	  ;;scaled activity envelope 
	  with  activity = (make-ale (genal) (floor notes cycles))
	  while ne
	  do 
	    (when (not (active activity))
	      (sc-force-rest2 opus (bar-num ne) (bar-pos ne) ins)))))

Backtrace:
0: ((:METHOD GET-NTH-EVENT (T RTHM-SEQ-BAR)) -1 ..) [fast-method]
1: ((:METHOD SC-FORCE-REST2 (SLIPPERY-CHICKEN T T T)) ..) [fast-method]