Updates from Michael Edwards Toggle Comment Threads | Keyboard Shortcuts

  • Michael Edwards 15:53 on March 27, 2017 Permalink | Reply
    Tags: musicxml,   

    Music XML output on its way. Been working really hard on this in my spare time for the past couple of weeks. Coupled with lilypond editing fatigue and a prod from Charles Gaskell I bit the bullet and wrote the code for this after looking at it again and deciding that it’s probably now worth it. Each bit of software seems to fail in its own way when importing XML, but finale seems to be pretty good. Just imported 90k+ lines of xml without error for the first time šŸ™‚ (that’s about 100 times more code than Lilypond)

  • Michael Edwards 14:31 on February 13, 2017 Permalink | Reply
    Tags: wiki   

    If you haven’t seen it already I’m increasingly using a wiki to share code snippets and bits of knowledge in the form of a HOWTO: http://michael-edwards.org/sc/dw/

  • Michael Edwards 11:27 on November 10, 2016 Permalink | Reply
    Tags: MaxMSP, PD, PD Vanilla, Pure Data, qlist,   

    With the demise of the extended version of Pure Data, we’ve lost the seq object for reading/playing MIDI files. I know there are alternative libraries out there but I would like to play a MIDI file in PD for teaching purposes. Sequencing in PD vanilla is really done with the qlist object, which I love, though I do find it a little frustrating that PD can’t handle reading that most standard of files, the MIDI file. On a more positive note, qlist is also available in Max so it’s a really handy object/format in both environments.

    Anyway, I’ve just added a new function (midi2qlist) to slippery chicken that converts from a MIDI file to a qlist text file format. I’ve tried it with a few different MIDI files and it seems to be working fine, but it wouldn’t hurt if other people took a poke. You can get the code via (update-app-src …) or from the svn-latest tag on the svn server.

    • Dan 11:42 on November 10, 2016 Permalink | Reply

      What’s the function called?

      • Michael Edwards 18:27 on January 27, 2017 Permalink | Reply

        Sorry i missed this dan as I always love to send you an RTFM: first line of 2nd para: midi2qlist

  • Michael Edwards 15:45 on October 28, 2016 Permalink | Reply
    Tags: graphics, , marks   

    For those of you interested in creating Lilypond scores via slippery chicken that use your own graphics files as marks, see the latest addition to the wiki: http://michael-edwards.org/sc/dw/doku.php?id=examples:graphics_files_as_marks

  • Michael Edwards 12:47 on August 27, 2016 Permalink | Reply
    Tags: rthm-seqs,   

    When creating rthm-seq-palettes you can add empty bars with the requisite number of rests but the easiest thing to do is simply leave them blank:

    (5 ((1 ((((3 4) { 7 (28/3) - 28/3 x 6 - })
             ((2 4) (q) g e (e)) ()
             ((5 8)))))))

    Note that two empty bars are created there: the first by a simple empty list: (), the second by a change of time signature followed by no rhythms ((5 8))

  • 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.

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

  • 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.

  • 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

  • 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.

  • 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!

  • 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)
  • Michael Edwards 09:58 on May 20, 2016 Permalink | Reply
    Tags: lachenmann, nono,   

    I have never quite been able to separate my sadness at the loss of Luigi Nono from a feeling of greater awareness, of happiness and gratitude that he ever existed—and ever existed in our proximity. And despite the loneliness which I share with so many others who loved him, I feel, when I think of him, a unique sense of the triumph of art and a hope that its restless force will endure in times of apparent hopelessness.

    Helmut Lachenmann
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