diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,22 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
-## 0.3.0 - 2017-06-10
+<!-- ## [Unreleased](https://github.com/DimaSamoz/mezzo/compare/v0.3.1...HEAD) -->
+
+## [0.3.1 - 2017-10-07](https://github.com/DimaSamoz/mezzo/releases/tag/v0.3.1)
+### Added
+- Live playback on the terminal: Mezzo compositions can now be played back live from the terminal using an external midi synthesiser (e.g. [SimpleSynth](http://notahat.com/simplesynth/)) and [Euterpea](http://www.euterpea.com/).
+- Empty cadences: you can use `end` as a cadential phrase to compose a chord progression without a cadence.
+- Score transformation: you can use the functions such as `delay` and `transpose` to manipulate music at the MIDI track level. While this allows for more flexibility, composition of `Score`s is not rule-checked, so there is no static guarantee that the resulting music will sound good.
+
+### Changed
+- The melody constructor `play` has been renamed to `start`.
+
+### Fixed
+- Readme typos and rule set changes in examples.
+- Clashes with Prelude's `min` function.
+
+## [0.3.0 - 2017-06-16](https://github.com/DimaSamoz/mezzo/releases/tag/v0.3.0)
 ### Added
 - Chord progressions: create chord progressions following the conventions of functional harmony.
 - Dyads: 2-note chords (thirds, fourths, fifths and octaves), together with their doubled versions.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -4,8 +4,6 @@
 
 *Mezzo* is a Haskell library and embedded domain-specific language for music description. Its novelty is in the fact that it can enforce various rules of music composition *statically*, that is, at compile-time. This effectively means that if you write "bad" music, your composition will not compile – think of it as a **very** strict spell-checker for music.
 
-<!-- TOC depthFrom:2 depthTo:6 withLinks:1 updateOnSave:1 orderedList:0 -->
-
 - [Getting started](#getting-started)
 	- [Prerequisites](#prerequisites)
 	- [Installation](#installation)
@@ -37,8 +35,6 @@
 - [License](#license)
 - [Acknowledgments](#acknowledgments)
 
-<!-- /TOC -->
-
 ## Getting started
 
 This section explains how to install Mezzo and start using the library.
@@ -60,7 +56,7 @@
 If using Stack, you will need to add the package to your `extra-deps` in your `stack.yaml` (as Mezzo is not part of Stackage yet), and then add it normally to your `.cabal` file dependencies:
 
 ```cabal
-extra-deps: [ mezzo-0.3.0.0 ]
+extra-deps: [ mezzo-0.3.1.0 ]
 
 build-depends: base >= 4.7 && < 5
              , mezzo
@@ -76,10 +72,10 @@
 ```haskell
 import Mezzo
 
-comp = defScore $ play $ melody :| c :| d :| e :| f :>> g
+comp = defScore $ start $ melody :| c :| d :| e :| f :>> g
 
 main :: IO ()
-main = renderMusic "comp.mid" comp
+main = renderScore "comp.mid" "First composition" comp
 ```
 
 Save, build and execute (e.g. with `stack exec <project_name>`). You should get a `.mid` file in the project directory which looks something like this:
@@ -123,7 +119,7 @@
 * **Accidental**: a suffix of the pitch class, one of `f` (flat, e.g. `bf qn`) or `s` (sharp, e.g. `fs qn`). Natural accidentals are not specified, so `c` means C natural. Accidentals can also be written out as a separate attribute (`c sharp qn`), or even repeated (for example, double sharps: `c sharp sharp qn` or `cs sharp qn`).
 * **Octave**: the last component of the value. The default octave is 4, this is unmarked. Lower octaves are marked with `_`, `__`, `_3`, `_4` and `_5`. Higher octaves are marked with `'`, `''`, `'3` and `'4`. A C natural in octave 2 is therefore `c__ qn`, a B flat in octave 7 is `bf'3 qn`.
 
-Durations are written after the pitch. For notes, the value is the first letter of the duration name (eighth, quarter, etc.) followed by `n` for note, e.g., `qn` for quarter note. A dotted duration is specified by following the name with a `'`: `hn'` is a dotted half note, with the length of three quarters.
+Durations are written after the pitch. For notes, the value is the first letter of the duration name (eighth, quarter, etc.) followed by `n` for note, e.g., `qn` for quarter note. A dotted duration is specified by following the name with a `'` (single quote):  `hn'` is a dotted half note, with the length of three quarters.
 
 #### Rests
 
@@ -210,10 +206,10 @@
 Mezzo provides a more concise way of melody input, where only the duration changes are explicit:
 
 ```haskell
-play $ melody :| c :< c :| d :| ef :| d :| c :| b_ :> c :| c
+start $ melody :| c :< c :| d :| ef :| d :| c :| b_ :> c :| c
 ```
 
-Melodies are effectively lists of pitches with the constructors specifying the duration of the next pitch. All melodies have to start with the `melody` keyword – which initialises the melody and set the "default" duration to a quarter note – and a melody can be converted into a playable `Music` value with the `play` function. The constructors can be used as follows:
+Melodies are effectively lists of pitches with the constructors specifying the duration of the next pitch. All melodies have to start with the `melody` keyword – which initialises the melody and set the "default" duration to a quarter note – and a melody can be converted into a playable `Music` value with the `start` function. The constructors can be used as follows:
 
 * `(:|)`: the next note has the same duration as the previous one. For example, `melody :| c :| d :| e` creates a melody of 3 quarter notes (since `melody` initialises the duration to a quarter note).
 * `(:<<<)`, `(:<<)`, `(:<)`, `(:^)`, `(:>)` and `(:>>)`: the next note is a thirty-second, sixteenth, eighth, quarter, half or whole note, respectively.
@@ -222,6 +218,7 @@
 * All constructors that change the duration (except `(:<<<)` and `(:~<<<)`) can be followed by a `.` to make the duration dotted. For example, `melody :^ c :^. d :> e` specifies a melody of a quarter note, a dotted quarter note and a half note.
 
 Below is a table summarising the melody construction operators.
+(See the [https://github.com/DimaSamoz/mezzo/blob/master/README.md](GitHub README) if the table is not formatted.)
 
 | Duration      | Note  | Rest  | Dotted note | Dotted rest |
 |---------------|-------|-------|-------------|-------------|
@@ -239,10 +236,10 @@
 * Frère Jacques:
 
 ```haskell
-fj1 = play $ melody :| g :| a :| b :| g
-fj2 = play $ melody :| b :| c' :> d'
-fj3 = play $ melody :< d' :| e' :| d' :| c' :^ b :| g
-fj4 = play $ melody :| g :| d :> g
+fj1 = start $ melody :| g :| a :| b :| g
+fj2 = start $ melody :| b :| c' :> d'
+fj3 = start $ melody :< d' :| e' :| d' :| c' :^ b :| g
+fj4 = start $ melody :| g :| d :> g
 
 fj = defScore $ fj1 :|: fj1 :|: fj2 :|: fj2 :|: fj3 :|: fj3 :|: fj4 :|: fj4
 ```
@@ -250,8 +247,8 @@
 * Jingle Bells:
 
 ```haskell
-p1 = play $ melody :< e :| e :^ e :< e :| e :^ e :< e :| g :<. c :<< d :>> e
-p2 = play $ melody :< f :| f :<. f :<< f :< f :| e :<. e :<< e :< e :| d :| d :| e :^ d :| g
+p1 = start $ melody :< e :| e :^ e :< e :| e :^ e :< e :| g :<. c :<< d :>> e
+p2 = start $ melody :< f :| f :<. f :<< f :< f :| e :<. e :<< e :< e :| d :| d :| e :^ d :| g
 
 jb = defScore $ p1 :|: p2
 ```
@@ -298,6 +295,7 @@
     * `auth_64_V7_I`: an authentic dominant cadence with a cadential 6-4.
     * `decept_V_iv`: a deceptive V-iv cadence.
     * `full sd c`: a full cadence, consisting of a subdominant region and a cadence.
+    * `end`: empty cadence.
 
 The example above therefore has a tonic-dominant-tonic region, followed by a full cadence with a fourth degree subdominant and authentic dominant cadence. The `prog` keyword converts a schema into a `Music` value.
 
@@ -354,11 +352,18 @@
 If a piece is broken up into smaller scores (sections), all of them can be concatenated and rendered using the `renderScores` function:
 
 ```haskell
-renderScore :: FilePath -> Title -> [Score] -> IO ()
+renderScores :: FilePath -> Title -> [Score] -> IO ()
 ```
 
 This is similar to `renderScore`, but takes a list of `Score`s (in the desired order). Note that this allows for reuse of sections: for example, a refrain (or repeated section) only has to be described once, and the score created from it can be reused without any additional rule-checking. See the Für Elise example for a demonstration.
 
+Mezzo compositions can be played live, from the terminal, using the function
+
+```haskell
+playLive' :: Score -> IO ()
+```
+You can also use `playLive = playLive' . defScore` to play a `Music` value right away. Note that in order to play Mezzo compositions from the terminal, you need to have an appropriate MIDI device (e.g. synthesiser) configured. As the implementation uses Euterpea's playback features, you should set up the configuration following [these](http://www.euterpea.com/euterpea/setting-up-midi/) instructions.
+
 ## Rule sets
 As different musical genres enforce different kinds of rules, Mezzo lets users select different levels of strictness (called *rule sets*) or even completely customise the musical rules that are checked. In particular, one rule set turns off correctness checking completely, allowing for complete creative freedom.
 
@@ -476,7 +481,9 @@
 
 ## License
 
-This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
+This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.
+
+Note that this project is different from [Mezzo](http://protz.github.io/mezzo/), a research language for effectful concurrent programming.
 
 ## Acknowledgments
 
diff --git a/mezzo.cabal b/mezzo.cabal
--- a/mezzo.cabal
+++ b/mezzo.cabal
@@ -1,5 +1,5 @@
 name:                mezzo
-version:             0.3.0.0
+version:             0.3.1.0
 synopsis:            Typesafe music composition
 description:         A Haskell music composition library that enforces common
                      musical rules in the type system.
@@ -46,13 +46,15 @@
                      , Mezzo.Render
                      , Mezzo.Render.MIDI
                      , Mezzo.Render.Score
-
+                     , Mezzo.Render.Transform
+                     
   build-depends:       base >= 4.7 && < 5
                      , ghc-typelits-natnormalise
                      , template-haskell
                      , HCodecs
                      , boxes
                      , ghc-prim
+                     , Euterpea
   ghc-options:         -fplugin GHC.TypeLits.Normalise
   default-language:    Haskell2010
   default-extensions:  TypeInType
diff --git a/src/Mezzo.hs b/src/Mezzo.hs
--- a/src/Mezzo.hs
+++ b/src/Mezzo.hs
@@ -1,4 +1,4 @@
-
+{-# LANGUAGE NoImplicitPrelude #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Mezzo
@@ -15,6 +15,7 @@
 -----------------------------------------------------------------------------
 
 module Mezzo (module X, ($), (++), concat) where
+import Prelude (($), (++), concat)
 
 -- Uses import/export shortcut as suggested by HLint.
 
diff --git a/src/Mezzo/Compose/Chords.hs b/src/Mezzo/Compose/Chords.hs
--- a/src/Mezzo/Compose/Chords.hs
+++ b/src/Mezzo/Compose/Chords.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TemplateHaskell, NoImplicitPrelude #-}
 
 -----------------------------------------------------------------------------
 -- |
diff --git a/src/Mezzo/Compose/Combine.hs b/src/Mezzo/Compose/Combine.hs
--- a/src/Mezzo/Compose/Combine.hs
+++ b/src/Mezzo/Compose/Combine.hs
@@ -28,7 +28,7 @@
     , pad3
     , pad4
     -- * Melody composition
-    , play
+    , start
     , melody
     -- * Textures
     , hom
@@ -123,31 +123,31 @@
 -------------------------------------------------------------------------------
 
 -- | Convert a melody (a sequence of notes and rests) to `Music`.
-play :: (Primitive d) => Melody s m d -> Music s m
-play m@(ps :| p)    = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :<<< p)  = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :<< p)   = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :< p)    = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :^ p)    = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :> p)    = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :>> p)   = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :<<. p)  = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :<. p)   = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :^. p)   = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :>. p)   = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :>>. p)  = case ps of Melody -> mkMelNote m p ; ps' -> play ps' :|: mkMelNote m p
-play m@(ps :~| p)   = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~<<< p) = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~<< p)  = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~< p)   = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~^ p)   = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~> p)   = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~>> p)  = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~<<. p) = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~<. p)  = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~^. p)  = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~>. p)  = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
-play m@(ps :~>>. p) = case ps of Melody -> mkMelRest m ; ps' -> play ps'   :|: mkMelRest m
+start :: (Primitive d) => Melody s m d -> Music s m
+start m@(ps :| p)    = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :<<< p)  = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :<< p)   = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :< p)    = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :^ p)    = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :> p)    = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :>> p)   = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :<<. p)  = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :<. p)   = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :^. p)   = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :>. p)   = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :>>. p)  = case ps of Melody -> mkMelNote m p ; ps' -> start ps' :|: mkMelNote m p
+start m@(ps :~| p)   = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~<<< p) = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~<< p)  = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~< p)   = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~^ p)   = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~> p)   = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~>> p)  = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~<<. p) = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~<. p)  = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~^. p)  = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~>. p)  = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
+start m@(ps :~>>. p) = case ps of Melody -> mkMelRest m ; ps' -> start ps'   :|: mkMelRest m
 
 -- | Make a note of suitable duration from a root specifier.
 mkMelNote :: (IntRep r, Primitive d, ValidNote s r d) => Melody s m d -> RootS r -> Music s (FromRoot r d)
@@ -173,7 +173,7 @@
 hom = Homophony
 
 melAccomp :: (s ~ (Sig :: Signature t k r), ValidProg r t p, pm ~ FromProg p t, ValidHom s m pm, Primitive d) => Melody s m d -> InKey k (PhraseList p) -> Music s (m +-+ pm)
-melAccomp m p = Homophony (play m) (prog p)
+melAccomp m p = Homophony (start m) (prog p)
 
 -------------------------------------------------------------------------------
 -- Triplets
diff --git a/src/Mezzo/Compose/Harmony.hs b/src/Mezzo/Compose/Harmony.hs
--- a/src/Mezzo/Compose/Harmony.hs
+++ b/src/Mezzo/Compose/Harmony.hs
@@ -92,6 +92,10 @@
 full :: InKey k (Sub s) -> InKey k (Cad c) -> InKey k (Cad (FullCad s c))
 full _ _ = const Cad
 
+-- | End progression without an explicit cadence.
+end :: InKey k (PhraseList (CadPhrase NoCad))
+end = cadence $ const Cad
+
 -- ** Tonic chords
 
 -- | Tonic chord.
diff --git a/src/Mezzo/Model/Harmony/Functional.hs b/src/Mezzo/Model/Harmony/Functional.hs
--- a/src/Mezzo/Model/Harmony/Functional.hs
+++ b/src/Mezzo/Model/Harmony/Functional.hs
@@ -137,6 +137,8 @@
     DeceptCad  :: DegreeC V DomQ k Inv2 o -> DegreeC VI q k Inv1 o -> Cadence k 2
     -- | Full cadence from subdominant to dominant to tonic.
     FullCad    :: Subdominant k l1 -> Cadence k (l - l1) -> Cadence k l
+    -- | No cadence.
+    NoCad      :: Cadence k 0
 
 -- | A tonic chord.
 data Tonic (k :: KeyType) (l :: Nat) where
@@ -182,6 +184,7 @@
     CadToChords 2 (DeceptCad d1 d2)    = DegToChord d1 :-- DegToChord d2 :-- None
     CadToChords 3 (AuthCad64 d1 d2 d3) = DegToChord d1 :-- DegToChord d2 :-- DegToChord d3 :-- None
     CadToChords l (FullCad (s :: Subdominant k l1) c) = SubdomToChords l1 s ++. CadToChords (l - l1) c
+    CadToChords 0 NoCad                = None
 
 -- | Convert a tonic to chords.
 type family TonToChords (l :: Nat) (t :: Tonic k l) :: Vector (ChordType 4) l where
@@ -355,6 +358,11 @@
     type Rep (FullCad sd c) = [[Int]]
     prim _ = prim (Sub @k @sdur @sd) ++ prim (Cad @k @(l - sdur) @c)
     pretty _ = pretty (Sub @k @sdur @sd) ++ " | " ++ pretty (Cad @k @(l - sdur) @c)
+
+instance Primitive NoCad where
+    type Rep NoCad = [[Int]]
+    prim _ = []
+    pretty _ = "NoCad"
 
 -- Phrases
 
diff --git a/src/Mezzo/Render.hs b/src/Mezzo/Render.hs
--- a/src/Mezzo/Render.hs
+++ b/src/Mezzo/Render.hs
@@ -20,3 +20,4 @@
 
 import Mezzo.Render.MIDI as X
 import Mezzo.Render.Score as X
+import Mezzo.Render.Transform as X
diff --git a/src/Mezzo/Render/MIDI.hs b/src/Mezzo/Render/MIDI.hs
--- a/src/Mezzo/Render/MIDI.hs
+++ b/src/Mezzo/Render/MIDI.hs
@@ -17,7 +17,8 @@
 -----------------------------------------------------------------------------
 
 module Mezzo.Render.MIDI
-    (renderScore, renderScores, withMusic, defScore )
+    ( MidiNote (..), Score, (><)
+    , renderScore, renderScores, withMusic, defScore, playLive, playLive' )
     where
 
 import Mezzo.Model
@@ -28,6 +29,9 @@
 
 import Codec.Midi hiding (key, Key)
 import qualified Codec.Midi as CM (key, Key)
+import Euterpea.IO.MIDI.Play (playM')
+import Euterpea.IO.MIDI.MidiIO (unsafeOutputID)
+import Prelude hiding (min)
 
 -------------------------------------------------------------------------------
 -- Types
@@ -37,7 +41,7 @@
 data MidiNote = MidiNote
     { noteNum :: Int        -- ^ MIDI number of a note (middle C is 60).
     , vel     :: Velocity   -- ^ Performance velocity of the note.
-    , start   :: Ticks      -- ^ Relative start time of the note.
+    , startT  :: Ticks      -- ^ Relative start time of the note.
     , noteDur :: Ticks      -- ^ Duration of the note.
     } deriving Show
 
@@ -56,18 +60,18 @@
 
 -- | Play a MIDI note with the specified duration and default velocity.
 midiNote :: Int -> Ticks -> MidiNote
-midiNote root dur = MidiNote {noteNum = root, vel = 100, start = 0, noteDur = dur}
+midiNote root dur = MidiNote {noteNum = root, vel = 100, startT = 0, noteDur = dur}
 
 midiRest :: Ticks -> MidiNote
-midiRest dur = MidiNote {noteNum = 60, vel = 0, start = 0, noteDur = dur}
+midiRest dur = MidiNote {noteNum = 0, vel = 0, startT = 0, noteDur = dur}
 
 -- | Start playing the specified 'MidiNote'.
 keyDown :: MidiNote -> MidiEvent
-keyDown n = (start n, NoteOn {channel = 0, CM.key = noteNum n, velocity = vel n})
+keyDown n = (startT n, NoteOn {channel = 0, CM.key = noteNum n, velocity = vel n})
 
 -- | Stop playing the specified 'MidiNote'.
 keyUp :: MidiNote -> MidiEvent
-keyUp n = (start n + noteDur n, NoteOn {channel = 0, CM.key = noteNum n, velocity = 0})
+keyUp n = (startT n + noteDur n, NoteOn {channel = 0, CM.key = noteNum n, velocity = 0})
 
 -- | Play the specified 'MidiNote'.
 playNote :: Int -> Ticks -> MidiTrack
@@ -151,3 +155,12 @@
 -- | Create a MIDI file with the specified path, title and list of scores.
 renderScores :: FilePath -> Title -> [Score] -> IO ()
 renderScores f compTitle ts = renderScore f compTitle (concat ts)
+
+-- | Live playback of a Mezzo score.
+playLive' :: Score -> IO ()
+playLive' s = playM' (Just $ unsafeOutputID 0) $ midiSkeleton "Live playback" s
+
+-- | Live playback of a Mezzo piece with default score attributes.
+playLive :: Music (Sig :: Signature 4 (Key C Natural MajorMode) Classical) m
+         -> IO ()
+playLive m = playLive' (defScore m)
diff --git a/src/Mezzo/Render/Score.hs b/src/Mezzo/Render/Score.hs
--- a/src/Mezzo/Render/Score.hs
+++ b/src/Mezzo/Render/Score.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE RecordWildCards, NoImplicitPrelude #-}
 
 -----------------------------------------------------------------------------
 -- |
@@ -43,6 +43,7 @@
 import Codec.Midi hiding (key, Key)
 import qualified Codec.Midi as CM (key, Key)
 import qualified GHC.TypeLits as GT
+import Prelude hiding (min)
 
 -------------------------------------------------------------------------------
 -- Attributes
diff --git a/src/Mezzo/Render/Transform.hs b/src/Mezzo/Render/Transform.hs
new file mode 100644
--- /dev/null
+++ b/src/Mezzo/Render/Transform.hs
@@ -0,0 +1,77 @@
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Mezzo.Render.Transform
+-- Description :  Score-level transformations
+-- Copyright   :  (c) Dima Szamozvancev
+-- License     :  MIT
+--
+-- Maintainer  :  ds709@cam.ac.uk
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Functions and combinators for transforming Scores. Allows for more flexibility,
+-- but no static correctness guarantees.
+--
+-----------------------------------------------------------------------------
+
+module Mezzo.Render.Transform
+    (transpose, delay, (><), (+++), flatten, reprise, cascade, scale, volta)
+    where
+
+import Mezzo.Render.Score
+import Mezzo.Render.MIDI
+
+import Codec.Midi hiding (key, Key)
+import qualified Codec.Midi as CM (key, Key)
+import Prelude hiding (min)
+import Control.Arrow (first, second)
+
+-- | Transpose a single MIDI message by the given number of semitones.
+transposeMessage :: Int -> Message -> Message
+transposeMessage t (NoteOff ch key vel) = NoteOff ch (key + t) vel
+transposeMessage t (NoteOn ch key vel) = NoteOn ch (key + t) vel
+transposeMessage _ m = m
+
+-- | Transpose a score by the given number of semitones.
+transpose :: Int -> Score -> Score
+transpose n = map (second (transposeMessage n))
+
+-- | Delay a score by the given number of ticks (60ths of a thirty-second note).
+delay :: Ticks -> Score -> Score
+delay ticks (n@(_, NoteOn{}) : rest) =
+    [ (0, NoteOn {channel = 0, CM.key = 60, velocity = 0})
+    , (ticks, NoteOn {channel = 0, CM.key = 60, velocity = 0})
+    ] ++ n : rest
+delay ticks (m : rest) = m : delay ticks rest
+
+-- | Remove the attribute MIDI messages in the score header.
+stripHeader :: Score -> Score
+stripHeader [] = []
+stripHeader (n@(_, NoteOn{}) : rest) = n : rest
+stripHeader (_ : rest) = stripHeader rest
+
+-- | Concatenation of scores.
+(+++) :: Score -> Score -> Score
+s1 +++ s2 = s1 ++ stripHeader s2
+
+-- | Flatten a list of scores into a single score.
+flatten :: [Score] -> Score
+flatten = foldr (+++) []
+
+-- | Repeat a score the given number of times.
+reprise :: Int -> Score -> Score
+reprise n = flatten . replicate n
+
+-- | Repeat the score, successively applying the function to each repetition.
+-- cascade 4 f s = s +++ f s +++ f (f s) +++ f (f (f s))
+cascade :: Int -> (Score -> Score) -> Score -> Score
+cascade n f = flatten . take n . iterate f
+
+-- | Create a scale of the given length and interval between scores.
+scale :: Int -> Int -> Score -> Score
+scale l i = cascade l (transpose i)
+
+-- | Repeat the score with the different endings at each repetition.
+volta :: Score -> [Score] -> Score
+volta s vs = flatten $ map (s +++) vs
