module Sound.MIDI.ControllerPrivate where

import Data.Ix (Ix)
import Sound.MIDI.Utility (checkRange,
          enumRandomR, boundedEnumRandom, chooseEnum, )

import Test.QuickCheck (Arbitrary(arbitrary), )
import qualified Test.QuickCheck as QC
import System.Random (Random(random, randomR), )

{- |
We do not define 'Controller' as enumeration with many constructors,
because some controllers have multiple names and some are undefined.
It is also more efficient this way.
Thus you cannot use @case@ for processing controller types,
but you can use 'Data.List.lookup' instead.

> maybe (putStrLn "unsupported controller") putStrLn $
> lookup ctrl $
>    (portamento, "portamento") :
>    (modulation, "modulation") :
>    []

newtype Controller = Controller {fromController :: Int} deriving (Show, Eq, Ord, Ix)

toController :: Int -> Controller
toController = checkRange "Controller" Controller

instance Random Controller where
   random  = boundedEnumRandom
   randomR = enumRandomR

instance Arbitrary Controller where
   arbitrary = chooseEnum

instance Enum Controller where
   toEnum   = toController
   fromEnum = fromController

instance Bounded Controller where
   minBound = Controller   0
   maxBound = Controller 119
   -- higher controller numbers have special meanings