All posts by Michael Edwards

Born Cheshire, England, 1968. Studied oboe then composition at Bristol University with Adrian Beaumont (1986-91); privately with Gwyn Pritchard; and computer music with John Chowning at CCRMA, Stanford University (1991-96). Consultant software engineer in Silicon Valley (1996-97); Guest Professor at the Universität Mozarteum Salzburg (1997-2002); currently Reader at the University of Edinburgh. Compositional interests lie in the development of algorithmic composition structures for instrumental music and the integration of these within similarly generated computer-processed sound structures and live electronics. Also active as an improvisor on laptop, saxophones, and MIDI wind controller.

Music XML output on its way Been working…

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)

With the demise of the extended version of…

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.

When creating rthm seq palettes you can add…

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

Apropos the symposium decision to make some short…

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)
                                 events+))))
  (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)
                     events+))))
  (setf events+ (reverse events+))
  (events-update-time events+)
  (event-list-to-midi-file events+ :start-tempo 450))

The first functionality update that arose out of…

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.

velocity-tweaked robot pianos

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.

 

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

Marcin was asking about initialising set palettes from…

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)
       sp)
  sp)

Dan’s advice is to keep Disklavier velocities to…

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
;;; 
;;; DESCRIPTION
;;; Given a value within an original range, return its value withing a new range
;;; 
;;; ARGUMENTS
;;; - the value we want to rescale
;;; - the original minimum
;;; - the original maximum
;;; - the new minimum
;;; - the new maximum
;;; 
;;; RETURN VALUE
;;; 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))))

Some of you will already know the rm…

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 …)

If you who read facebook slippery chicken group…

pedal

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.

Some of you might be interested in the…

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
                           (round
                            (randomise 
                             (min 110 (max 70 (- 127 d)))
                             10)))))
                 (format t “~&~a –> ~a” d v)
                 v)))

I have never quite been able to separate…

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