{-|
Module      : Bang.Music.Operators
Description : The DSL part of the Bang library
Copyright   : (c) Benjamin Kovach, 2014
License     : MIT
Maintainer  : bkovach13@gmail.com
Stability   : experimental
Portability : Mac OSX

Defines a number of operators to effectively piece together Bang compositions.
-}
module Bang.Music.Operators where

import Bang.Music.Class
import Bang.Music.Transform
import Bang.Interface.Base
import Data.Foldable(foldMap)

import Data.Monoid

-- |Infix operator for `cappend`
infixr 6 ><
(><) :: Music dur a -> Music dur a -> Music dur a
(><) = cappend

infixr 0 !>
-- |Set the `Tempo` of a composition (default 1)
-- 
--  Example (play 4 bass drum hits at double speed):
--
-- > 2 !> (4 #> bd)
(!>) :: Rational -> Music a b -> Music a b
(!>) = tempo

infixr 1 #>
-- |Infix operator for 'repl'
--
-- Example (play a bass drum twice):
--
-- > 2 #> bd
(#>) :: Num a => Int -> Music a b -> Music a b
(#>) = repl

infixl 1 >>~
-- |Map a function over a list of compositions and sequentially compose them.
-- Note: This is just 'foldMap' specialized to the list Monoid.
--
-- Example (play 'sn', 't1' and 't2' all twice): 
--
-- > (2 #>) >>~ [sn, t1, t2]
(>>~) :: Monoid b => (a -> b) -> [a] -> b
(>>~) = foldMap

-- |Infix operator for 'poly'
-- 
-- Example (A 3\/4 polyrhythm):
--
-- > (3, 3 #> bd) ~=~ (4, 4 #> sn)
(~=~) :: (Dur, Music Dur b) -> (Dur, Music Dur b) -> Music Dur b
(~=~) = poly

infixl 2 ~=
-- |Infix operator for 'fitL'
--
-- Example (a 3\/4 polyrhythm with duration 3\/4):
-- 
-- > (3 #> bd) ~= (4 #> sn)
(~=) :: Music Dur b -> Music Dur b -> Music Dur b
(~=) = fitL

infixr 2 =~
-- |Infix operator for 'fitR'
-- 
-- Example (a 3\/4 polyrhythm with duration 1:
-- 
-- > (3 #> bd) =~ (4 #> sn)
(=~) :: Music Dur b -> Music Dur b -> Music Dur b
(=~) = fitR

infixr 2 ~~
-- |Infix operator for 'withDuration'
--
-- Example:
--
-- @
-- 2 ~~ mconcat [
--    16 #> bd
--  , 4 #> sn
--  , wr
--  ]
-- @
(~~) :: Dur -> Music Dur b -> Music Dur b
(~~) = withDuration

infixr 2 <<~
-- |Infix operator for 'takeDur'
--
-- Example (Only play 2 bass drum hits):
-- 
-- > (1/2) <<~ (4 #> bd)
(<<~) :: Dur -> Music Dur b -> Music Dur b
(<<~) = takeDur

infixr 2 ~>>
-- |Infix operator for 'dropDur'
--
-- Example (play 2 closed hi-hats):
-- 
-- > (1/2) ~>> ( (2 #> bd) <> (2 #> hc) )
(~>>) :: Dur -> Music Dur b -> Music Dur b
(~>>) = dropDur

infixr 2 <@~
-- |Infix operator for 'hushFor'
--
-- Example (half rest, then two closed hi-hats):
--
-- > (1/2) ~@> ( (2 #> bd) <> (2 #> hc) )
(~@>) :: Dur -> Music Dur b -> Music Dur b
(~@>) = hushFor

infixr 2 ~@>
-- |Infix operator for 'hushFrom'
--
-- Example (two bass drum hits, then a half rest):
--
-- > (1/2) <@~ ( (2 #> bd) <> (2 #> hc) )
(<@~) :: Dur -> Music Dur b -> Music Dur b
(<@~) = hushFrom

infixr 0 <!>
-- |Infix operator for 'normalize'
-- 
-- Example (Play 12 bass drum hits, then 4 closed hi-hats, then 3 snares, each within a single measure's time):
--
-- @
-- 1 \<!\> [
--     12 #> bd
--   , 4  #> hc
--   , 3  #> sn
--   ]
-- @
(<!>) :: Dur -> [Music Dur b] -> Music Dur b
(<!>) = normalize

infixr 0 >!<
-- |Infix operator for 'normalizeC'
-- 
-- Example: (Play 12 bass drum hits, then 4 closed hi-hats, then 3 snares, 
-- all concurrently within a single measure's time):
--
-- @
-- 1 >!< [
--     12 #> bd
--   , 4  #> hc
--   , 3  #> sn
--   ]
-- @
(>!<) :: Dur -> [Music Dur b] -> Music Dur b
(>!<) = normalizeC