alsa-seq-0.5: src/Sound/ALSA/Sequencer/Marshal/Event.hsc
--------------------------------------------------------------------------------
-- |
-- Module : Sound.ALSA.Sequencer.Marshal.Event
-- Copyright : (c) Henning Thielemann, 2010
-- (c) Iavor S. Diatchki, 2007
-- License : BSD3
--
-- Maintainer: Henning Thielemann
-- Stability : provisional
--
-- PRIVATE MODULE.
--
-- Here we have the various types used by the library,
-- and how they are imported\/exported to C.
--
-- NOTE: In the translations bellow we make the following assumptions
-- about the sizes of C types.
-- CChar = 8 bits
-- CShort = 16 bit
-- CInt = 32 bits
--------------------------------------------------------------------------------
module Sound.ALSA.Sequencer.Marshal.Event where
#include <alsa/asoundlib.h>
import qualified Sound.ALSA.Sequencer.Marshal.Address as Addr
import qualified Sound.ALSA.Sequencer.Marshal.Queue as Queue
import qualified Sound.ALSA.Sequencer.Marshal.RealTime as RealTime
import Foreign.C.Types (CUInt, )
import Foreign.Storable
(Storable, sizeOf, alignment, peek, poke, pokeByteOff, peekByteOff, )
import Foreign.Ptr (Ptr, castPtr, nullPtr, plusPtr, )
import Foreign.Marshal.Alloc (alloca, )
import Data.Bits ((.|.), (.&.), )
import Data.Int (Int16, Int32, )
import Data.Word (Word8, Word16, Word32, )
import Data.Array (Array, (!), accumArray, )
data Connect = Connect
{ connSource :: !Addr.T
, connDest :: !Addr.T
} deriving (Show,Eq,Ord)
instance Storable Connect where
sizeOf _ = #size snd_seq_connect_t
alignment _ = 4 -- XXX
peek p = do s <- #{peek snd_seq_connect_t, sender} p
d <- #{peek snd_seq_connect_t, dest} p
return Connect { connSource = s, connDest = d }
poke p v = #{poke snd_seq_connect_t, sender} p (connSource v)
>> #{poke snd_seq_connect_t, dest} p (connDest v)
data TimeStamp = TickTime !Word32
| RealTime !RealTime.T
deriving Show
peekTimestamp :: Word8 -> Ptr TimeStamp -> IO TimeStamp
peekTimestamp flags p =
case flags .&. #{const SND_SEQ_TIME_STAMP_MASK} of
{ #{const SND_SEQ_TIME_STAMP_TICK} -> TickTime `fmap` peek (castPtr p)
; _ -> RealTime `fmap` peek (castPtr p)
}
pokeTimestamp :: Ptr TimeStamp -> TimeStamp -> IO Word8
pokeTimestamp p ts = case ts of
TickTime t -> poke (castPtr p) t >> return #{const SND_SEQ_TIME_STAMP_TICK}
RealTime t -> poke (castPtr p) t >> return #{const SND_SEQ_TIME_STAMP_REAL}
newtype InstrCluster = InstrCluster CUInt
deriving (Show,Eq,Ord,Num,Enum,Storable)
data Instr = Instr
{ instrCluster :: !InstrCluster
-- XXX: perhaps use Sample?
, instrStd :: !Word32
, instrBank :: !Word16
, instrPrg :: !Word16
} deriving (Show)
{-
instance Storable Instr where
sizeOf _ = #{size snd_seq_instr_t}
alignment _ = 4 -- XXX
peek p = do cl <- #{peek snd_seq_instr_t, cluster} p
st <- #{peek snd_seq_instr_t, std} p
ba <- #{peek snd_seq_instr_t, bank} p
pr <- #{peek snd_seq_instr_t, prg} p
return Instr { instr_cluster = cl
, instr_std = st
, instr_bank = ba
, instr_prg = pr
}
poke p v = #{poke snd_seq_instr_t, cluster} p (instr_cluster v)
>> #{poke snd_seq_instr_t, std} p (instr_std v)
>> #{poke snd_seq_instr_t, bank} p (instr_bank v)
>> #{poke snd_seq_instr_t, prg} p (instr_prg v)
-}
data Note = Note
{ noteChannel :: !Word8
, noteNote :: !Word8
, noteVelocity :: !Word8
, noteOffVelocity :: !Word8
, noteDuration :: !Word32
} deriving (Show)
instance Storable Note where
sizeOf _ = #{size snd_seq_ev_note_t}
alignment _ = 4 -- XXX
peek p = do c <- #{peek snd_seq_ev_note_t, channel} p
n <- #{peek snd_seq_ev_note_t, note} p
v <- #{peek snd_seq_ev_note_t, velocity} p
ov <- #{peek snd_seq_ev_note_t, off_velocity} p
d <- #{peek snd_seq_ev_note_t, duration} p
return Note { noteChannel = c
, noteNote = n
, noteVelocity = v
, noteOffVelocity = ov
, noteDuration = d
}
poke p v = #{poke snd_seq_ev_note_t, channel} p (noteChannel v)
>> #{poke snd_seq_ev_note_t, note} p (noteNote v)
>> #{poke snd_seq_ev_note_t, velocity} p (noteVelocity v)
>> #{poke snd_seq_ev_note_t, off_velocity} p (noteOffVelocity v)
>> #{poke snd_seq_ev_note_t, duration} p (noteDuration v)
data Ctrl = Ctrl
{ ctrlChannel :: !Word8
, ctrlParam :: !Word32
, ctrlValue :: !Int32
} deriving (Show)
instance Storable Ctrl where
sizeOf _ = #{size snd_seq_ev_ctrl_t}
alignment _ = 4 -- XXX
peek p = do ct <- #{peek snd_seq_ev_ctrl_t, channel} p
pa <- #{peek snd_seq_ev_ctrl_t, param} p
va <- #{peek snd_seq_ev_ctrl_t, value} p
return Ctrl { ctrlChannel = ct
, ctrlParam = pa
, ctrlValue = va
}
poke p v = #{poke snd_seq_ev_ctrl_t, channel} p (ctrlChannel v)
>> #{poke snd_seq_ev_ctrl_t, param} p (ctrlParam v)
>> #{poke snd_seq_ev_ctrl_t, value} p (ctrlValue v)
data Sample = Sample
{ sampleStd :: !Word32
, sampleBank :: !Word16
, samplePrg :: !Word16
} deriving (Show)
{-
instance Storable Sample where
sizeOf _ = #{size snd_seq_ev_sample_t}
alignment _ = 4 -- XXX
peek p = do st <- #{peek snd_seq_ev_sample_t, std} p
ba <- #{peek snd_seq_ev_sample_t, bank} p
pr <- #{peek snd_seq_ev_sample_t, prg} p
return Sample { sample_std = st
, sample_bank = ba
, sample_prg = pr
}
poke p v = #{poke snd_seq_ev_sample_t, std} p (sampleStd v)
>> #{poke snd_seq_ev_sample_t, bank} p (sampleBank v)
>> #{poke snd_seq_ev_sample_t, prg} p (samplePrg v)
-}
newtype Cluster = Cluster
{ clusterCluster :: InstrCluster
} deriving (Show, Eq, Storable)
-- | These are all 14 bit values.
data Volume = Volume
{ volumeVolume :: !Int16
, volumeLR :: !Int16
, volumeFR :: !Int16
, volumeDU :: !Int16
} deriving (Show)
{-
instance Storable Volume where
sizeOf _ = #{size snd_seq_ev_volume_t}
alignment _ = 4 -- XXX
peek p = do v <- #{peek snd_seq_ev_volume_t, volume} p
l <- #{peek snd_seq_ev_volume_t, lr} p
f <- #{peek snd_seq_ev_volume_t, fr} p
d <- #{peek snd_seq_ev_volume_t, du} p
return Volume { volume_volume = v
, volume_lr = l
, volume_fr = f
, volume_du = d
}
poke p v = #{poke snd_seq_ev_volume_t, volume} p (volumeVolume v)
>> #{poke snd_seq_ev_volume_t, lr} p (volumeLR v)
>> #{poke snd_seq_ev_volume_t, fr} p (volumeFR v)
>> #{poke snd_seq_ev_volume_t, du} p (volumeDU v)
-}
data Custom = Custom { custom0, custom1, custom2 :: !Word32 }
deriving (Show)
instance Storable Custom where
sizeOf _ = #{size snd_seq_ev_raw32_t}
alignment _ = 4 -- XXX
peek p = do d0 <- #{peek snd_seq_ev_raw32_t, d[0]} p
d1 <- #{peek snd_seq_ev_raw32_t, d[1]} p
d2 <- #{peek snd_seq_ev_raw32_t, d[2]} p
return Custom { custom0 = d0
, custom1 = d1
, custom2 = d2
}
poke p v = #{poke snd_seq_ev_raw32_t, d[0]} p (custom0 v)
>> #{poke snd_seq_ev_raw32_t, d[1]} p (custom1 v)
>> #{poke snd_seq_ev_raw32_t, d[2]} p (custom2 v)
data T = Cons
{ highPriority :: !Bool
, tag :: !Word8
, queue :: !Queue.T
, timestamp :: !TimeStamp
, source :: !Addr.T
, dest :: !Addr.T
, body :: !Data
} deriving Show
instance Storable T where
sizeOf _ = #{size snd_seq_event_t}
alignment _ = 4 -- XXX
peek p =
do ty <- #{peek snd_seq_event_t, type} p
flags <- #{peek snd_seq_event_t, flags} p
tg <- #{peek snd_seq_event_t, tag} p
q <- #{peek snd_seq_event_t, queue} p
time <- peekTimestamp flags (#{ptr snd_seq_event_t, time} p)
src <- #{peek snd_seq_event_t, source} p
dst <- #{peek snd_seq_event_t, dest} p
d <- (peekData ! ty) (#{ptr snd_seq_event_t, data} p)
return Cons
{ highPriority = (flags .&. #{const SND_SEQ_PRIORITY_MASK}) /= 0
, tag = tg
, queue = q
, timestamp = time
, source = src
, dest = dst
, body = d
}
poke p e = do
{ ty <- pokeData (#{ptr snd_seq_event_t, data} p) (body e)
; #{poke snd_seq_event_t, type} p ty
; #{poke snd_seq_event_t, tag} p (tag e)
; #{poke snd_seq_event_t, queue} p (queue e)
; real <- pokeTimestamp (#{ptr snd_seq_event_t, time} p) (timestamp e)
; #{poke snd_seq_event_t, source} p (source e)
; #{poke snd_seq_event_t, dest} p (dest e)
; let flags = (if highPriority e
then #{const SND_SEQ_PRIORITY_HIGH}
else #{const SND_SEQ_PRIORITY_NORMAL})
.|. real
.|. #{const SND_SEQ_EVENT_LENGTH_FIXED} -- XXX
; #{poke snd_seq_event_t, flags} p flags
}
allocaEv :: T -> (Ptr T -> IO a) -> IO a
allocaEv e h = alloca (\p -> poke p e >> h p)
allocaMaybeEv :: Maybe T -> (Ptr T -> IO a) -> IO a
allocaMaybeEv me h =
maybe (h nullPtr) (\e -> allocaEv e h) me
pokeData :: Ptr Data -> Data -> IO Word8
pokeData p dt = case dt of
NoteEv e d -> poke (castPtr p) d >> return (expNoteEv e)
CtrlEv e d -> poke (castPtr p) d >> return (expCtrlEv e)
AddrEv e d -> poke (castPtr p) d >> return (expAddrEv e)
ConnEv e d -> poke (castPtr p) d >> return (expConnEv e)
CustomEv e d -> poke (castPtr p) d >> return (expCustomEv e)
EmptyEv e -> return (expEmptyEv e)
peekData :: Array Word8 (Ptr Data -> IO Data)
peekData = accumArray (const id) unknown (0,255)
[ -- result events (2)
(#{const SND_SEQ_EVENT_SYSTEM}, unknown)
, (#{const SND_SEQ_EVENT_RESULT}, unknown)
-- note events (4)
, (#{const SND_SEQ_EVENT_NOTE}, peekNoteEv ANote)
, (#{const SND_SEQ_EVENT_NOTEON}, peekNoteEv NoteOn)
, (#{const SND_SEQ_EVENT_NOTEOFF}, peekNoteEv NoteOff)
, (#{const SND_SEQ_EVENT_KEYPRESS}, peekNoteEv KeyPress)
-- control events (12)
, (#{const SND_SEQ_EVENT_CONTROLLER}, peekCtrlEv Controller)
, (#{const SND_SEQ_EVENT_PGMCHANGE}, peekCtrlEv PgmChange)
, (#{const SND_SEQ_EVENT_CHANPRESS}, peekCtrlEv ChanPress)
, (#{const SND_SEQ_EVENT_PITCHBEND}, peekCtrlEv PitchBend)
, (#{const SND_SEQ_EVENT_CONTROL14}, peekCtrlEv Control14)
, (#{const SND_SEQ_EVENT_NONREGPARAM}, peekCtrlEv NonRegParam)
, (#{const SND_SEQ_EVENT_REGPARAM}, peekCtrlEv RegParam)
, (#{const SND_SEQ_EVENT_SONGPOS}, peekCtrlEv SongPos)
, (#{const SND_SEQ_EVENT_SONGSEL}, peekCtrlEv SongSel)
, (#{const SND_SEQ_EVENT_QFRAME}, peekCtrlEv QFrame)
, (#{const SND_SEQ_EVENT_TIMESIGN}, peekCtrlEv TimeSign)
, (#{const SND_SEQ_EVENT_KEYSIGN}, peekCtrlEv KeySign)
-- queue control (10)
, (#{const SND_SEQ_EVENT_START}, unknown)
, (#{const SND_SEQ_EVENT_CONTINUE}, unknown)
, (#{const SND_SEQ_EVENT_STOP}, unknown)
, (#{const SND_SEQ_EVENT_SETPOS_TICK}, unknown)
, (#{const SND_SEQ_EVENT_SETPOS_TIME}, unknown)
, (#{const SND_SEQ_EVENT_TEMPO}, unknown)
, (#{const SND_SEQ_EVENT_CLOCK}, unknown)
, (#{const SND_SEQ_EVENT_TICK}, unknown)
, (#{const SND_SEQ_EVENT_QUEUE_SKEW}, unknown)
, (#{const SND_SEQ_EVENT_SYNC_POS}, unknown)
-- misc (3)
, (#{const SND_SEQ_EVENT_TUNE_REQUEST}, peekEmptyEv TuneRequest)
, (#{const SND_SEQ_EVENT_RESET}, peekEmptyEv Reset)
, (#{const SND_SEQ_EVENT_SENSING}, peekEmptyEv Sensing)
, (#{const SND_SEQ_EVENT_ECHO}, peekCustomEv Echo)
, (#{const SND_SEQ_EVENT_OSS}, peekCustomEv OSS)
-- networking (8)
, (#{const SND_SEQ_EVENT_CLIENT_START}, peekAddrEv ClientStart)
, (#{const SND_SEQ_EVENT_CLIENT_EXIT}, peekAddrEv ClientExit)
, (#{const SND_SEQ_EVENT_CLIENT_CHANGE}, peekAddrEv ClientChange)
, (#{const SND_SEQ_EVENT_PORT_START}, peekAddrEv PortStart)
, (#{const SND_SEQ_EVENT_PORT_EXIT}, peekAddrEv PortExit)
, (#{const SND_SEQ_EVENT_PORT_CHANGE}, peekAddrEv PortChange)
, (#{const SND_SEQ_EVENT_PORT_SUBSCRIBED}, peekConnEv PortSubscribed)
, (#{const SND_SEQ_EVENT_PORT_UNSUBSCRIBED}, peekConnEv PortUnsubscribed)
{-
, (#{const SND_SEQ_EVENT_SAMPLE}, unknown)
, (#{const SND_SEQ_EVENT_SAMPLE_CLUSTER}, unknown)
, (#{const SND_SEQ_EVENT_SAMPLE_START}, unknown)
, (#{const SND_SEQ_EVENT_SAMPLE_STOP}, unknown)
, (#{const SND_SEQ_EVENT_SAMPLE_FREQ}, unknown)
, (#{const SND_SEQ_EVENT_SAMPLE_VOLUME}, unknown)
, (#{const SND_SEQ_EVENT_SAMPLE_LOOP}, unknown)
, (#{const SND_SEQ_EVENT_SAMPLE_POSITION}, unknown)
, (#{const SND_SEQ_EVENT_SAMPLE_PRIVATE1}, unknown)
-}
, (#{const SND_SEQ_EVENT_USR0}, peekCustomEv User0)
, (#{const SND_SEQ_EVENT_USR1}, peekCustomEv User1)
, (#{const SND_SEQ_EVENT_USR2}, peekCustomEv User2)
, (#{const SND_SEQ_EVENT_USR3}, peekCustomEv User3)
, (#{const SND_SEQ_EVENT_USR4}, peekCustomEv User4)
, (#{const SND_SEQ_EVENT_USR5}, peekCustomEv User5)
, (#{const SND_SEQ_EVENT_USR6}, peekCustomEv User6)
, (#{const SND_SEQ_EVENT_USR7}, peekCustomEv User7)
, (#{const SND_SEQ_EVENT_USR8}, peekCustomEv User8)
, (#{const SND_SEQ_EVENT_USR9}, peekCustomEv User9)
{-
, (#{const SND_SEQ_EVENT_INSTR_BEGIN}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_END}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_INFO}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_INFO_RESULT}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_FINFO}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_FINFO_RESULT}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_RESET}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_STATUS}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_STATUS_RESULT}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_PUT}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_GET}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_GET_RESULT}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_FREE}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_LIST}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_LIST_RESULT}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_CLUSTER}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_CLUSTER_GET}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_CLUSTER_RESULT}, unknown)
, (#{const SND_SEQ_EVENT_INSTR_CHANGE}, unknown)
-}
, (#{const SND_SEQ_EVENT_SYSEX}, unknown)
, (#{const SND_SEQ_EVENT_BOUNCE}, unknown)
, (#{const SND_SEQ_EVENT_USR_VAR0}, unknown)
, (#{const SND_SEQ_EVENT_USR_VAR1}, unknown)
, (#{const SND_SEQ_EVENT_USR_VAR2}, unknown)
, (#{const SND_SEQ_EVENT_USR_VAR3}, unknown)
, (#{const SND_SEQ_EVENT_USR_VAR3}, unknown)
, (#{const SND_SEQ_EVENT_NONE}, peekEmptyEv None)
]
where unknown = peekEmptyEv Unknown
data NoteEv = ANote | NoteOn | NoteOff | KeyPress
deriving Show
data CtrlEv = Controller | PgmChange | ChanPress
| PitchBend | Control14
| NonRegParam | RegParam
| SongPos | SongSel
| QFrame
| TimeSign | KeySign
deriving Show
data QueueEv = QueueStart
| QueueContinue
| QueueStop
| QueueSetPosTick
| QueueSetPosTime
| QueueTempo
| QueueClock
| QueueTick
| QueueSkew
| QueueSyncPos
deriving Show
data EmptyEv = TuneRequest | Reset | Sensing | None | Unknown
deriving Show
data CustomEv = Echo | OSS
| User0 | User1 | User2 | User3 | User4
| User5 | User6 | User7 | User8 | User9
deriving Show
data AddrEv = ClientStart | ClientExit | ClientChange
| PortStart | PortExit | PortChange
deriving Show
data ConnEv = PortSubscribed | PortUnsubscribed
deriving Show
expNoteEv :: NoteEv -> Word8
expNoteEv e = case e of
ANote -> #{const SND_SEQ_EVENT_NOTE}
NoteOn -> #{const SND_SEQ_EVENT_NOTEON}
NoteOff -> #{const SND_SEQ_EVENT_NOTEOFF}
KeyPress -> #{const SND_SEQ_EVENT_KEYPRESS}
expCtrlEv :: CtrlEv -> Word8
expCtrlEv e = case e of
Controller -> #{const SND_SEQ_EVENT_CONTROLLER}
PgmChange -> #{const SND_SEQ_EVENT_PGMCHANGE}
ChanPress -> #{const SND_SEQ_EVENT_CHANPRESS}
PitchBend -> #{const SND_SEQ_EVENT_PITCHBEND}
Control14 -> #{const SND_SEQ_EVENT_CONTROL14}
NonRegParam -> #{const SND_SEQ_EVENT_NONREGPARAM}
RegParam -> #{const SND_SEQ_EVENT_REGPARAM}
SongPos -> #{const SND_SEQ_EVENT_SONGPOS}
SongSel -> #{const SND_SEQ_EVENT_SONGSEL}
QFrame -> #{const SND_SEQ_EVENT_QFRAME}
TimeSign -> #{const SND_SEQ_EVENT_TIMESIGN}
KeySign -> #{const SND_SEQ_EVENT_KEYSIGN}
expQueueEv :: QueueEv -> Word8
expQueueEv e = case e of
QueueStart -> #{const SND_SEQ_EVENT_START}
QueueContinue -> #{const SND_SEQ_EVENT_CONTINUE}
QueueStop -> #{const SND_SEQ_EVENT_STOP}
QueueSetPosTick -> #{const SND_SEQ_EVENT_SETPOS_TICK}
QueueSetPosTime -> #{const SND_SEQ_EVENT_SETPOS_TIME}
QueueTempo -> #{const SND_SEQ_EVENT_TEMPO}
QueueClock -> #{const SND_SEQ_EVENT_CLOCK}
QueueTick -> #{const SND_SEQ_EVENT_TICK}
QueueSkew -> #{const SND_SEQ_EVENT_QUEUE_SKEW}
QueueSyncPos -> #{const SND_SEQ_EVENT_SYNC_POS}
expEmptyEv :: EmptyEv -> Word8
expEmptyEv e = case e of
TuneRequest -> #{const SND_SEQ_EVENT_TUNE_REQUEST}
Reset -> #{const SND_SEQ_EVENT_RESET}
Sensing -> #{const SND_SEQ_EVENT_SENSING}
None -> #{const SND_SEQ_EVENT_NONE}
Unknown -> #{const SND_SEQ_EVENT_NONE}
expCustomEv :: CustomEv -> Word8
expCustomEv e = case e of
Echo -> #{const SND_SEQ_EVENT_ECHO}
OSS -> #{const SND_SEQ_EVENT_OSS}
User0 -> #{const SND_SEQ_EVENT_USR0}
User1 -> #{const SND_SEQ_EVENT_USR1}
User2 -> #{const SND_SEQ_EVENT_USR2}
User3 -> #{const SND_SEQ_EVENT_USR3}
User4 -> #{const SND_SEQ_EVENT_USR4}
User5 -> #{const SND_SEQ_EVENT_USR5}
User6 -> #{const SND_SEQ_EVENT_USR6}
User7 -> #{const SND_SEQ_EVENT_USR7}
User8 -> #{const SND_SEQ_EVENT_USR8}
User9 -> #{const SND_SEQ_EVENT_USR9}
expAddrEv :: AddrEv -> Word8
expAddrEv e = case e of
ClientStart -> #{const SND_SEQ_EVENT_CLIENT_START}
ClientExit -> #{const SND_SEQ_EVENT_CLIENT_EXIT}
ClientChange -> #{const SND_SEQ_EVENT_CLIENT_CHANGE}
PortStart -> #{const SND_SEQ_EVENT_PORT_START}
PortExit -> #{const SND_SEQ_EVENT_PORT_EXIT}
PortChange -> #{const SND_SEQ_EVENT_PORT_CHANGE}
expConnEv :: ConnEv -> Word8
expConnEv e = case e of
PortSubscribed -> #{const SND_SEQ_EVENT_PORT_SUBSCRIBED}
PortUnsubscribed -> #{const SND_SEQ_EVENT_PORT_UNSUBSCRIBED}
peekNoteEv :: NoteEv -> Ptr Data -> IO Data
peekNoteEv e p = NoteEv e `fmap` peek (castPtr p)
peekCtrlEv :: CtrlEv -> Ptr Data -> IO Data
peekCtrlEv e p = CtrlEv e `fmap` peek (castPtr p)
peekAddrEv :: AddrEv -> Ptr Data -> IO Data
peekAddrEv e p = AddrEv e `fmap` peek (castPtr p)
peekConnEv :: ConnEv -> Ptr Data -> IO Data
peekConnEv e p = ConnEv e `fmap` peek (castPtr p)
peekEmptyEv :: EmptyEv -> Ptr Data -> IO Data
peekEmptyEv e _ = return (EmptyEv e)
peekCustomEv :: CustomEv -> Ptr Data -> IO Data
peekCustomEv e p = CustomEv e `fmap` peek (castPtr p)
data Data
= NoteEv NoteEv Note
| CtrlEv CtrlEv Ctrl
| AddrEv AddrEv Addr.T
| ConnEv ConnEv Connect
| EmptyEv EmptyEv
| CustomEv CustomEv Custom
deriving Show