module Bang.Interpreter where

import Bang.Music.Class
import Bang.Interface.Drum

import System.MIDI
import Data.Bifunctor
import Data.Ratio
import Data.Monoid


toList :: Music Dur PercussionSound -> [MidiEvent]
toList m = map drumToMidiEvent (interpret m)

merge :: Ord d => [Primitive d a] -> [Primitive d a] -> [Primitive d a]
merge [] ys = ys
merge xs [] = xs
merge (a:xs) (b:ys)
  | dur a <= dur b = a : merge xs (b:ys)
  | otherwise = b : merge (a:xs) ys

interpret :: Music Dur PercussionSound -> [Primitive Dur PercussionSound]
interpret = go 0
  where go d (a :+: b) = go d a `mappend` go (d + duration a) b
        go d (a :=: b) = go d a `merge`   go d b
        go d (Prim n@(Note _ _))       = [n{dur = d}]
        go d (Prim n@(Rest _))         = []
        go d (Modify (Tempo a) m)      = go d (first (*a) m)
        go d (Modify (BPM n)   m)      = go d (first (* (240000 % n)) m) -- breaks down when bpm has already been set
        go d (Modify (Instrument _) m) = go d m -- @TODO