Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time



An opinionated music construction playground build on top of the excellent csound-expression library.

Quick Example

A quick and dirty example song highlighting:

  • Stochastic note generation
  • Drum tab DSL
  • Applicative melody construction

Doesn't sound great, mostly here for didactic purposes! The src directory contains other songs as modules.

Link to a .wav compiled from the below. GitHub doesn't seem to want to stream this, so Save As... if you want to hear it.

song :: SongM
song = do
  -- 4 on the floor bass drum, on for 16 beats, off for 16 beats
  kicks <- do
    d <- drums "X _ _ _|O _ _ _|O _ _ _|O _ _ _" Tr808.bd2
    env <- sqrEnvM 0 16
    return (d & withEnv env)

  -- Closed hats, always on
  cHats <- drums "X O o ." Tr808.chh

  -- Open hats, always on
  oHats <- drums "o _ o _|_ _ o _" Tr808.ohh

  -- Group the drums
  let drms = har [kicks, cHats, oHats]

  -- Bassline - 5 notes from two chords at 2/3 velocity every 4 beats
  bass <- do
    let notes = take 5 $ minorChord D ++ reverse (majorChord Bb)
    compileI (withDeepBass 1.0 fmBass1) $ Pch <$> notes ?? 6 ?? (2/3) ?? 4

  -- Take 16 random notes from D minor, over 3 octaves, with some notes silent.
  lead <- do
    notes <-
      $ replicate 16 randomFrom
      ?? expandScale [7, 8, 9] (minorScale D) ++ replicate 10 (\_ _ -> Silent (1/2))
    compileI razorLead $ notes ?? (1/2) ?? (1/2)

  -- Add some reverb FX to the instrs
  let instrs = har [ rever2 0.5 <$> bass
                   , rever2 0.2 <$> lead

  -- Play all the above at once
  return $ drms =:= instrs

-- Set BPM and track length
songEnv :: SongEnv
songEnv = SongEnv { _bpm=140
                  , _beatLength=64

To play the song in real-time e.g. in GHCi:

dac =<< runSongM songEnv song

Or to compile to a WAV:

runToDisk =<< runSongM songEnv song


Follows mtl style, where a song is represented by a SongM monad transformer stack combining various effects useful for music creation:

  • RandT for stochastic music generation
  • IOT for loading samples, other external files
  • ReaderT pattern over a song environment governing BPM and duration
  • SE as the base monad (this is the csound-expression side-effecting monad)
data SongEnv = SongEnv { _bpm :: Bpm
                       , _beatLength :: Int
type SongT = ReaderT SongEnv (RandT StdGen (IOT SE))
type SongM = SongT (Seg Sig2)


  • stack or cabal
  • csound 6.17 or 6.14


  • stack ghci or cabal repl should both drop into GHCI
  • nix-shell will enable e.g. cabal --enable-nix repl or cabal --enable-nix run
  • Began as a stack project but Cabal/Nix seem better supported on M1 macs so I'll probably remove Stack and go Cabal-only if I need to introduce new deps. For now it should run as either Cabal or Stack as I haven't made any configuration changes for a while.


Opinionated music creation in Haskell built on top of csound-expression







No releases published


No packages published