Skip to content

harryaskham/funktor

master
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?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
app
 
 
 
 
 
 
src
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

funktor

Overview

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 <-
      sequence
      $ 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

Design

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)

Requirements

  • stack or cabal
  • csound 6.17 or 6.14

Running

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

About

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

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published