{-# OPTIONS -fffi #-}

module Sound.ALSA.SequencerFFI where

import Foreign.C
import Foreign
import Control.Monad (liftM, liftM2, zipWithM_)
import Data.Array (inRange, Ix)
import Data.List (find)



newtype T = Cons (Ptr ())

instance Storable T where
    sizeOf (Cons x) = sizeOf x
    alignment (Cons x) = alignment x
    peek = liftM Cons . peek . castPtr
    poke ptr (Cons x) = poke (castPtr ptr) x

-- size: 12 bytes
data EventDataUnion =
      DataUnknown CUInt CUInt CUInt
    | Note {
        noteChannel     :: CUChar,
        notePitch       :: CUChar,
        noteVelocity    :: CUChar,
        noteOffVelocity :: CUChar,
        noteDuration    :: CUInt
      }
    | Control {
        controlChannel   :: CUChar,
        controlParameter :: CUInt,
        controlValue     :: CInt
      }
    | QueueEv {
        queueId      :: Queue,
        queueControl :: QueueControl
      }
    | Connect {
        connectSender :: Address,
        connectDest   :: Address
      }
    | Fixed
  deriving Show

isConnect :: EventDataUnion -> Bool
isConnect Connect{} = True
isConnect _ = False

isFixed :: EventDataUnion -> Bool
isFixed Fixed{} = True
isFixed _ = False

isNote :: EventDataUnion -> Bool
isNote Note{} = True
isNote _ = False

isController :: EventDataUnion -> Bool
isController Control{} = True
isController _ = False

{-
instance Storable EventDataUnion where
    sizeOf _ = 12
    alignment _ = 4
    peek ptr =
        liftM3 DataUnknown
           (peekByteOff ptr 0)
           (peekByteOff ptr 4)
           (peekByteOff ptr 8)
    poke = pokeEventData
-}


peekEventData ::
   Ptr EventDataUnion -> EventType -> IO EventDataUnion
peekEventData ptr t =
   select
--      (fail ("peekEventData: " ++ show t)) $
      (return Fixed) $
      (t == EventPortSubscribed, peekConnect ptr) :
      (inRange (EventNote, EventKeyPressure) t, peekNote ptr) :
      (inRange (EventController, EventRegisteredParameter) t, peekControl ptr) :
      (t == EventSensing, return Fixed) :
      []

peekConnect :: Ptr EventDataUnion -> IO EventDataUnion
peekConnect ptr =
    liftM2 Connect
       (peekByteOff ptr 0)
       (peekByteOff ptr 2)

peekNote :: Ptr EventDataUnion -> IO EventDataUnion
peekNote ptr = do
    channel <- peekByteOff ptr 0
    note <- peekByteOff ptr 1
    velocity <- peekByteOff ptr 2
    offVelocity <- peekByteOff ptr 3
    duration <- peekByteOff ptr 4
    return $ Note channel note velocity offVelocity duration

peekControl :: Ptr EventDataUnion -> IO EventDataUnion
peekControl ptr = do
    channel <- peekByteOff ptr 0
    param <- peekByteOff ptr 4
    value <- peekByteOff ptr 8
    return $ Control channel param value


pokeEventData ::
   Ptr EventDataUnion -> EventDataUnion -> IO ()
pokeEventData ptr dat =
   case dat of
      Note {
        noteChannel     = channel,
        notePitch       = pitch,
        noteVelocity    = velocity,
        noteOffVelocity = offVelocity,
        noteDuration    = duration} ->
         do pokeByteOff ptr 0 channel
            pokeByteOff ptr 1 pitch
            pokeByteOff ptr 2 velocity
            pokeByteOff ptr 3 offVelocity
            pokeByteOff ptr 4 duration
      Control {
        controlChannel   = channel,
        controlParameter = param,
        controlValue     = value} ->
         do pokeByteOff ptr 0 channel
            pokeByteOff ptr 4 param
            pokeByteOff ptr 8 value
      QueueEv {
        queueId      = q,
        queueControl = qc} ->
         do pokeByteOff ptr 0 q
            pokeQueueControl (plusPtr ptr 4) qc
      DataUnknown a b c ->
         let intPtr = castPtr ptr
         in  do pokeElemOff intPtr 0 a
                pokeElemOff intPtr 1 b
                pokeElemOff intPtr 2 c
      Connect {
        connectSender = src,
        connectDest   = dst} ->
         let addrPtr = castPtr ptr
         in  do pokeElemOff addrPtr 0 src
                pokeElemOff addrPtr 1 dst
      Fixed -> return ()



class TimeValue a

-- size: 8 bytes
data RealTime = RealTime {
    tv_sec :: CUInt,
    tv_nsec :: CUInt
  } deriving Show

instance TimeValue RealTime

instance Storable RealTime where
    sizeOf (RealTime a b) = sizeOf a + sizeOf b
    alignment (RealTime a _) = alignment a
    peek ptr =
        liftM2 RealTime
           (peekByteOff ptr 0)
           (peekByteOff ptr 4)
    poke ptr (RealTime a b) = do
        pokeByteOff ptr 0 a
        pokeByteOff ptr 4 b


newtype TickTime = TickTime {
    tv_ticks :: CUInt
  } deriving Show

instance TimeValue TickTime

instance Storable TickTime where
    sizeOf (TickTime a) = sizeOf a
    alignment (TickTime a) = alignment a
    peek ptr =
        liftM TickTime (peekByteOff ptr 0)
    poke ptr (TickTime a) =
        pokeByteOff ptr 0 a



data TimeUnit =
     TimeUnitReal
   | TimeUnitTick
      deriving (Eq, Ord, Enum, Show)

data TimeMode =
     TimeModeAbsolute
   | TimeModeRelative
      deriving (Eq, Ord, Enum, Show)

-- size: 8 bytes
data TimeStamp =
      TimeStampTick TickTime
    | TimeStampReal RealTime
  deriving Show

peekTimeStamp :: TimeUnit -> Ptr TimeStamp -> IO TimeStamp
peekTimeStamp unit ptr =
    case unit of
       TimeUnitReal -> liftM TimeStampReal (peekByteOff ptr 0)
       TimeUnitTick -> liftM TimeStampTick (peekByteOff ptr 0)

pokeTimeStamp :: Ptr TimeStamp -> TimeStamp -> IO TimeUnit
pokeTimeStamp ptr ts =
    case ts of
       TimeStampReal t ->
          pokeByteOff ptr 0 t >> return TimeUnitReal
       TimeStampTick t ->
          pokeByteOff ptr 0 t >> return TimeUnitTick




newtype ClientId = ClientId CUInt
   deriving (Eq, Show)

instance Enum ClientId where
   toEnum = ClientId . fromIntegral
   fromEnum (ClientId x) = fromIntegral x

instance Storable ClientId where
    sizeOf = sizeOf . enumToChar
    alignment = alignment . enumToChar
    peek = liftM enumFromChar . peek . castPtr
    poke ptr = poke (castPtr ptr) . enumToChar

{- known client numbers -}

{- | system client -}
clientSystem :: ClientId
clientSystem = ClientId  0
{- | dummy ports -}
clientDummy :: ClientId
clientDummy  = ClientId 62
{- | OSS sequencer emulator -}
clientOSS :: ClientId
clientOSS    = ClientId 63


newtype Port = Port CUInt
   deriving (Eq, Show)

instance Enum Port where
   toEnum = Port . fromIntegral
   fromEnum (Port x) = fromIntegral x

instance Storable Port where
    sizeOf = sizeOf . enumToChar
    alignment = alignment . enumToChar
    peek = liftM enumFromChar . peek . castPtr
    poke ptr = poke (castPtr ptr) . enumToChar


{- | system timer port -}
portSystemTimer :: Port
portSystemTimer    = Port 0
{- | system announce port -}
portSystemAnnounce :: Port
portSystemAnnounce = Port 1



-- size: 2 bytes
data Address = Address {
    client :: ClientId,
    port :: Port
  } deriving Show

instance Storable Address where
    sizeOf _ = 2
    alignment _ = 4
    peek ptr =
        liftM2 Address
           (peekByteOff ptr 0)
           (peekByteOff ptr 1)
    poke ptr (Address a b) = do
        pokeByteOff ptr 0 a
        pokeByteOff ptr 1 b


addressTimer :: Address
addressTimer = Address clientSystem portSystemTimer


newtype Queue = Queue CUInt
   deriving (Eq, Show)

instance Enum Queue where
   toEnum = Queue . fromIntegral
   fromEnum (Queue x) = fromIntegral x

instance Storable Queue where
    sizeOf = sizeOf . enumToChar
    alignment = alignment . enumToChar
    peek = liftM enumFromChar . peek . castPtr
    poke ptr = poke (castPtr ptr) . enumToChar


queueDirect :: Queue
queueDirect = Queue 253


data QueueControl =
     QueueControlValue CInt
   | QueueControlTime TimeStamp
   | QueueControlPosition CUInt
--   | QueueControlSkew QueueSkew
   | QueueControlData32 CUInt CUInt
   | QueueControlData8  CUChar CUChar CUChar CUChar CUChar CUChar CUChar CUChar
   deriving Show


{-
instance Storable QueueControl where
    sizeOf _ = 8
    alignment _ = 4
    peek ptr =
        liftM2 QueueControlData32
           (peekByteOff ptr 0)
           (peekByteOff ptr 4)
    poke ptr qc =
       case qc of
          QueueControlValue val -> pokeByteOff ptr 0 val
          QueueControlTime ts -> pokeByteOff ptr 0 ts
          QueueControlPosition pos -> pokeByteOff ptr 0 pos
       -- QueueControlSkew skew -> pokeByteOff ptr 0 skew
          QueueControlData32 d0 d1 ->
              pokeByteOff ptr 0 d0 >>
              pokeByteOff ptr 4 d1
          QueueControlData8  d0 d1 d2 d3 d4 d5 d6 d7 ->
              zipWithM_ (pokeByteOff ptr)
                  [0..] [d0, d1, d2, d3, d4, d5, d6, d7]
-}

{-
peekQueueControl :: EventType -> TimeUnit -> Ptr QueueControl -> IO QueueControl
peekQueueControl et tu ptr =
-}

pokeQueueControl :: Ptr QueueControl -> QueueControl -> IO ()
pokeQueueControl ptr qc =
   case qc of
      QueueControlValue val -> pokeByteOff ptr 0 val
      QueueControlTime ts -> pokeTimeStamp (castPtr ptr) ts >> return ()
      QueueControlPosition pos -> pokeByteOff ptr 0 pos
   -- QueueControlSkew skew -> pokeByteOff ptr 0 skew
      QueueControlData32 d0 d1 ->
          pokeByteOff ptr 0 d0 >>
          pokeByteOff ptr 4 d1
      QueueControlData8  d0 d1 d2 d3 d4 d5 d6 d7 ->
          zipWithM_ (pokeByteOff ptr)
              [0..] [d0, d1, d2, d3, d4, d5, d6, d7]




data EventType =
   {- system status; event data type = 'Result' -}
     EventSystem  {- 0 -}
   {- returned result status; event data type = 'Result' -}
   | EventResult

   | EventPad002
   | EventPad003
   | EventPad004

   {- note on and off with duration; event data type = 'Note' -}
   | EventNote  {- 5 -}
   {- note on; event data type = 'Note' -}
   | EventNoteOn
   {- note off; event data type = 'Note' -}
   | EventNoteOff
   {- key pressure change (aftertouch); event data type = 'Note' -}
   | EventKeyPressure

   | EventPad009

   {- controller; event data type = 'Control' -}
   | EventController  {- 10 -}
   {- program change; event data type = 'Control' -}
   | EventProgramChange
   {- channel pressure; event data type = 'Control' -}
   | EventChannelPressure
   {- pitchwheel; event data type = 'Control'; data is from -8192 to 8191) -}
   | EventPitchbend
   {- 14 bit controller value; event data type = 'Control' -}
   | EventControl14
   {- 14 bit NRPN;  event data type = 'Control' -}
   | EventNonRegisteredParameter
   {- 14 bit RPN; event data type = 'Control' -}
   | EventRegisteredParameter

   | EventPad017
   | EventPad018
   | EventPad019

   {- SPP with LSB and MSB values; event data type = 'Control' -}
   | EventSongPosition  {- 20 -}
   {- Song Select with song ID number; event data type = 'Control' -}
   | EventSongSelect
   {- midi time code quarter frame; event data type = 'Control' -}
   | EventQuarterFrame
   {- SMF Time Signature event; event data type = 'Control' -}
   | EventTimeSign
   {- SMF Key Signature event; event data type = 'Control' -}
   | EventKeySign

   | EventPad025
   | EventPad026
   | EventPad027
   | EventPad028
   | EventPad029

   {- MIDI Real Time Start message; event data type = 'QueueControl' -}
   | EventStart  {- 30 -}
   {- MIDI Real Time Continue message; event data type = 'QueueControl' -}
   | EventContinue
   {- MIDI Real Time Stop message; event data type = 'QueueControl' -}
   | EventStop
   {- Set tick queue position; event data type = 'QueueControl' -}
   | EventSetPositionTick
   {- Set real-time queue position; event data type = 'QueueControl' -}
   | EventSetPositionTime
   {- (SMF) Tempo event; event data type = 'QueueControl' -}
   | EventTempo
   {- MIDI Real Time Clock message; event data type = 'QueueControl' -}
   | EventClock
   {- MIDI Real Time Tick message; event data type = 'QueueControl' -}
   | EventTick
   {- Queue timer skew; event data type = 'QueueControl' -}
   | EventQueueSkew
   {- Sync position changed; event data type = 'QueueControl' -}
   | EventSyncPos

   {- Tune request; event data type = none -}
   | EventTuneRequest  {- 40 -}
   {- Reset to power-on state; event data type = none -}
   | EventReset
   {- Active sensing event; event data type = none -}
   | EventSensing

   | EventPad043
   | EventPad044
   | EventPad045
   | EventPad046
   | EventPad047
   | EventPad048
   | EventPad049

   {- Echo-back event; event data type = any type -}
   | EventEcho  {- 50 -}
   {- OSS emulation raw event; event data type = any type -}
   | EventOSS

   | EventPad052
   | EventPad053
   | EventPad054
   | EventPad055
   | EventPad056
   | EventPad057
   | EventPad058
   | EventPad059

   {- New client has connected; event data type = 'T' -}
   | EventClientStart  {- 60 -}
   {- Client has left the system; event data type = 'T' -}
   | EventClientExit
   {- Client status/info has changed; event data type = 'T' -}
   | EventClientChange
   {- New port was created; event data type = 'T' -}
   | EventPortStart
   {- Port was deleted from system; event data type = 'T' -}
   | EventPortExit
   {- Port status/info has changed; event data type = 'T' -}
   | EventPortChange

   {- Ports connected; event data type = 'Connect' -}
   | EventPortSubscribed
   {- Ports disconnected; event data type = 'Connect' -}
   | EventPortUnsubscribed

   | EventPad068
   | EventPad069

   {- Sample select; event data type = 'SampleControl' -}
   | EventSample  {- 70 -}
   {- Sample cluster select; event data type = 'SampleControl' -}
   | EventSampleCluster
   {- voice start -}
   | EventSampleStart
   {- voice stop -}
   | EventSampleStop
   {- playback frequency -}
   | EventSampleFrequency
   {- volume and balance -}
   | EventSampleVolume
   {- sample loop -}
   | EventSampleLoop
   {- sample position -}
   | EventSamplePosition
   {- private (hardware dependent) event -}
   | EventSamplePrivate1

   | EventPad079
   | EventPad080
   | EventPad081
   | EventPad082
   | EventPad083
   | EventPad084
   | EventPad085
   | EventPad086
   | EventPad087
   | EventPad088
   | EventPad089

   {- user-defined event; event data type = any (fixed size) -}
   | EventUser0  {- 90 -}
   {- user-defined event; event data type = any (fixed size) -}
   | EventUser1
   {- user-defined event; event data type = any (fixed size) -}
   | EventUser2
   {- user-defined event; event data type = any (fixed size) -}
   | EventUser3
   {- user-defined event; event data type = any (fixed size) -}
   | EventUser4
   {- user-defined event; event data type = any (fixed size) -}
   | EventUser5
   {- user-defined event; event data type = any (fixed size) -}
   | EventUser6
   {- user-defined event; event data type = any (fixed size) -}
   | EventUser7
   {- user-defined event; event data type = any (fixed size) -}
   | EventUser8
   {- user-defined event; event data type = any (fixed size) -}
   | EventUser9

   {- begin of instrument management -}
   | EventInstrumentBegin  {- 100 -}
   {- end of instrument management -}
   | EventInstrumentEnd
   {- query instrument interface info -}
   | EventInstrumentInfo
   {- result of instrument interface info -}
   | EventInstrumentInfoResult
   {- query instrument format info -}
   | EventInstrumentFormatInfo
   {- result of instrument format info -}
   | EventInstrumentFormatInfoResult
   {- reset instrument instrument memory -}
   | EventInstrumentReset
   {- get instrument interface status -}
   | EventInstrumentStatus
   {- result of instrument interface status -}
   | EventInstrumentStatusResult
   {- put an instrument to port -}
   | EventInstrumentPut
   {- get an instrument from port -}
   | EventInstrumentGet
   {- result of instrument query -}
   | EventInstrumentGetResult
   {- free instrument(s) -}
   | EventInstrumentFree
   {- get instrument list -}
   | EventInstrumentList
   {- result of instrument list -}
   | EventInstrumentListResult
   {- set cluster parameters -}
   | EventInstrumentCluster
   {- get cluster parameters -}
   | EventInstrumentClusterGet
   {- result of cluster parameters -}
   | EventInstrumentClusterResult
   {- instrument change -}
   | EventInstrumentChange

   | EventPad119
   | EventPad120
   | EventPad121
   | EventPad122
   | EventPad123
   | EventPad124
   | EventPad125
   | EventPad126
   | EventPad127
   | EventPad128
   | EventPad129

   {- system exclusive data (variable length);  event data type = 'Exclusive' -}
   | EventSystemExclusive  {- 130 -}
   {- error event;  event data type = 'Exclusive' -}
   | EventBounce

   | EventPad132
   | EventPad133
   | EventPad134

   {- reserved for user apps;  event data type = 'Exclusive' -}
   | EventUserVar0  {- 135 -}
   {- reserved for user apps; event data type = 'Exclusive' -}
   | EventUserVar1
   {- reserved for user apps; event data type = 'Exclusive' -}
   | EventUserVar2
   {- reserved for user apps; event data type = 'Exclusive' -}
   | EventUserVar3
   {- reserved for user apps; event data type = 'Exclusive' -}
   | EventUserVar4

   {- NOP; ignored in any case -}
   -- EventNone  {- 255 -}
     deriving (Eq, Ord, Enum, Ix, Show)


instance Storable EventType where
    sizeOf = sizeOf . enumToChar
    alignment = alignment . enumToChar
    peek = liftM enumFromChar . peek . castPtr
    poke ptr = poke (castPtr ptr) . enumToChar


data EventLength =
     EventLengthFixed
   | EventLengthVariable
   | EventLengthVariableUser
      deriving (Eq, Ord, Enum, Show)

data Priority =
     PriorityNormal
   | PriorityHigh
      deriving (Eq, Ord, Enum, Show)


data Event = Event {
    typ :: EventType,
    tag :: CUChar,
    queue :: Queue,
    time :: TimeStamp,
    timeMode :: TimeMode,
    eventLength :: EventLength,
    priority :: Priority,
    source :: Address,
    dest :: Address,
    eventData :: EventDataUnion
  } deriving Show

instance Storable Event where
    sizeOf _ = 16+12
    alignment _ = 4
    peek ptr = do
        typ_ <- peekByteOff ptr 0
        flags <- peekByteOff ptr 1 :: IO CUChar
        tag_ <- peekByteOff ptr 2
        queue_ <- peekByteOff ptr 3
        time_ <-
           peekTimeStamp
              (unpackEnum 1 timeUnitBit flags)
              (plusPtr ptr 4)
        source_ <- peekByteOff ptr 12
        dest_ <- peekByteOff ptr 14
        eventData_ <- peekEventData (plusPtr ptr 16) typ_
        return $ Event
            typ_
            tag_
            queue_
            time_
            (unpackEnum 1 timeModeBit    flags)
            (unpackEnum 3 eventLengthBit flags)
            (unpackEnum 1 priorityBit    flags)
            source_
            dest_
            eventData_
    poke ptr ev = do
        timeUnitSet <- pokeTimeStamp (plusPtr ptr 4) (time ev)
        let timeModeSet    = packEnum timeModeBit    (timeMode    ev)
        let eventLengthSet = packEnum eventLengthBit (eventLength ev)
        let prioritySet =    packEnum priorityBit    (priority    ev)
        pokeByteOff ptr  0 (typ ev)
        pokeByteOff ptr  1
            (packEnum timeUnitBit timeUnitSet .|. timeModeSet .|. eventLengthSet .|. prioritySet :: CUChar)
        pokeByteOff ptr  2 (tag ev)
        pokeByteOff ptr  3 (queue ev)
        pokeByteOff ptr 12 (source ev)
        pokeByteOff ptr 14 (dest ev)
        pokeEventData (plusPtr ptr 16) (eventData ev)


newtype EnumBitPos a = EnumBitPos Int

timeUnitBit :: EnumBitPos TimeUnit
timeUnitBit = EnumBitPos 0

timeModeBit :: EnumBitPos TimeMode
timeModeBit = EnumBitPos 1

eventLengthBit :: EnumBitPos EventLength
eventLengthBit = EnumBitPos 2

priorityBit :: EnumBitPos Priority
priorityBit = EnumBitPos 4


newtype ReturnCode = ReturnCode CInt

check :: String -> IO ReturnCode -> IO CUInt
check name act =
   do ReturnCode c <- act
      if c<0
        then str_error c >>= peekCString >>= \str ->
             fail ("ALSA.Sequencer." ++ name ++ ": exception " ++ show (-c) ++ ": " ++ str)
        else return $ fromIntegral c




-- * FFI stuff

-- ** Error handling

-- | should be in a more general ALSA module
foreign import ccall "static alsa/asoundlib.h snd_strerror"
    str_error :: CInt -> IO CString


-- ** Sequencer

foreign import ccall "static alsa/asoundlib.h snd_seq_open"
    open :: Ptr T -> CString -> OpenMode -> CUInt -> IO ReturnCode

foreign import ccall "static alsa/asoundlib.h snd_seq_close"
    close :: T -> IO ReturnCode

foreign import ccall "static alsa/asoundlib.h snd_seq_set_client_name"
    set_client_name :: T -> CString -> IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_client_id"
    client_id :: T -> ClientId

foreign import ccall "static alsa/asoundlib.h snd_seq_event_output"
    event_output :: T -> Ptr Event -> IO ReturnCode

foreign import ccall "static alsa/asoundlib.h snd_seq_drain_output"
    drain_output :: T -> IO ReturnCode

foreign import ccall "static alsa/asoundlib.h snd_seq_event_input"
    event_input :: T -> Ptr (Ptr Event) -> IO ReturnCode

-- snd_seq_ev_clear(&ev);   macro for memset


-- ** Port

foreign import ccall "static alsa/asoundlib.h snd_seq_create_simple_port"
    create_simple_port :: T -> Ptr CChar -> PortCapabilitySet -> PortTypeSet -> IO ReturnCode

foreign import ccall "static alsa/asoundlib.h snd_seq_delete_simple_port"
    delete_simple_port :: T -> Port -> IO ReturnCode


-- ** Queue

foreign import ccall "static alsa/asoundlib.h snd_seq_alloc_named_queue"
    alloc_named_queue :: T -> CString -> IO ReturnCode

foreign import ccall "static alsa/asoundlib.h snd_seq_alloc_queue"
    alloc_queue :: T -> IO ReturnCode

foreign import ccall "static alsa/asoundlib.h snd_seq_free_queue"
    free_queue :: T -> Queue -> IO ReturnCode


-- ** Tempo

newtype Tempo = Tempo (Ptr ())

instance Storable Tempo where
    sizeOf (Tempo x) = sizeOf x
    alignment (Tempo x) = alignment x
    peek = liftM Tempo . peek . castPtr
    poke ptr (Tempo x) = poke (castPtr ptr) x



foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_malloc"
    queue_tempo_malloc :: Ptr Tempo -> IO ReturnCode

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_free"
    queue_tempo_free :: Tempo -> IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_set_tempo"
    queue_tempo_set_tempo :: Tempo -> CUInt -> IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_set_ppq"
    queue_tempo_set_ppq :: Tempo -> CUInt -> IO ()



foreign import ccall "static alsa/asoundlib.h snd_seq_get_queue_tempo"
    get_queue_tempo :: T -> Queue -> Tempo -> IO ReturnCode

foreign import ccall "static alsa/asoundlib.h snd_seq_set_queue_tempo"
    set_queue_tempo :: T -> Queue -> Tempo -> IO ReturnCode


{-
/*
 */
foreign import ccall "static alsa/asoundlib.h snd_seq_open"
    open :: snd_seq_t **handle, const char *name, int streams, int mode) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_open_lconf"
    open_lconf :: snd_seq_t **handle, const char *name, int streams, int mode, snd_config_t *lconf) IO CInt

const char *snd_seq_name(snd_seq_t *seq);
foreign import ccall "static alsa/asoundlib.h snd_seq_type"
    type :: snd_seq_t *seq) IO snd_seq_type_t


foreign import ccall "static alsa/asoundlib.h snd_seq_close"
    close :: snd_seq_t *handle) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_poll_descriptors_count"
    poll_descriptors_count :: T -> short events) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_poll_descriptors"
    poll_descriptors :: T -> struct pollfd *pfds, unsigned int space, short events) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_poll_descriptors_revents"
    poll_descriptors_revents :: T -> struct pollfd *pfds, unsigned int nfds, unsigned short *revents) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_nonblock"
    nonblock :: T -> int nonblock) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_client_id"
    client_id :: snd_seq_t *handle) IO CInt


foreign import ccall "static alsa/asoundlib.h snd_seq_get_output_buffer_size"
    get_output_buffer_size :: snd_seq_t *handle) IO size_t

foreign import ccall "static alsa/asoundlib.h snd_seq_get_input_buffer_size"
    get_input_buffer_size :: snd_seq_t *handle) IO size_t

foreign import ccall "static alsa/asoundlib.h snd_seq_set_output_buffer_size"
    set_output_buffer_size :: T -> size_t size) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_set_input_buffer_size"
    set_input_buffer_size :: T -> size_t size) IO CInt


{- | system information container -}
typedef struct _snd_seq_system_info snd_seq_system_info_t;

foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_sizeof"
    system_info_sizeof :: void) IO size_t

{- | allocate a #snd_seq_system_info_t container on stack -}
#define snd_seq_system_info_alloca(ptr) \
	SND_ALLOCA(snd_seq_system_info, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_malloc"
    system_info_malloc :: snd_seq_system_info_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_free"
    system_info_free :: snd_seq_system_info_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_copy"
    system_info_copy :: snd_seq_system_info_t *dst, const snd_seq_system_info_t *src) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_get_queues"
    system_info_get_queues :: const snd_seq_system_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_get_clients"
    system_info_get_clients :: const snd_seq_system_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_get_ports"
    system_info_get_ports :: const snd_seq_system_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_get_channels"
    system_info_get_channels :: const snd_seq_system_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_get_cur_clients"
    system_info_get_cur_clients :: const snd_seq_system_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_system_info_get_cur_queues"
    system_info_get_cur_queues :: const snd_seq_system_info_t *info) IO CInt


foreign import ccall "static alsa/asoundlib.h snd_seq_system_info"
    system_info :: T -> snd_seq_system_info_t *info) IO CInt


/** \} */


/**
 *  \defgroup SeqClient Sequencer Client Interface
 *  Sequencer Client Interface
 *  \ingroup Sequencer
 *  \{
 */

{- | client information container -}
typedef struct _snd_seq_client_info snd_seq_client_info_t;

{- | client types -}
typedef enum snd_seq_client_type {
	SND_SEQ_USER_CLIENT     = 1,	{- | user client -}
	SND_SEQ_KERNEL_CLIENT   = 2	{- | kernel client -}
} snd_seq_client_type_t;

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_sizeof"
    client_info_sizeof :: void) IO size_t

{- | allocate a #snd_seq_client_info_t container on stack -}
#define snd_seq_client_info_alloca(ptr) \
	SND_ALLOCA(snd_seq_client_info, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_malloc"
    client_info_malloc :: snd_seq_client_info_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_free"
    client_info_free :: snd_seq_client_info_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_copy"
    client_info_copy :: snd_seq_client_info_t *dst, const snd_seq_client_info_t *src) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_get_client"
    client_info_get_client :: const snd_seq_client_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_get_type"
    client_info_get_type :: const snd_seq_client_info_t *info) IO snd_seq_client_type_t

const char *snd_seq_client_info_get_name(snd_seq_client_info_t *info);
foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_get_broadcast_filter"
    client_info_get_broadcast_filter :: const snd_seq_client_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_get_error_bounce"
    client_info_get_error_bounce :: const snd_seq_client_info_t *info) IO CInt

const unsigned char *snd_seq_client_info_get_event_filter(const snd_seq_client_info_t *info);
foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_get_num_ports"
    client_info_get_num_ports :: const snd_seq_client_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_get_event_lost"
    client_info_get_event_lost :: const snd_seq_client_info_t *info) IO CInt


foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_set_client"
    client_info_set_client :: snd_seq_client_info_t *info, int client) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_set_name"
    client_info_set_name :: snd_seq_client_info_t *info, const char *name) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_set_broadcast_filter"
    client_info_set_broadcast_filter :: snd_seq_client_info_t *info, int val) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_set_error_bounce"
    client_info_set_error_bounce :: snd_seq_client_info_t *info, int val) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_client_info_set_event_filter"
    client_info_set_event_filter :: snd_seq_client_info_t *info, unsigned char *filter) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_get_client_info"
    get_client_info :: T -> snd_seq_client_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_get_any_client_info"
    get_any_client_info :: T -> int client, snd_seq_client_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_set_client_info"
    set_client_info :: T -> snd_seq_client_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_query_next_client"
    query_next_client :: T -> snd_seq_client_info_t *info) IO CInt


/*
 */

{- | client pool information container -}
typedef struct _snd_seq_client_pool snd_seq_client_pool_t;

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_sizeof"
    client_pool_sizeof :: void) IO size_t

{- | allocate a #snd_seq_client_pool_t container on stack -}
#define snd_seq_client_pool_alloca(ptr) \
	SND_ALLOCA(snd_seq_client_pool, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_malloc"
    client_pool_malloc :: snd_seq_client_pool_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_free"
    client_pool_free :: snd_seq_client_pool_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_copy"
    client_pool_copy :: snd_seq_client_pool_t *dst, const snd_seq_client_pool_t *src) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_get_client"
    client_pool_get_client :: const snd_seq_client_pool_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_get_output_pool"
    client_pool_get_output_pool :: const snd_seq_client_pool_t *info) IO size_t

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_get_input_pool"
    client_pool_get_input_pool :: const snd_seq_client_pool_t *info) IO size_t

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_get_output_room"
    client_pool_get_output_room :: const snd_seq_client_pool_t *info) IO size_t

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_get_output_free"
    client_pool_get_output_free :: const snd_seq_client_pool_t *info) IO size_t

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_get_input_free"
    client_pool_get_input_free :: const snd_seq_client_pool_t *info) IO size_t

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_set_output_pool"
    client_pool_set_output_pool :: snd_seq_client_pool_t *info, size_t size) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_set_input_pool"
    client_pool_set_input_pool :: snd_seq_client_pool_t *info, size_t size) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_client_pool_set_output_room"
    client_pool_set_output_room :: snd_seq_client_pool_t *info, size_t size) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_get_client_pool"
    get_client_pool :: T -> snd_seq_client_pool_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_set_client_pool"
    set_client_pool :: T -> snd_seq_client_pool_t *info) IO CInt



/** \} */


/**
 *  \defgroup SeqPort Sequencer Port Interface
 *  Sequencer Port Interface
 *  \ingroup Sequencer
 *  \{
 */

{- | port information container -}
typedef struct _snd_seq_port_info snd_seq_port_info_t;

{- | known port numbers -}
#define SND_SEQ_PORT_SYSTEM_TIMER	0	{- | system timer port -}
#define SND_SEQ_PORT_SYSTEM_ANNOUNCE	1	{- | system announce port -}

{- | port capabilities (32 bits) -}
#define SND_SEQ_PORT_CAP_READ		(1<<0)	{- | readable from this port -}
#define SND_SEQ_PORT_CAP_WRITE		(1<<1)	{- | writable to this port -}

#define SND_SEQ_PORT_CAP_SYNC_READ	(1<<2)	{- | allow read subscriptions -}
#define SND_SEQ_PORT_CAP_SYNC_WRITE	(1<<3)	{- | allow write subscriptions -}

#define SND_SEQ_PORT_CAP_DUPLEX		(1<<4)	{- | allow read/write duplex -}

#define SND_SEQ_PORT_CAP_SUBS_READ	(1<<5)	{- | allow read subscription -}
#define SND_SEQ_PORT_CAP_SUBS_WRITE	(1<<6)	{- | allow write subscription -}
#define SND_SEQ_PORT_CAP_NO_EXPORT	(1<<7)	{- | routing not allowed -}

{- | port type -}
#define SND_SEQ_PORT_TYPE_SPECIFIC	(1<<0)	{- | hardware specific -}
#define SND_SEQ_PORT_TYPE_MIDI_GENERIC	(1<<1)	{- | generic MIDI device -}
#define SND_SEQ_PORT_TYPE_MIDI_GM	(1<<2)	{- | General MIDI compatible device -}
#define SND_SEQ_PORT_TYPE_MIDI_GS	(1<<3)	{- | GS compatible device -}
#define SND_SEQ_PORT_TYPE_MIDI_XG	(1<<4)	{- | XG compatible device -}
#define SND_SEQ_PORT_TYPE_MIDI_MT32	(1<<5)	{- | MT-32 compatible device -}
#define SND_SEQ_PORT_TYPE_SYNTH		(1<<10)	{- | Synth device -}
#define SND_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11)	{- | Sampling device (support sample download) -}
#define SND_SEQ_PORT_TYPE_SAMPLE	(1<<12)	{- | Sampling device (sample can be downloaded at any time) -}
#define SND_SEQ_PORT_TYPE_APPLICATION	(1<<20)	{- | application (sequencer/editor) -}


foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_sizeof"
    port_info_sizeof :: void) IO size_t

{- | allocate a #snd_seq_port_info_t container on stack -}
#define snd_seq_port_info_alloca(ptr) \
	SND_ALLOCA(snd_seq_port_info, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_malloc"
    port_info_malloc :: snd_seq_port_info_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_free"
    port_info_free :: snd_seq_port_info_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_copy"
    port_info_copy :: snd_seq_port_info_t *dst, const snd_seq_port_info_t *src) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_client"
    port_info_get_client :: const snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_port"
    port_info_get_port :: const snd_seq_port_info_t *info) IO CInt

const snd_seq_addr_t *snd_seq_port_info_get_addr(const snd_seq_port_info_t *info);
const char *snd_seq_port_info_get_name(const snd_seq_port_info_t *info);
unsigned int snd_seq_port_info_get_capability(const snd_seq_port_info_t *info);
unsigned int snd_seq_port_info_get_type(const snd_seq_port_info_t *info);
foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_midi_channels"
    port_info_get_midi_channels :: const snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_midi_voices"
    port_info_get_midi_voices :: const snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_synth_voices"
    port_info_get_synth_voices :: const snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_read_use"
    port_info_get_read_use :: const snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_write_use"
    port_info_get_write_use :: const snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_port_specified"
    port_info_get_port_specified :: const snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_timestamping"
    port_info_get_timestamping :: const snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_timestamp_real"
    port_info_get_timestamp_real :: const snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_get_timestamp_queue"
    port_info_get_timestamp_queue :: const snd_seq_port_info_t *info) IO CInt


foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_client"
    port_info_set_client :: snd_seq_port_info_t *info, int client) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_port"
    port_info_set_port :: snd_seq_port_info_t *info, int port) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_addr"
    port_info_set_addr :: snd_seq_port_info_t *info, const snd_seq_addr_t *addr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_name"
    port_info_set_name :: snd_seq_port_info_t *info, const char *name) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_capability"
    port_info_set_capability :: snd_seq_port_info_t *info, unsigned int capability) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_type"
    port_info_set_type :: snd_seq_port_info_t *info, unsigned int type) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_midi_channels"
    port_info_set_midi_channels :: snd_seq_port_info_t *info, int channels) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_midi_voices"
    port_info_set_midi_voices :: snd_seq_port_info_t *info, int voices) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_synth_voices"
    port_info_set_synth_voices :: snd_seq_port_info_t *info, int voices) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_port_specified"
    port_info_set_port_specified :: snd_seq_port_info_t *info, int val) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_timestamping"
    port_info_set_timestamping :: snd_seq_port_info_t *info, int enable) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_timestamp_real"
    port_info_set_timestamp_real :: snd_seq_port_info_t *info, int realtime) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_info_set_timestamp_queue"
    port_info_set_timestamp_queue :: snd_seq_port_info_t *info, int queue) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_create_port"
    create_port :: T -> snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_delete_port"
    delete_port :: T -> int port) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_get_port_info"
    get_port_info :: T -> int port, snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_get_any_port_info"
    get_any_port_info :: T -> int client, int port, snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_set_port_info"
    set_port_info :: T -> int port, snd_seq_port_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_query_next_port"
    query_next_port :: T -> snd_seq_port_info_t *info) IO CInt


/** \} */


/**
 *  \defgroup SeqSubscribe Sequencer Port Subscription
 *  Sequencer Port Subscription
 *  \ingroup Sequencer
 *  \{
 */

{- | port subscription container -}
typedef struct _snd_seq_port_subscribe snd_seq_port_subscribe_t;

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_sizeof"
    port_subscribe_sizeof :: void) IO size_t

{- | allocate a #snd_seq_port_subscribe_t container on stack -}
#define snd_seq_port_subscribe_alloca(ptr) \
	SND_ALLOCA(snd_seq_port_subscribe, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_malloc"
    port_subscribe_malloc :: snd_seq_port_subscribe_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_free"
    port_subscribe_free :: snd_seq_port_subscribe_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_copy"
    port_subscribe_copy :: snd_seq_port_subscribe_t *dst, const snd_seq_port_subscribe_t *src) IO ()


const snd_seq_addr_t *snd_seq_port_subscribe_get_sender(const snd_seq_port_subscribe_t *info);
const snd_seq_addr_t *snd_seq_port_subscribe_get_dest(const snd_seq_port_subscribe_t *info);
foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_get_queue"
    port_subscribe_get_queue :: const snd_seq_port_subscribe_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_get_exclusive"
    port_subscribe_get_exclusive :: const snd_seq_port_subscribe_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_get_time_update"
    port_subscribe_get_time_update :: const snd_seq_port_subscribe_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_get_time_real"
    port_subscribe_get_time_real :: const snd_seq_port_subscribe_t *info) IO CInt


foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_set_sender"
    port_subscribe_set_sender :: snd_seq_port_subscribe_t *info, const snd_seq_addr_t *addr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_set_dest"
    port_subscribe_set_dest :: snd_seq_port_subscribe_t *info, const snd_seq_addr_t *addr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_set_queue"
    port_subscribe_set_queue :: snd_seq_port_subscribe_t *info, int q) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_set_exclusive"
    port_subscribe_set_exclusive :: snd_seq_port_subscribe_t *info, int val) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_set_time_update"
    port_subscribe_set_time_update :: snd_seq_port_subscribe_t *info, int val) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_port_subscribe_set_time_real"
    port_subscribe_set_time_real :: snd_seq_port_subscribe_t *info, int val) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_get_port_subscription"
    get_port_subscription :: T -> snd_seq_port_subscribe_t *sub) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_subscribe_port"
    subscribe_port :: T -> snd_seq_port_subscribe_t *sub) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_unsubscribe_port"
    unsubscribe_port :: T -> snd_seq_port_subscribe_t *sub) IO CInt


/*
 */

{- | subscription query container -}
typedef struct _snd_seq_query_subscribe snd_seq_query_subscribe_t;

{- | type of query subscription -}
typedef enum {
	SND_SEQ_QUERY_SUBS_READ,	{- | query read subscriptions -}
	SND_SEQ_QUERY_SUBS_WRITE	{- | query write subscriptions -}
} snd_seq_query_subs_type_t;

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_sizeof"
    query_subscribe_sizeof :: void) IO size_t

{- | allocate a #snd_seq_query_subscribe_t container on stack -}
#define snd_seq_query_subscribe_alloca(ptr) \
	SND_ALLOCA(snd_seq_query_subscribe, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_malloc"
    query_subscribe_malloc :: snd_seq_query_subscribe_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_free"
    query_subscribe_free :: snd_seq_query_subscribe_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_copy"
    query_subscribe_copy :: snd_seq_query_subscribe_t *dst, const snd_seq_query_subscribe_t *src) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_get_client"
    query_subscribe_get_client :: const snd_seq_query_subscribe_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_get_port"
    query_subscribe_get_port :: const snd_seq_query_subscribe_t *info) IO CInt

const snd_seq_addr_t *snd_seq_query_subscribe_get_root(const snd_seq_query_subscribe_t *info);
foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_get_type"
    query_subscribe_get_type :: const snd_seq_query_subscribe_t *info) IO snd_seq_query_subs_type_t

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_get_index"
    query_subscribe_get_index :: const snd_seq_query_subscribe_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_get_num_subs"
    query_subscribe_get_num_subs :: const snd_seq_query_subscribe_t *info) IO CInt

const snd_seq_addr_t *snd_seq_query_subscribe_get_addr(const snd_seq_query_subscribe_t *info);
foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_get_queue"
    query_subscribe_get_queue :: const snd_seq_query_subscribe_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_get_exclusive"
    query_subscribe_get_exclusive :: const snd_seq_query_subscribe_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_get_time_update"
    query_subscribe_get_time_update :: const snd_seq_query_subscribe_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_get_time_real"
    query_subscribe_get_time_real :: const snd_seq_query_subscribe_t *info) IO CInt


foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_set_client"
    query_subscribe_set_client :: snd_seq_query_subscribe_t *info, int client) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_set_port"
    query_subscribe_set_port :: snd_seq_query_subscribe_t *info, int port) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_set_root"
    query_subscribe_set_root :: snd_seq_query_subscribe_t *info, const snd_seq_addr_t *addr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_set_type"
    query_subscribe_set_type :: snd_seq_query_subscribe_t *info, snd_seq_query_subs_type_t type) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_query_subscribe_set_index"
    query_subscribe_set_index :: snd_seq_query_subscribe_t *info, int _index) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_query_port_subscribers"
    query_port_subscribers :: T -> snd_seq_query_subscribe_t * subs) IO CInt


/** \} */


/**
 *  \defgroup SeqQueue Sequencer Queue Interface
 *  Sequencer Queue Interface
 *  \ingroup Sequencer
 *  \{
 */

{- | queue information container -}
typedef struct _snd_seq_queue_info snd_seq_queue_info_t;
{- | queue status container -}
typedef struct _snd_seq_queue_status snd_seq_queue_status_t;
{- | queue tempo container -}
typedef struct _snd_seq_queue_tempo snd_seq_queue_tempo_t;
{- | queue timer information container -}
typedef struct _snd_seq_queue_timer snd_seq_queue_timer_t;

{- | special queue ids -}
#define SND_SEQ_QUEUE_DIRECT		253	{- | direct dispatch -}

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_sizeof"
    queue_info_sizeof :: void) IO size_t

{- | allocate a #snd_seq_queue_info_t container on stack -}
#define snd_seq_queue_info_alloca(ptr) \
	SND_ALLOCA(snd_seq_queue_info, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_malloc"
    queue_info_malloc :: snd_seq_queue_info_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_free"
    queue_info_free :: snd_seq_queue_info_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_copy"
    queue_info_copy :: snd_seq_queue_info_t *dst, const snd_seq_queue_info_t *src) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_get_queue"
    queue_info_get_queue :: const snd_seq_queue_info_t *info) IO CInt

const char *snd_seq_queue_info_get_name(const snd_seq_queue_info_t *info);
foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_get_owner"
    queue_info_get_owner :: const snd_seq_queue_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_get_locked"
    queue_info_get_locked :: const snd_seq_queue_info_t *info) IO CInt

unsigned int snd_seq_queue_info_get_flags(const snd_seq_queue_info_t *info);

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_set_name"
    queue_info_set_name :: snd_seq_queue_info_t *info, const char *name) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_set_owner"
    queue_info_set_owner :: snd_seq_queue_info_t *info, int owner) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_set_locked"
    queue_info_set_locked :: snd_seq_queue_info_t *info, int locked) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_info_set_flags"
    queue_info_set_flags :: snd_seq_queue_info_t *info, unsigned int flags) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_create_queue"
    create_queue :: T -> snd_seq_queue_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_alloc_named_queue"
    alloc_named_queue :: T -> const char *name) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_alloc_queue"
    alloc_queue :: snd_seq_t *handle) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_free_queue"
    free_queue :: T -> int q) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_get_queue_info"
    get_queue_info :: T -> Queue -> snd_seq_queue_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_set_queue_info"
    set_queue_info :: T -> Queue -> snd_seq_queue_info_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_query_named_queue"
    query_named_queue :: T -> const char *name) IO CInt


foreign import ccall "static alsa/asoundlib.h snd_seq_get_queue_usage"
    get_queue_usage :: T -> Queue -> IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_set_queue_usage"
    set_queue_usage :: T -> Queue -> int used) IO CInt


/*
 */
foreign import ccall "static alsa/asoundlib.h snd_seq_queue_status_sizeof"
    queue_status_sizeof :: void) IO size_t

{- | allocate a #snd_seq_queue_status_t container on stack -}
#define snd_seq_queue_status_alloca(ptr) \
	SND_ALLOCA(snd_seq_queue_status, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_queue_status_malloc"
    queue_status_malloc :: snd_seq_queue_status_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_status_free"
    queue_status_free :: snd_seq_queue_status_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_status_copy"
    queue_status_copy :: snd_seq_queue_status_t *dst, const snd_seq_queue_status_t *src) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_queue_status_get_queue"
    queue_status_get_queue :: const snd_seq_queue_status_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_status_get_events"
    queue_status_get_events :: const snd_seq_queue_status_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_status_get_tick_time"
    queue_status_get_tick_time :: const snd_seq_queue_status_t *info) IO snd_seq_tick_time_t

const snd_seq_real_time_t *snd_seq_queue_status_get_real_time(const snd_seq_queue_status_t *info);
unsigned int snd_seq_queue_status_get_status(const snd_seq_queue_status_t *info);

foreign import ccall "static alsa/asoundlib.h snd_seq_get_queue_status"
    get_queue_status :: T -> Queue -> snd_seq_queue_status_t *status) IO CInt


/*
 */
foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_sizeof"
    queue_tempo_sizeof :: void) IO size_t

{- | allocate a #snd_seq_queue_tempo_t container on stack -}
#define snd_seq_queue_tempo_alloca(ptr) \
	SND_ALLOCA(snd_seq_queue_tempo, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_malloc"
    queue_tempo_malloc :: Ptr Tempo -> IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_free"
    queue_tempo_free :: Tempo -> IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_copy"
    queue_tempo_copy :: Tempo -> const Tempo -> IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_get_queue"
    queue_tempo_get_queue :: const Tempo -> IO CInt

unsigned int snd_seq_queue_tempo_get_tempo(const Tempo ->;
foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_get_ppq"
    queue_tempo_get_ppq :: const Tempo -> IO CInt

unsigned int snd_seq_queue_tempo_get_skew(const Tempo ->;
unsigned int snd_seq_queue_tempo_get_skew_base(const Tempo ->;
foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_set_tempo"
    queue_tempo_set_tempo :: Tempo -> unsigned int tempo) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_set_ppq"
    queue_tempo_set_ppq :: Tempo -> int ppq) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_set_skew"
    queue_tempo_set_skew :: Tempo -> unsigned int skew) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_tempo_set_skew_base"
    queue_tempo_set_skew_base :: Tempo -> unsigned int base) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_get_queue_tempo"
    get_queue_tempo :: T -> Queue -> Tempo -> IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_set_queue_tempo"
    set_queue_tempo :: T -> Queue -> Tempo -> IO CInt


/*
 */

{- | sequencer timer sources -}
typedef enum {
	SND_SEQ_TIMER_ALSA = 0,		/* ALSA timer */
	SND_SEQ_TIMER_MIDI_CLOCK = 1,	/* Midi Clock (CLOCK event) */
	SND_SEQ_TIMER_MIDI_TICK = 2	/* Midi Timer Tick (TICK event */
} snd_seq_queue_timer_type_t;

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_timer_sizeof"
    queue_timer_sizeof :: void) IO size_t

{- | allocate a #snd_seq_queue_timer_t container on stack -}
#define snd_seq_queue_timer_alloca(ptr) \
	SND_ALLOCA(snd_seq_queue_timer, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_queue_timer_malloc"
    queue_timer_malloc :: snd_seq_queue_timer_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_timer_free"
    queue_timer_free :: snd_seq_queue_timer_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_timer_copy"
    queue_timer_copy :: snd_seq_queue_timer_t *dst, const snd_seq_queue_timer_t *src) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_queue_timer_get_queue"
    queue_timer_get_queue :: const snd_seq_queue_timer_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_timer_get_type"
    queue_timer_get_type :: const snd_seq_queue_timer_t *info) IO snd_seq_queue_timer_type_t

const snd_timer_id_t *snd_seq_queue_timer_get_id(const snd_seq_queue_timer_t *info);
unsigned int snd_seq_queue_timer_get_resolution(const snd_seq_queue_timer_t *info);

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_timer_set_type"
    queue_timer_set_type :: snd_seq_queue_timer_t *info, snd_seq_queue_timer_type_t type) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_timer_set_id"
    queue_timer_set_id :: snd_seq_queue_timer_t *info, const snd_timer_id_t *id) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_queue_timer_set_resolution"
    queue_timer_set_resolution :: snd_seq_queue_timer_t *info, unsigned int resolution) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_get_queue_timer"
    get_queue_timer :: T -> Queue -> snd_seq_queue_timer_t *timer) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_set_queue_timer"
    set_queue_timer :: T -> Queue -> snd_seq_queue_timer_t *timer) IO CInt


/** \} */

/**
 *  \defgroup SeqEvent Sequencer Event API
 *  Sequencer Event API
 *  \ingroup Sequencer
 *  \{
 */

foreign import ccall "static alsa/asoundlib.h snd_seq_free_event"
    free_event :: snd_seq_event_t *ev) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_event_length"
    event_length :: snd_seq_event_t *ev) IO ssize_t

foreign import ccall "static alsa/asoundlib.h snd_seq_event_output"
    event_output :: T -> snd_seq_event_t *ev) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_event_output_buffer"
    event_output_buffer :: T -> snd_seq_event_t *ev) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_event_output_direct"
    event_output_direct :: T -> snd_seq_event_t *ev) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_event_input"
    event_input :: T -> snd_seq_event_t **ev) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_event_input_pending"
    event_input_pending :: T -> int fetch_sequencer) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_drain_output"
    drain_output :: snd_seq_t *handle) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_event_output_pending"
    event_output_pending :: snd_seq_t *seq) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_extract_output"
    extract_output :: T -> snd_seq_event_t **ev) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_drop_output"
    drop_output :: snd_seq_t *handle) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_drop_output_buffer"
    drop_output_buffer :: snd_seq_t *handle) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_drop_input"
    drop_input :: snd_seq_t *handle) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_drop_input_buffer"
    drop_input_buffer :: snd_seq_t *handle) IO CInt


{- | event removal conditionals -}
typedef struct _snd_seq_remove_events snd_seq_remove_events_t;

{- | Remove conditional flags -}
#define SND_SEQ_REMOVE_INPUT		(1<<0)	{- | Flush input queues -}
#define SND_SEQ_REMOVE_OUTPUT		(1<<1)	{- | Flush output queues -}
#define SND_SEQ_REMOVE_DEST		(1<<2)	{- | Restrict by destination q:client:port -}
#define SND_SEQ_REMOVE_DEST_CHANNEL	(1<<3)	{- | Restrict by channel -}
#define SND_SEQ_REMOVE_TIME_BEFORE	(1<<4)	{- | Restrict to before time -}
#define SND_SEQ_REMOVE_TIME_AFTER	(1<<5)	{- | Restrict to time or after -}
#define SND_SEQ_REMOVE_TIME_TICK	(1<<6)	{- | Time is in ticks -}
#define SND_SEQ_REMOVE_EVENT_TYPE	(1<<7)	{- | Restrict to event type -}
#define SND_SEQ_REMOVE_IGNORE_OFF 	(1<<8)	{- | Do not flush off events -}
#define SND_SEQ_REMOVE_TAG_MATCH 	(1<<9)	{- | Restrict to events with given tag -}

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_sizeof"
    remove_events_sizeof :: void) IO size_t

{- | allocate a #snd_seq_remove_events_t container on stack -}
#define snd_seq_remove_events_alloca(ptr) \
	SND_ALLOCA(snd_seq_remove_events, ptr)
foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_malloc"
    remove_events_malloc :: snd_seq_remove_events_t **ptr) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_free"
    remove_events_free :: snd_seq_remove_events_t *ptr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_copy"
    remove_events_copy :: snd_seq_remove_events_t *dst, const snd_seq_remove_events_t *src) IO ()


unsigned int snd_seq_remove_events_get_condition(const snd_seq_remove_events_t *info);
foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_get_queue"
    remove_events_get_queue :: const snd_seq_remove_events_t *info) IO CInt

const snd_seq_timestamp_t *snd_seq_remove_events_get_time(const snd_seq_remove_events_t *info);
const snd_seq_addr_t *snd_seq_remove_events_get_dest(const snd_seq_remove_events_t *info);
foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_get_channel"
    remove_events_get_channel :: const snd_seq_remove_events_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_get_event_type"
    remove_events_get_event_type :: const snd_seq_remove_events_t *info) IO CInt

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_get_tag"
    remove_events_get_tag :: const snd_seq_remove_events_t *info) IO CInt


foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_set_condition"
    remove_events_set_condition :: snd_seq_remove_events_t *info, unsigned int flags) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_set_queue"
    remove_events_set_queue :: snd_seq_remove_events_t *info, int queue) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_set_time"
    remove_events_set_time :: snd_seq_remove_events_t *info, const snd_seq_timestamp_t *time) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_set_dest"
    remove_events_set_dest :: snd_seq_remove_events_t *info, const snd_seq_addr_t *addr) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_set_channel"
    remove_events_set_channel :: snd_seq_remove_events_t *info, int channel) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_set_event_type"
    remove_events_set_event_type :: snd_seq_remove_events_t *info, int type) IO ()

foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events_set_tag"
    remove_events_set_tag :: snd_seq_remove_events_t *info, int tag) IO ()


foreign import ccall "static alsa/asoundlib.h snd_seq_remove_events"
    remove_events :: T -> snd_seq_remove_events_t *info) IO CInt

-}



type OpenMode = FlagSet CUInt Open

data Open =
     OpenOutput
   | OpenInput
     deriving (Enum, Eq, Ord, Show, Ix)

openOutput :: OpenMode
openOutput = flagToWord OpenOutput

openInput :: OpenMode
openInput = flagToWord OpenInput

openDuplex :: OpenMode
openDuplex = flagsToWord [OpenOutput, OpenInput]


type PortTypeSet = FlagSet CUInt PortType

data PortType =
     PortTypeSpecific       {- hardware specific -}
   | PortTypeMIDIGeneric    {- generic MIDI device -}
   | PortTypeMIDIGM         {- General MIDI compatible device -}
   | PortTypeMIDIGS         {- GS compatible device -}
   | PortTypeMIDIXG         {- XG compatible device -}
   | PortTypeMIDIMT32       {- MT-32 compatible device -}
   | PortType06
   | PortType07
   | PortType08
   | PortType09
   | PortTypeSynth          {- Synth device -}
   | PortTypeDirectSample   {- Sampling device (support sample download) -}
   | PortTypeSample         {- Sampling device (sample can be downloaded at any time) -}
   | PortType13
   | PortType14
   | PortType15
   | PortType16
   | PortType17
   | PortType18
   | PortType19
   | PortTypeApplication    {- application (sequencer/editor) -}
     deriving (Enum, Eq, Ord, Show, Ix)

portTypeSpecific, portTypeMIDIGeneric,
  portTypeMIDIGM, portTypeMIDIGS, portTypeMIDIXG, portTypeMIDIMT32,
  portTypeSynth, portTypeDirectSample, portTypeSample, portTypeApplication
     :: PortTypeSet

portTypeSpecific     = flagToWord PortTypeSpecific
portTypeMIDIGeneric  = flagToWord PortTypeMIDIGeneric
portTypeMIDIGM       = flagToWord PortTypeMIDIGM
portTypeMIDIGS       = flagToWord PortTypeMIDIGS
portTypeMIDIXG       = flagToWord PortTypeMIDIXG
portTypeMIDIMT32     = flagToWord PortTypeMIDIMT32
portTypeSynth        = flagToWord PortTypeSynth
portTypeDirectSample = flagToWord PortTypeDirectSample
portTypeSample       = flagToWord PortTypeSample
portTypeApplication  = flagToWord PortTypeApplication


type PortCapabilitySet = FlagSet CUInt PortCapability

data PortCapability =
     PortCapRead        {- readable from this port -}
   | PortCapWrite       {- writable to this port -}
   | PortCapSyncRead    {- allow read subscriptions -}
   | PortCapSyncWrite   {- allow write subscriptions -}
   | PortCapDuplex      {- allow read/write duplex -}
   | PortCapSubsRead    {- allow read subscription -}
   | PortCapSubsWrite   {- allow write subscription -}
   | PortCapNoExport    {- routing not allowed -}
     deriving (Enum, Eq, Ord, Show, Ix)


portCapRead, portCapWrite, portCapSyncRead, portCapSyncWrite,
  portCapDuplex, portCapSubsRead, portCapSubsWrite, portCapNoExport :: PortCapabilitySet

portCapRead : portCapWrite : portCapSyncRead : portCapSyncWrite :
  portCapDuplex : portCapSubsRead : portCapSubsWrite : portCapNoExport :
   [] = map flagToWord [PortCapRead ..]



-- * Utility functions

{-| From a list of expressions choose the one,
    whose condition holds. -}
select :: a -> [(Bool, a)] -> a
select def = maybe def snd . find fst

newtype FlagSet word enum = FlagSet {unFlagSet :: word}

-- looks like we are duplicating work from Edison EnumSet
flagToWord :: (Enum a, Bits w) => a -> FlagSet w a
flagToWord = FlagSet . bit . fromEnum

flagsToWord :: (Enum a, Bits w) => [a] -> FlagSet w a
flagsToWord = FlagSet . foldl setBit 0 . map fromEnum

wordToFlags :: (Enum a, Bits w) => FlagSet w a -> [a]
wordToFlags =
   map fst . filter (flip testBit 0 . snd) .
   zip [toEnum 0 ..] . iterate (flip shiftR 1) .
   unFlagSet

intToFlags :: (Enum a, Integral w) => FlagSet w a -> [a]
intToFlags =
   map fst . filter (odd . snd) .
   zip [toEnum 0 ..] . iterate (flip div 2) .
   unFlagSet

unpackEnum ::
   (Enum a, Integral b, Bits b) => b -> EnumBitPos a -> b -> a
unpackEnum mask (EnumBitPos pos) =
   toEnum . fromIntegral . (mask .&.) . flip shiftR pos

packEnum :: (Bits b, Enum a) => EnumBitPos a -> a -> b
packEnum (EnumBitPos pos) =
   flip shiftL pos . fromIntegral . fromEnum



enumToChar :: Enum a => a -> CUChar
enumToChar = fromIntegral . fromEnum

enumFromChar :: Enum a => CUChar -> a
enumFromChar = toEnum . fromIntegral