Updates from July, 2016 Toggle Comment Threads | Keyboard Shortcuts

  • Daniel Ross 10:41 on July 6, 2016 Permalink | Reply  

    At the conference MIke mentioned how to stop the sl-c global variable from triggering a warning. Can anyone remember how to do this?

    • Michael Edwards 16:58 on July 10, 2016 Permalink | Reply

      if you mean when calling e.g. a post-gen function, then you can put something like this at the top of your file: (proclaim ‘(special +my-piece+)) then any reference to +my-piece+ in that source file will not trigger a warning. Or within a single function, your first line of code in the body should be (declare (special +my-piece+))

  • Michael Edwards 15:06 on July 2, 2016 Permalink | Reply
    Tags: release,   

    slippery chicken 1.0.7 is now available for download at
    http://michael-edwards.org/sc/source.html Highlights of new features
    and bug fixes are at http://michael-edwards.org/sc/version-history.txt

  • Michael Edwards 17:54 on June 28, 2016 Permalink | Reply  

    relenting to pressure from Dan and Jolon I’ve had a stab at importing midi files into slippery chicken. see the function midi-file-to-events (added to cm.lsp) once you’ve done (update-app-src ….)

    • Daniel Ross 09:03 on June 29, 2016 Permalink | Reply

      Testing now, very excited!

      • Daniel Ross 13:25 on June 29, 2016 Permalink | Reply

        Error with midi type 0 made in Sibelius
        Shouldnt: message not implemented: 4096.

      • Daniel Ross 13:26 on June 29, 2016 Permalink | Reply

        Error with midi type 1 made in SIbelius
        There is no applicable method for the generic function

        1. when called with arguments

        ((# #)).
        [Condition of type SIMPLE-ERROR]

        • Daniel Ross 13:27 on June 29, 2016 Permalink | Reply

          There is no applicable method for the generic function

          1. when called with arguments

          ((# #)).
          [Condition of type SIMPLE-ERROR]

        • Daniel Ross 13:27 on June 29, 2016 Permalink | Reply

          There is no applicable method for the generic function

          1. when called with arguments

          ((# #)).
          [Condition of type SIMPLE-ERROR]

    • Daniel Ross 13:29 on June 29, 2016 Permalink | Reply

      It won’t let me put the full erro in pre tags without cutting bits off:

      1. when called with arguments

      ((# #)).
      [Condition of type SIMPLE-ERROR]

      • Daniel Ross 13:29 on June 29, 2016 Permalink | Reply

        when called with arguments
        ((# #)).
        [Condition of type SIMPLE-ERROR]

    • Michael Edwards 13:30 on June 29, 2016 Permalink | Reply

      which function? what arguments? maybe send the midi file. i tested by writing via sc’s midi-play, importing that as events, then rewriting via event-list-to-midi-file. worked a treat.

  • Daniel Ross 13:32 on June 28, 2016 Permalink | Reply
    Tags: dynamics, , staff, staves   

    Above-the-staff Lilypond dynamics. Simple but very useful code.
    Above-the-Staff Lilypond Dynamics

    • Michael Edwards 17:53 on June 28, 2016 Permalink | Reply

      nice one dan. and for future reference, if you ever add text marks to an event, you can force these to be above or below the staff by starting the string with ^ (up) or _ (down)

  • Daniel Ross 18:36 on June 27, 2016 Permalink | Reply  

    Hi Mike,

    I’m loving add-auxiliary-notes but it plays havoc with handle-ties when used in conjunction with any of the tie-over-rests, etc. methods.

    I’ve added an extra line to the add-auxiliary-notes-aux function which makes everything work nicely. Could this be incorporated into the download, please?

    (defun add-auxiliary-notes-aux (pitch-list &key (num-notes 3) (interval 1)
                                                 ignore (activity-level 5)
                                                 destructively verbose)
      (let* ((igns (loop for p in (force-list ignore) collect
                        (frequency (make-pitch p))))
             (most-used (hash-least-useds (pitch-list-stats pitch-list)
                                          :ignore igns :num num-notes
                                          :auto-inc nil :invert t))
             (result '())
             (als (loop repeat num-notes collect (make-al 2))))
        (loop for thing in pitch-list
           for freq = (get-freq thing)
           for pos = (position freq most-used)
             (push (if (and (atom freq)     ; don't fiddle with chords
                            (active (nth pos als) activity-level))
    		   ;; DJR - Mon Jun 27 18:34:35 BST 2016
    		   ;; The following line stops the function from
    		   ;; disrupting handle-ties
    		   (unless (or (is-tied-to thing)(is-tied-from thing))
    		     (if (event-p thing)
    			     (when verbose
    			       (format t "~&At bar ~a, transposing ~a "
    				       (bar-num thing) (get-pitch-symbol thing)))
    			     (transpose thing interval
    					:destructively destructively)
    			   (when verbose
    			     (format t "to ~a" (get-pitch-symbol thing))))
    			 (transpose thing interval)))
        (nreverse result)))
    • Michael Edwards 18:01 on June 28, 2016 Permalink | Reply

      Well spotted Dan. Thanks for this. I’d do your is-tied-* tests after the (event-p ) test because otherwise those methods might fail. But I’ve added this very sane code to the repo now:

                         (if (and (event-p thing)
                                  ;; thanks to Dan Ross for this; a further
                                  ;; improvement might be to change the tied notes if
                                  ;; this is tied-from but hey ho...
                                  (not (is-tied-to thing))
                                  (not (is-tied-from thing)))
  • Michael Edwards 18:44 on June 16, 2016 Permalink | Reply
    Tags: loop, nokia, unorthodox   

    Apropos the symposium decision to make some short examples—perhaps first of all, of slippery chicken stuff without a call to make-slippery-chicken—here’s some Nokia fun to make being on a busy train on a Friday night seem positively calm:

    ;;; the nokia tune
    (let* ((motif '(e e q q))
           (rhythms (append (loop repeat 3 append motif) '(h.)))
           (notes '(e6 d fs5 gs cs6 b5 d e b a cs e a))
           (events (loop for r in rhythms and n in notes collect
                        (make-event n r))))
      (events-update-time events)
      (event-list-to-midi-file events :start-tempo 150))
    ;;; the nokia tune after 5 cans of red bull
    (let* ((motif '(e e q q))
           (rhythms (append (loop repeat 3 append motif) '(q.)))
           (notes '(e6 d fs5 gs cs6 b5 d e b a cs e a))
           (events (loop repeat 20 appending
                        (loop for r in rhythms and n in notes collect
                             (make-event n r))))
           (events+ '()))
      (loop for e in events and i from 0 do
           (push e events+)
           (when (and (not (zerop i)) (zerop (mod i 11)))
             (loop repeat 9 do (push (make-event (data (pitch-or-chord e)) 's)
      (setf events+ (reverse events+))
      (events-update-time events+)
      (event-list-to-midi-file events+ :start-tempo 450))
    ;;; same red bull but getting more nervous as the night goes on
    (let* ((motif '(e e q q))
           (rhythms (append (loop repeat 3 append motif) '(q.)))
           (notes '(e6 d fs5 gs cs6 b5 d e b a cs e a))
           (events (loop repeat 20 appending
                        (loop for r in rhythms and n in notes collect
                             (make-event n r))))
           (events+ '()))
      (loop for e in events and i from 0 do
           (push e events+)
           (when (and (not (zerop i)) (zerop (mod i 37)))
             (loop repeat (* 5 (floor i 13))
                do (push (make-event (data (pitch-or-chord e)) 's)
      (setf events+ (reverse events+))
      (events-update-time events+)
      (event-list-to-midi-file events+ :start-tempo 450))
  • Daniel Ross 14:21 on June 15, 2016 Permalink | Reply
    Tags: add-auxiliary-notes, error, transpose   

    Getting an error when calling add-auxiliary-notes. No idea how it is passing the wrong arguments to transpose in add-axiliary-notes-aux

    There is no applicable method for the generic function

    1. when called with arguments

    (2 1).
    [Condition of type SIMPLE-ERROR]

    • Daniel Ross 14:32 on June 15, 2016 Permalink | Reply

      Here’s some simplified code. I think it’s a rhythm chain problem.

      (let* ((rch (make-rthm-chain
      ‘test-rch 23
      ‘((((e) e) ; 4 in total
      (- s (s) (s) s -)
      ({ 3 (te) – te te – })
      ((e.) s))
      (({ 3 (te) te (te) }) ; what we transition to
      ({ 3 – te (te) te – })
      ({ 3 (te) – te te – })
      ({ 3 (te) (te) te })))
      ‘((((q q) ; the 2/4 bars: 5 total
      ((q) q)
      ((q) q)
      ((q) (s) e.)
      (- e e – (e) e))
      (({ 3 te+te te+te te+te }) ; what we transition to
      (q – s e. -)
      (q (s) e.)
      (q (s) – s e -)
      ({ 3 te+te te+te – te te – })))
      ((((e.) s (e) e (s) e.) ; the 3/4 bars: 4 total
      (- e e – (e) e (q))
      (- e. s – – +e e – (q))
      (q (e.) s (q)))
      (({ 3 (te) (te) te+te te+te } (q)) ; what we transition to
      (- e. s – (q) (s) – s e -)
      ({ 3 te+te te } (q) q)
      ({ 3 – te te te – } (e) e { 3 (te) (te) te }))))
      :players ‘(pno pnol)
      :activity-curve ‘(0 10 100 10)
      :harmonic-rthm-curve ‘(0 1 100 3)
      :do-sticking t
      :do-sticking-curve ‘(0 1 25 0 50 1 75 0 100 1)
      :sticking-curve ‘(0 0 100 1)
      :sticking-repeats ‘(3 5 7 11 2 7 5 3 13)
      :sticking-rthms ‘(e s e q)
      :split-data ‘(4 7))))

      (create-psps (palette rch))

      :title “Your Title Here”
      :composer “Your Name Here”
      :ensemble ‘(((pno (piano :midi-channel 1))
      (pnol (piano-lh :midi-channel 1))))
      :staff-groupings ‘(2)
      :tempo-map ‘((1 (q 60)))
      :set-palette `((set1 ((b2 a4 d5 e5 a5 d6)))
      (set2 ((b2 fs3 d4 e4 a4 d5 e5 a5 d6))))
      :set-map `((1 ,(loop for i below (num-rthm-seqs rch)
      collect (if (evenp i) ‘set1 ‘set2))))
      :rthm-seq-palette (palette rch)
      :rthm-seq-map rch)

      (add-auxiliary-notes +mini+)
      ;;; Output
      (midi-play +mini+ :midi-file “/users/danieljross/desktop/mini.mid”)
      (cmn-display +mini+) ; score display
      ;(lp-display +mini+) ; lilypond display

    • Michael Edwards 19:53 on June 15, 2016 Permalink | Reply

      Hi Dan, you’re going to hate this answer but this code runs perfectly for me. Have you got an old/corrupted version of the source again perhaps?

      By the way, if you put code within the <pre> </pre> tags copy/paste might be easier

      • Daniel Ross 10:02 on June 16, 2016 Permalink | Reply

        Yeah, sorry, forgot about the tags. Anyway, re-updated and all works now. Odd. Thanks for the help.

  • Michael Edwards 17:35 on June 14, 2016 Permalink | Reply
    Tags: competition   

    Let’s have a “hello slippery world” competition to see if we can get a very short, pithy, but appealing little piece out of a basic (make-slippery-chicken) call. It’s got to be just pitches and rhythms first of all so it can then be dressed up to show off other features.

  • Dario Sanfilippo 16:43 on June 14, 2016 Permalink | Reply  

    Composing with the logistic map 

    The following code, is an example of how to generate rhythm, set and pitch palettes, as well as maps, based on the Logistic Map (LM).


    (defun logistic-map (x r map n &key (exp 1.0) (offset 0.0) (round t))
      (unless (and (= x 0.0) (= r 0.0))
        (error "chaos: First argument should be in the [0;1] range; second ~
                argument should be in the [3;4] range."))
      (loop for i from 1 to n
         for result = (+ offset
                         (* map
    			 (setf x (* r (* x (- 1.0 x)))) exp)))
         collect (if round (round result)
    (defun gen-set-palette (lower upper elements x r &key (exponent 1.0)) 
      (let* ((range
    	  (- (note-to-midi upper)
    	     (note-to-midi lower))))
         (loop for i from 0 to (- elements 1)
    	for init in (logistic-map x 4 1 elements :round nil)
    	for leap in (logistic-map x 4 range elements)
    	for offset = (+ (note-to-midi lower)
    			(first (logistic-map init 4 (- range leap) 1)))
    	collect (list i
    			(mapcar 'midi-to-note
    				 (loop for midi in
    				      (logistic-map init r leap 20
    						    :exp exponent)
    				    collect (note-to-midi (+ midi offset)))
         '(:recurse-simple-data nil))))
    (defun gen-rsp (timesig smallest elements x r &key (exponent 1.0))
      (loop for i from 0 to (- elements 1)
         for init in (logistic-map x 4 1 elements :round nil)
         collect (list i
    		   (let* ((rsp '())
    			  (sum 0)
    			  (notes 0))
    		     (loop for x in
    			  (remove 0
    				  (logistic-map init r (* 2 smallest) 1000
    					;double it to have a bipolar output
    					 :exp exponent
    					 :offset (* -1 smallest)))
    			summing (/ 1.0 (abs x)) into tot
    					; accumulate
    			while (< tot (/ (first timesig)
    					(second timesig)))
    					; check if the accumulated values do
    					; exceed bar length
    			do (setf sum tot)
    			if (< x 0) ; attack if positive, rest if negative
    			do (setf rsp
    				  (list (abs x)) rsp))
    			do (setf rsp
    				 (cons x rsp)))
    		     (setf rsp (cons    ; when notes exceed bar length,
    				(/ 1	; fill the remaining part
    				    (- (/ (first timesig)
    					  (second timesig)) sum))) rsp))
    		     (setf rsp
    			    (cons timesig (reverse rsp)))) ; correct order
    		     (loop for i in (first rsp)
    			when (numberp i)
    			do (incf notes)) ; accumulate number of attacks
    		     (setf rsp
    			   (list rsp ':pitch-seq-palette
    				 (list ; generate pitch curve
    				  (logistic-map init r 10 notes))))))))
    (let* ((seed .7342)
           (r 4)
           (bars 20)
           (sets 20)
           (seqs 20)
    	 :ensemble '(((hand0 (piano :midi-channel 1))
    		      (hand1 (piano :midi-channel 1))))
    	 :tempo-map '((1 (q 60)))
    	 :set-palette (gen-set-palette 'c2 'c4 sets seed r)
    	 :set-map `((1 ,(logistic-map seed 4 (1- sets) bars)))
    	 :rthm-seq-palette (gen-rsp '(2 4) 32 seqs seed r)
    	 :rthm-seq-map `((1
    			  ((hand0 ,(logistic-map .24324 r (1- seqs) bars))
    			   (hand1 ,(logistic-map .34312 r (1- seqs) bars))))))))
      (re-bar logistic-map-test
    	  :min-time-sig '(4 4) 
    	  :auto-beam 'q)
      (midi-play logistic-map-test)
      (cmn-display logistic-map-test))

    The LM is an iterated nonlinear function which, under specific conditions, can generate chaotic behaviours.

    This is its form:

    x_n+1 = r * x_n * (1 – x_n).

    x_n (in the [0;1] range) is the initial condition, while r is sometimes called "growth rate". r (in the [0;4] range) is the most important parameter in the LM as it determines the degree of repetition/unpredictability in the sequence of values (in the [0;1] range) generated by the function. The x_n parameter can also have significant effects for some specific values, although it will generally create different outputs while the function keeps an overall consistent behaviour depending on r.

    Recently, I've composed a piece for piano in occasion of the Slippery Chicken symposium at Goldsmiths and I've decided to create it entirely using the LM as an algorithmic technique. The reason is that my research is based on feedback, and I wanted to be consistent even in the context of non-realtime systems, which is different than my usual one. Besides, the LM seemed to offer an ideal solution since, in general, my idea of music creation implies varying structures which still keep a unique identity and overall character. This, indeed, could be achieved by controlling the x and r parameters: r would determine the overall infrastructure of the piece, while x could generate different versions of the same work.

    For my piece, I also decided to have nested levels of unpredictability, meaning that the output of some LM(s) would control the values of x and r of other LM(s) used for the generation of the SC data. In this example, though, most of the values are fixed and there is perhaps only one case of nested LM(s).

    Here, I'm showing how the LM can be used to algorithmically generate palettes and maps.

    The LOGISTIC-MAP function takes four arguments, has three keywords, and returns a list of numbers. The four arguments are: initial value (x); rate (r); mapping range (map); list length (n). The three keywords determine the exponent to which the sequence will be raised to (before being mapped to its range), an offset, and whether the values are integers or floating point numbers. The reason why I decided to add an exponent keyword is that a [0;1] range is convenient in this case as it is possible to push the sequence towards either of the two extremes, depending on exponents which are greater than 1 or between 0 and 1, without exceeding its boundaries. Please note that the sequence generated by the logistic-map function starts at x_n+1.

    The GEN-SET-PALETTE function takes five arguments, has one keyword, and returns a SC set palette. The five arguments are: lowest note in the sets (lower, a symbol); highest note in the sets (upper, a symbol); the number of sets in the palette (elements); the initial value of the LM (x); the LM rate (r). The keyword sets an exponent which is then passed to the LM function. For example, using an exponent greater than 1 will push the notes in the sets towards to lower limit, whereas an exponent within 0 and 1 would push the notes towards the upper limit. Please note that, internally, there is a LM-dependent offset which shifts each set within the lower and upper limits.

    The GEN-RSP function takes five arguments, has one keyword, and returns a SC rhythm sequence palette. The five arguments are: a time signature (timesig, a two-integer list); the smallest possible duration for an attack or rest (smallest, a denominator); the number of sets in the palette (elements); the initial value for the LM (x); the LM rate (r). The keyword sets an exponent which is then passed to the LM function. Internally, the mechanism is rather trivial and it maps the sequence of the LM function to a range which goes from -smallest to smallest. If the resulting value is a negative value, that is added to the set as a rest, otherwise, it is added as an attack. Some conditionals will make sure that the set is filled with the right durations, and the right number of pitch points will be generated based on the LM. For example, the argument r, here, could be used to determine the regularity of durations as well as the repetition of notes, while the exponent could be used as a density index considering that it would push the sequence towards the negative or positive side of the range.

    The rest of the code is also very straightforward and it just creates a very simple example to give you a basic idea. Hopefully, the GEN-RSP will eventually become something more advanced, capable of generating tuplets and other more articulated rhythms. The GEN-SET-PALETTE, too, could easily be improved by, for example, giving the possibility to set varying limits for each set. And as I already mentioned, extending these algorithms in order to implement nested LM could also result in more interesting outputs.

    I still hope that this will be useful for some of you.

    Thanks to Michael and Dan for putting together this event which was a very productive and enjoyable experience with nice people and good music.

  • Michael Edwards 10:15 on June 14, 2016 Permalink | Reply
    Tags: hairpins, midi-play,   

    The first functionality update that arose out of the Goldsmiths symposium last weekend was a fix to the way MIDI velocities are handled. As of the latest svn-latest check-in (2 mins ago) when you call midi-play, event velocities will reflect the last dynamic seen in any given part (rather than retaining their default velocity). Also, if you have hairpins (crescendo/diminuendo marks), then the notes that are under these will have correspondingly increasing/decreasing amplitudes.

  • Shelly Knotts 17:54 on June 12, 2016 Permalink | Reply  

    From SuperCollider to Slippery Chicken by trial-and-error 

    In the last 72 hours I used the trial-and-error (mostly error) method of composition to write a disklavier piece in Slippery Chicken. I had never used a lisp type language before and mostly discovered that this is nothing like SuperCollider (which I’ve been having a love-hate relationship with for the last decade) and it isn’t possible (at least for me) to learn enough to get creative with it in 3 days.

    The result of this endeavour was a suite of six pieces: your-title-here1-6, which reflect various stages of learning to wrangle slippery bits of chicken code into new arrangements and executing it to work out what I’ve just changed. I quickly learned that to make anything more than minor changes between checking the code output would result in confusion and frustration as I tried to work out which brackets don’t match up or what coding concept my SuperCollider shaped brain has misunderstood.

    This process of course wasn’t exactly aided by my aversion to reading manuals and inability to concentrate on watching five minute long videos which probably contain all the answers to everything in the slippery chickenverse.

    My composition process ended, mostly because time-til-concert reached zero before piece seven –  which may have engaged more deeply with dynamics – was finished, but here’s some things I learned which might help future SuperCollider->Slippery Chicken converts get going a bit quicker than I did:

    • everything in Slippery Chicken happens in bars (although apparently this can be bypassed by working in lisp directly…). Your bars need a time signature, and if you have 4 durations in the bar then you also need 4 pitches. This was probably the biggest shock to my system after spending the last 10 years liberally shoving any number of pitches and durations in arrays and letting Pbinds work out the rest.
    • if your number of durations and number of pitches aren’t the same the code wont run.
    • you can’t actually specify the exact pitches you want to use. You specify pitch sets and then approximate points in the pitch set where you want to choose a pitch from.
    • you also can’t specify pitches or intervals in chords (i think?).
    • the chords are generated by chord functions which are specified per instrument not at the place you want to use the chord.
    • each rhythm sequence and pitch set gets some kind of name and that name could be a single integer.
    • but tempo is specified by bar number, which could look the same as your rhythm seq/pitch set naming, but is unrelated.
    • there’s no modularity in slippery chicken – the bar based structure means that all the parts of the code need to have the same number of bars match up to other bits of the code, so most of the time copy and pasting bits of code in from other examples in the manual will probably just break your code.

    Of course all of these things are explained in the manual, so if you have more time/patience and a longer concentration span than me, then that’s a good place to start.

    • Michael Edwards 17:22 on June 14, 2016 Permalink | Reply

      Most of what you write Shelly does apply to the “orthodox” use of slippery
      chicken but that’s just one way of using it. You can bypass bars and have
      exactly the pitches you want but that would mean another way of working than
      perhaps the example(s) you looked at.

      Labelling data (like harmonic sets) is fundamental to the reuse of material and
      mapping structures. Labels (IDs) can be numbers, strings, or symbols. Lots of
      other functionality though is referenced via bar numbers, for convenience. So
      yes, numbers can refer to many things.

      slippery chicken is in fact highly modular, hence its object-oriented design. But
      perhaps you mean modular in a supercollider way, rather than as the computer
      science term?

      Here’s an example of making a piece without a call to
      make-slippery-chicken (so no rthm-seq-maps or set-maps):
      don’t flinch

  • adam 17:09 on June 12, 2016 Permalink | Reply  

    improving documentation usability 

    Drawing on my experiences as a new user, and further discussions with new and power users, as well as with the lead developer (Michael E.), we have reached a consensus on how to re-organize the documentation for improving usability.

    There are two main points to be noted:

    • move some or all existing (non-interactive) documentation to a wiki
    • ‘atomize’ documentation of all functions, and illustrate each with a limited collection of simplified examples that are re-used across entries (in the spirit of ‘hello world’).

    The atomization will allow for functions and techniques to be more easily learned, as well as more effectively communicating how to combine them to achieve desired results.

    The role of traditional wiki ‘discussion’ (aka ‘talk’, ‘sandbox’, etc.) pages could be served by the current microblog (where this entry was originally posted). The microblog has already been earmarked as a target destination to which existing social media discussions of the software will be migrated.

    Over time, a two-way relationship can evolve between the microblog and wiki, where questions can be answered by microblog links to the wiki, and solutions arrived at in microblog discussions can be added to the wiki when an entry is absent or missing details (including a link back to the original microblog discussion).

    A further benefit of using a wiki is its internal network structure, where each entry is a node (aka ‘deep link’) that can be linked to any other entry, allowing for the expansion of explanations as needed by a given user (e.g. an entry on mapping pitches to rhythms might link to an entry on specifying pitches; an entry on specifying basic rhythms might link to an entry on adding more detailed articulations such as accents, etc.).

    Lastly, the use of tags in a wiki would allow for multiple concurrent organisations of concepts. To illustrate why this would be useful, consider that the way dynamics are implemented in a single bar differs from how they are implemented in multi-bar structures. A hierarchically organised wiki structure with tags would allow for a user to approach the documentation in two different ways: a user could choose to focus on the group of all operations involving dynamics in one or more bars, or, alternatively, on all operations that can be performed on a single bar and/or those that can be performed across multiple bars.

  • Owen Green 17:08 on June 12, 2016 Permalink | Reply  

    Owen 's Symposium Reflections 


    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.

  • Daniel Ross 17:01 on June 12, 2016 Permalink | Reply  


    The EMS was packed for the concert and the Disklavier did sterling work! There will be video and audio available soon so watch this space!

  • Marcin PietruszewskiIt 16:54 on June 12, 2016 Permalink | Reply  

    ‘sifting’ for piano – a little bit on compositional ideas behind the piece.

    1. Pitch Sets

    A selection of the pitch material for the piece was a two levelled process. At first I have used simple sieve generators (such as arithmetic series, sieve of Eratosthenes – a simple, ancient algorithm for finding all prime numbers up to any given limit) to generate lists of values of a range between 21 and 107 (a midi range of a piano instrument). Second stage consisted in logical operations (a binary operators – union, intersection and symmetric difference; a unary operator – complementation) on these lists. An inspiration for this way of working with musical material was sifting used by Iannis Xenakis. In numerous publications Xenakis developed an elegant and powerful system for creating integer-sequence generators. Xenakis used sieves (cribles) for the generation of pitch scales and rhythm sequences in many compositions, and he suggested their application to a variety of additional musical parameters (see an implementation of the algorithm by Christopher Ariza http://www.mitpressjournals.org/doi/pdf/10.1162/0148926054094396). Additionally in ‘sifting’ this technique had been used to generate values for pattern chop algorithm.

    2. Rhythm Material and rhythm chop

    The basis of a rhythmic structures of the piece were traditional – existing largely in aural tradition – folk tunes from Wielkopolska region. A five short (1 bar length) rhythm sequences were declared as a source material for the pattern chop algorithm (based on Michael Edwards’ chop example) and values from a sifting algorithm were used to select a section of a sequence. The resulting material still has a distinct feel of a folk tune – I think – with added complexity of expanded pitch content and a break-beat style rhythm processing.

    Here is a version of the piece as played at the concert

    • Fiona Harrison 07:37 on June 15, 2016 Permalink | Reply

      Hi Marcin, for some reason I can’t play this. I’d be interested to hear it though!

      • marcin pietruszewski 11:13 on June 20, 2016 Permalink | Reply

        hey Fiona, it’s a midi file you can play it from within a DAW of your choice using a virtual piano instrument.

  • Daniel Ross 16:50 on June 12, 2016 Permalink | Reply  



    The title of my piece for the slippery chicken Symposium arose after attending a lecture by the composer Christopher Fox on musical memory. One of the points he mentioned was that when we listen to music we tend to have in mind the thing we are currently listening to and the thing we listened to just before that. Every time we hear something that we recognise it is like returning to the (a) chorus, therefore it is possible to say that all music is essentially in rondo form.


    At the heart of this piece is a rhythm chain, or more specifically, two rhythm chains which give me four lines of counterpoint. Using the add-voice method I then double the number of voices to eight and use the data to generate two separate slippery chicken objects. These are spliced together using my copy-bars-sc2sc method. (Follow the link and you can have it for yourself.)

    The rondo part of the piece comes from a third slippery chicken object which contains hand coded rthm-seqs. I substitute these for the sticking points of the rhythm chain using a loop that analyses time signatures bar-by-bar and copy-bars-sc2sc. When the time signature is ‘(3 8) the method does its thing. (The time signature is only ever ‘(3 8) during the sticking points because these are defined as repeated quavers (‘e) in multiples of 3. The rhythm chain itself tends to make bars of ‘(2 4) and ‘(3 4).)

    The pitch data is generated from harmonic sequences. Most by harm-list. The ordering of the set-map is determined by L-system rules.

    Tempo changes are dependent on the sl-c object and there are brief rallentandi between these sections to make the piece sound more natural. This is further aided by my sc-midi-groove method (NB this is not yet available to the public).


    It is very easy to create interesting material within sl-c but it is much harder to combine several different sections together within the same call to make-slippery-chicken. My copy-bars-sc2sc method makes life a lot easier in this regard and I plan to use it a lot more. At the conference, I presented work I had made using the method and have made it available on my website for anyone else to use. http://vitruviandan.wordpress.com/code

    Midi-file of the piece: rondo-del-computer


  • Michael Edwards 16:42 on June 12, 2016 Permalink | Reply  

    One of the greatest pleasures of developing my algorithmic composition software is watching what happens when it’s taken up by other composers. It’s always astonishing to me to hear the variety of music that comes out of even quite orthodox use of the software. We’ve just presented a concert of nine new algorithmic works composed for the Disklavier at Goldsmiths. Robot piano music, Dan Ross called it, and though there were no actual robots in the sense that you might imagine from such a description, the Disklavier’s computer controlled hammers offered a precision attack that was particularly striking in the onsets of some of the massive chords that were generated.

    Several of the pieces were developed over the last couple of months (and several coding sessions) in Edinburgh; others arose in just the last week. They ranged from Schillinger-inspired rhythmic structures to conflations of different pieces made with the rhythm chains algorithm; from the generation of musical parameters from chaos algorithms to those based on biomechanics; from Xenakis-style sieving to randomness to irrational rhythms from permutated proportions. With the permission of the composers I’ll post recordings of the the music on this blog as soon as possible.



    Last-minute hammer velocity tweaking at the Goldsmiths slippery-chicken symposium

  • Owen Green 17:13 on June 11, 2016 Permalink | Reply  

    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
         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)
           (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.

  • Daniel Ross 15:56 on June 9, 2016 Permalink | Reply  

    When adding dynamics post-gen with add-mark, the added dynamic doesn’t effect the midi velocity of subsequent notes. How do you get around this, Mike?

    • Daniel Ross 16:48 on June 9, 2016 Permalink | Reply

      OK, have found set-amplitudes.

  • Marcin PietruszewskiIt 18:26 on June 8, 2016 Permalink | Reply
    Tags: sieve   

    here is a little example of what I’m about to present on Saturday.

    • set-palette generated through logic operations on sieves;
    • original rhythmic material based on traditional polish tunes (from Wielkopolska region);
    • Michael’s chop algorithm …amazeballs 🙂
    • further sifting on set-map and rthm-set-map data

    to do

    • dynamics
    • extend it!!


  • Michael Edwards 11:41 on June 8, 2016 Permalink | Reply
    Tags: MIDI note numbers, set-palettes   

    Marcin was asking about initialising set-palettes from MIDI note numbers instead of note names. The set-palette init method doesn’t (yet) accommodate MIDI numbers but this works fine for creating a set-palette ‘by hand’ via the add method:

    (let* ((sp (make-set-palette 'empty nil)))
      (add (make-sc-set '(cs3 d4) :id 1) sp)
      (add (make-sc-set (loop for m in '(10 20 30 40 50 60) collect
    			 (midi-to-note m))
    		    :id 2)
    • Marcin PietruszewskiIt 18:18 on June 8, 2016 Permalink | Reply

      Cheers Michael,

      I just used

      (defun sp-from-midi (list)
      (loop for x in list collect (midi-to-note x))

      along with function to parse set-palette now I can throw all integer based sieves into it 🙂

  • Michael Edwards 11:33 on June 8, 2016 Permalink | Reply
    Tags: ,   

    Dan’s advice is to keep Disklavier velocities to within the 30 to 90 range. I’ve just implemented the rescale function to help with this (see below) so if you have events with amplitudes between 0.0 and 1.0 then the following would map those to velocities of 30 to 90:

    (midi-play +jitterbug+ :force-velocity
    	   #'(lambda (event) 
    	       (round (rescale (amplitude event) 0 1 30 90))))

    ;;; ****f* utilities/rescale
    ;;; DATE
    ;;; June 8th 2016, Edinburgh
    ;;; Given a value within an original range, return its value withing a new range
    ;;; - the value we want to rescale
    ;;; - the original minimum
    ;;; - the original maximum
    ;;; - the new minimum
    ;;; - the new maximum
    ;;; The value within the new range (a number)
    ;;; EXAMPLE
    (rescale .5 0 1 0 100)
    ==> 50.0
    ;;; SYNOPSIS
    (defun rescale (val min max new-min new-max)
    ;;; ****
      (when (or (>= min max)
                (>= new-min new-max))
        (error "utilities::rescale: argument 2 (~a) must be < argument 3 (~a) ~
                ~%and sim. for argument 4 (~a) and 5 (~a)" min max new-min new-max))
      (unless (and (>= val min)
                   (<= val max))
        (error "utilities::rescale: first argument (~a) must be within original ~
                range (~a to ~a)" val min max))
      (let* ((range1 (float (- max min)))
             (range2 (float (- new-max new-min)))
             (prop (float (/ (- val min) range1))))
        (+ new-min (* prop range2))))
    • Daniel Ross 12:54 on June 9, 2016 Permalink | Reply

      Misspelling in your code, mate. There is a space between ‘<' and '=' in your unless clause.

      • Michael Edwards 12:56 on June 9, 2016 Permalink | Reply

        there isn’t, it just looks like it :/ saw that yesterday but it’s wordpress screwing display up–if I edit the post there’s no space. anyway, (update-app-src) and you should get all the new glory

        • Daniel Ross 13:13 on June 9, 2016 Permalink | Reply

          Ah cool. It is there if you copy and paste direct from above, but no probs if it’s on the svn anyway.

  • Owen Green 23:34 on June 7, 2016 Permalink | Reply  

    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

        ;;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)))
           (next-event opus ins t 1);start slurping events
    	  for ne = (next-event opus ins t)
    	  for i from 1
    	  ;;scaled activity envelope 
    	  with  activity = (make-ale (genal) (floor notes cycles))
    	  while ne
    	    (when (not (active activity))
    	      (sc-force-rest2 opus (bar-num ne) (bar-pos ne) ins)))))

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

    • Owen Green 23:37 on June 7, 2016 Permalink | Reply

      It’s happy enough if I just (force-rest) on the event, btw.

      • Michael Edwards 11:39 on June 8, 2016 Permalink | Reply

        Looks like your (bar-pos ne) hasn’t been initialised correctly. If I do (make-rthm-seq-bar ‘((2 4) q e e)) I can see that the bar-pos slot of the rhythm objects is correct. How about yours (look at a random bar via (get-bar …)? If they’re all -1 does (update-slots +opus+) help?

        • Owen Green 12:08 on June 8, 2016 Permalink | Reply

          (let ((b (get-bar +opus+ 2 'p1)))
          (loop for i from 0 below (sclist-length b)
          do (print (bar-pos (get-nth-event i b)))))



          (It also says caught WARNING: undefined variable: +OPUS+ (when I run this from REPL after building the piece), so I’ve still got something to learn about how global vars are bound…)

        • Michael Edwards 12:16 on June 8, 2016 Permalink | Reply

          Ah, we both should have spotted this: doc to sc-force-rest2: – The event number in the bar (integer, counting from 1)

          So you’ll need (1+ (bar-pos ne))

          • Michael Edwards 12:20 on June 8, 2016 Permalink | Reply

            re. warning: that’s just SBCL being paranoid. I’d ignore it in the repl but in your code you can always write (declare (special +whatever+)) at the beginning of a defun or even (proclaim ‘(special …)) at the top of a file which might reference a global in several funs.

          • Owen Green 12:20 on June 8, 2016 Permalink | Reply

            Bingo, cheers.

  • Daniel Ross 13:16 on June 6, 2016 Permalink | Reply
    Tags: add-bar, make-rthm-chain, rthm-chain   

    How do I add a bar to the end of a rthm-chain? The add-bar method returns an error.

    (let* ((rch (make-rthm-chain
    	     'test-rch 23
    	     '((((e) e)			; 4 in total
    		(- s (s) (s) s -)
    		({ 3 (te) - te te - })
    		((e.) s))
    	       (({ 3 (te) te (te) })	; what we transition to
    		({ 3 - te (te) te - })
    		({ 3 (te) - te te - })
    		({ 3 (te) (te) te })))
    	     '((((q q)			; the 2/4 bars: 5 total
    		 ((q) q)
    		 ((q) q)
    		 ((q) (s) e.)
    		 (- e e - (e) e))
    		(({ 3 te+te te+te te+te }) ; what we transition to
    		 (q - s e. -)
    		 (q (s) e.)
    		 (q (s) - s e -)
    		 ({ 3 te+te te+te - te te - })))
    	       ((((e.) s (e) e (s) e.)	; the 3/4 bars: 4 total
    		 (- e e - (e) e (q))
    		 (- e. s - - +e e - (q))
    		 (q (e.) s (q)))
    		(({ 3 (te) (te) te+te te+te } (q)) ; what we transition to
    		 (- e. s - (q) (s) - s e -)
    		 ({ 3 te+te te } (q) q)
    		 ({ 3 - te te te - } (e) e { 3 (te) (te) te }))))
    	     :players '(pno pnol)
    	     :slow-fibonacci t
    	     :activity-curve '(0 1 100 10)
    	     :harmonic-rthm-curve '(0 1 100 3)
    	     :do-sticking t
    	     :do-sticking-curve '(0 1 25 0 50 1 75 0 100 1)
    	     :sticking-curve '(0 0 100 10)
    	     :sticking-repeats '(3 5 7 11 2 7 5 3 13)
    	     :sticking-rthms '(e s. 32 e.)
    	     :split-data '(4 7))))
      (create-psps (palette rch))
       :title "Your Title Here" 
       :composer "Your Name Here"
       :ensemble '(((pno (piano :midi-channel 1))
    		(pnol (piano-lh :midi-channel 1))))
       :staff-groupings '(2)
       :tempo-map '((1 (q 60)))
       :set-palette `((set1 ((b2 a4 d5 e5 a5 d6))) 
    		  (set2 ((b2 fs3 d4 e4 a4 d5 e5 a5 d6))))
       :set-map `((1 ,(loop for i below (num-rthm-seqs rch)
    		     collect (if (evenp i) 'set1 'set2))))
       :rthm-seq-palette (palette rch)
       :rthm-seq-map rch)
      (add-bar rch (make-rthm-seq-bar '((5 8) e e+32 s. +q)))
    ;;; Output
      (midi-play +mini+)			; midi file
      (cmn-display +mini+)			; score display
    					;(lp-display +mini+) ; lilypond display
    • Michael Edwards 14:22 on June 6, 2016 Permalink | Reply

      add-bar is a rthm-seq method but rthm-chain is a rthm-seq-map subclass so you just can’t do what you’ve tried to do. Maybe if you get a rthm-seq out of rch via get-data you might be able to add a bar

  • Daniel Ross 09:42 on June 6, 2016 Permalink | Reply

    I did a recording session with the disklavier on Friday. Velocity 90 is massive. Don’t go above 90.

    • Michael Edwards 12:19 on June 6, 2016 Permalink | Reply

      anyone who’s setting their amplitudes before the call to midi-play can make sure their velocities don’t get too high via this hard-limiting approach when calling midi-play:

      (midi-play +jitterbug+ :force-velocity
      	   #'(lambda (event)
      	       (min 100 (floor (* (amplitude event) 127)))))
      • Michael Edwards 12:23 on June 6, 2016 Permalink | Reply

        or perhaps simpler and not hard-limiting, this will automatically range over 100 instead of 127, assuming that your events’ amplitude values range up to 1.0

        (midi-play +jitterbug+ :force-velocity
                   #'(lambda (event)
                       (floor (* (amplitude event) 100))))
  • Michael Edwards 13:17 on June 2, 2016 Permalink | Reply
    Tags: , velocity   

    Dan’s tested the Goldsmiths Disklavier. All keys are working, as are the damper and una corda pedals. He suggests limiting your MIDI velocities to 100 as anything higher is phenomenally loud and liable to disturb the tuning or perhaps even damage the instrument. See the post below for how to handle velocities within the midi-play method.

    • Michael Edwards 13:19 on June 2, 2016 Permalink | Reply

      the middle (sostenuto) pedal does not seem to be responding to controller number 66.

    • Daniel Ross 15:52 on June 2, 2016 Permalink | Reply

      MIDI Velocity 90 is LOUD on the dislklav. Go up to 100 at your peril!

  • Daniel Ross 16:22 on May 31, 2016 Permalink | Reply  

    Would be lovely to include something like this in sl-c. Something to discuss at the symposium, perhaps?

    • Michael Edwards 16:48 on June 1, 2016 Permalink | Reply

      That looks great though I’m not sure how it works. Definitely something to discuss at the symposium though, thanks.

  • Michael Edwards 08:34 on May 27, 2016 Permalink | Reply
    Tags: auxiliary notes, post-generation,   

    Some of you will already know the rm-repeated-pitches method. This finds repeating pitches in any or all voices of a slippery-chicken object and replaces them with other pitches from the current set. Of course what this is doing is ironing out some of the problems inherent to algorithmic pitch selection, and slippery chicken’s in particular.

    For the Goldsmith’s project next month I’ve developed a related method called add-auxiliary-notes. This tries to deal with some of the static pitch structures that arise out of limited but extended harmonic fields. It analyses slippery-chicken voices phrase by phrase to find the most frequently used notes, then changes some of them (according to an activity-levels object) to auxiliary notes (up a semitone by default but any and varied intervals are possible). It’s already available on the SVN server so those of you who want it will find it along with documentation in the file slippery-chicken-edit.lsp after doing (update-app-src …)

    • Daniel Ross 16:19 on June 2, 2016 Permalink | Reply

      I’m getting the following error with this new add-aux–notes method:
      (LET* ((POC
      (PITCH-OR-CHORD E)))

      • Daniel Ross 16:19 on June 2, 2016 Permalink | Reply

        Execution of a form compiled with errors.
        (LET* ((POC
        (IF WRITTEN
        (PITCH-OR-CHORD E)))
        (IS-CHORD E)
        Compile-time error:
        The LET* binding spec (IF (IS-CHORD E)
        COLLECT (FREQUENCY P))) is malformed.
        [Condition of type SB-INT:COMPILED-PROGRAM-ERROR]

      • Michael Edwards 16:40 on June 2, 2016 Permalink | Reply

        that code works fine for me. I can’t see an error in there and my Lisp doesn’t complain when I compile event.lsp

        I think you’ll have to send the offending code

        • Daniel Ross 16:45 on June 2, 2016 Permalink | Reply

          It’ll take me ages to get something you an run on your machine….
          Isn’t it just a misplaced bracket in the get-frequency method? (A close paren missing on line 7 and on line 10 instead)

          • Michael Edwards 17:08 on June 2, 2016 Permalink | Reply

            I know what you mean but I can’t see an error there. Maybe a download problem? This is what I’ve got and it runs fine for me:

            (defmethod get-frequency ((e event) &key written force-list average)
              (if (is-rest e)
                  (let* ((poc (if written
                                  (written-pitch-or-chord e)
                                  (pitch-or-chord e))))
                    (if (is-chord e)
                        (if average
                            (/ (loop for p in (data poc) sum (frequency p))
                               (sclist-length poc))
                            (loop for p in (data poc) collect (frequency p)))
                        ;; single pitch
                        (if force-list (list (frequency poc)) (frequency poc))))))
            • Daniel Ross 17:23 on June 2, 2016 Permalink

              That’s nothing like what I have. Will try update-app-src again…

            • Daniel Ross 17:25 on June 2, 2016 Permalink

              Nope, no luck. Still looks like this:
              (defmethod get-frequency ((e event) &key written force-list)
              ;;; ****
              (if (is-rest e)
              (let* ((poc (if written
              (written-pitch-or-chord e)
              (pitch-or-chord e)))
              (if (is-chord e)
              (loop for p in (data poc) collect (frequency p)))
              (if force-list (list (frequency poc)) (frequency poc))))))

            • Michael Edwards 17:34 on June 2, 2016 Permalink

              so your code is different to mine. that’s weird. I’m updating the src at svn-latest. In the meantime just replace your method definition with mine and all should be well.

            • Michael Edwards 17:37 on June 2, 2016 Permalink

              try (update-app-src …) I can definitely see the right version of the method at https://sourced.ecdf.ed.ac.uk/projects/user/medward2/browser/sc-tags/sc-latest/src/event.lsp

            • Daniel Ross 08:41 on June 3, 2016 Permalink

              Cool, that works now. Thanks!

  • Michael Edwards 13:48 on May 25, 2016 Permalink | Reply
    Tags: pedalling, piano,   


    If you who read facebook slippery chicken group posts you may remember this one about pedalling:

    “Those of you working on piano pieces: as of yesterday, if you add one of the three pedal marks ‘ped, ‘ped-up, or ‘ped^ you’ll get the correct controller information written to your MIDI files for free—in other words, during MIDI playback the sustain pedal should work.

    If you want to set the controller message of an event yourself, just e.g.
    (push '(1 64 127) (midi-control-changes event))
    where the first 3-element list there is (midi-channel controller-number value). 64 is the sustain pedal controller number; 127 will depress and 0 will release.

    If you need this functionality do (update-app-src …)”

    Just wanted to update this to mention that this will also work with the ‘uc and ‘tc marks (una corda / tre corde) and the ‘sost and ‘sost-up marks (middle / sostenuto pedal), i.e. not only will the pedal marking appear in the score but the MIDI controller data will be written when you call midi-play.

  • Michael Edwards 16:56 on May 23, 2016 Permalink | Reply
    Tags: MIDI   

    Some of you might be interested in the following bit of code to get bass notes to play louder (not at all Fletcher-Munson curve correction but that could be implemented too by using the a-weighting function).

    :force-velocity can either be a fixed number or a function. If the latter then each consecutive event is passed to the function automatically by midi-play. Below we subtract the degree (equivalent to MIDI note number when using the chromatic scale) from 127 to make lower notes louder than higher notes, but we do restrict this to between 70 and 110, so there’ll be a hard cut-off—notes above MIDI 55 will have a velocity of 70 and those < 18 will have 110. Note that we do randomise/humanise the velocities by 10% for a less mechanical feeling (assuming your synth/sampler will distinguish significantly there); also that get-degree will return an average for chords.

    (midi-play +jitterbug+ :force-velocity
               #'(lambda (event)
                   (let* ((d (get-degree event :average t))
                          (v (when d
                                 (min 110 (max 70 (- 127 d)))
                     (format t “~&~a –> ~a” d v)
compose new post
next post/next comment
previous post/previous comment
show/hide comments
go to top
go to login
show/hide help
shift + esc