module Bang(
bang
, bangR
, bangWith
, bangRWith
, Options(..)
, defaultOptions
, module Bang.Music
, module Bang.Interface
) where
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.State
import Control.Concurrent
import Data.Monoid
import System.MIDI
import Bang.Music
import Bang.Interface
import Bang.Interpreter
data Options = Options {
o_bpm :: Integer,
o_tempo :: Dur
} deriving (Show, Eq)
defaultOptions :: Options
defaultOptions = Options{ o_bpm = 120, o_tempo = 1 }
bang :: Music Dur PercussionSound -> IO ()
bang = bangWith defaultOptions
bangR :: Music Dur PercussionSound -> IO ()
bangR = bangRWith defaultOptions
bangRWith :: Options -> Music Dur PercussionSound -> IO ()
bangRWith opts = bangWith opts . mconcat . repeat
bangWith :: Options -> Music Dur PercussionSound -> IO ()
bangWith opts song = do
dstlist <- enumerateDestinations
case dstlist of
[] -> fail "No MIDI Devices found."
(dst:_) -> do
name <- getName dst
putStrLn $ "Using MIDI device: " ++ name
conn <- openDestination dst
playWith opts conn song
playWith :: Options -> Connection -> Music Dur PercussionSound -> IO ()
playWith (Options oBpm oTempo) conn song = do
start conn
evalStateT runComposition (conn, interpret (bpm oBpm $ tempo oTempo song))
close conn
play :: Connection -> Music Dur PercussionSound -> IO ()
play conn song = do
start conn
evalStateT runComposition (conn, interpret song)
close conn
runComposition :: StateT (Connection, [Primitive Dur PercussionSound]) IO ()
runComposition = do
(conn, evs) <- get
t <- lift $ currentTime conn
case evs of
[] -> return ()
(e@(Note _ _):xs) -> do
let x@(MidiEvent s ev) = drumToMidiEvent e
when (s < t) $ do
put (conn, xs)
lift $ send conn ev
lift $ threadDelay 1000
runComposition