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)
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 :: Int -> Score -> Score
transpose n = map (second (transposeMessage n))
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
stripHeader :: Score -> Score
stripHeader [] = []
stripHeader (n@(_, NoteOn{}) : rest) = n : rest
stripHeader (_ : rest) = stripHeader rest
(+++) :: Score -> Score -> Score
s1 +++ s2 = s1 ++ stripHeader s2
flatten :: [Score] -> Score
flatten = foldr (+++) []
reprise :: Int -> Score -> Score
reprise n = flatten . replicate n
cascade :: Int -> (Score -> Score) -> Score -> Score
cascade n f = flatten . take n . iterate f
scale :: Int -> Int -> Score -> Score
scale l i = cascade l (transpose i)
volta :: Score -> [Score] -> Score
volta s vs = flatten $ map (s +++) vs