{- |
MIDI messages for real-time communication with MIDI devices.
This does not cover MIDI file events.
For these refer to "Sound.MIDI.File.Event".
-}
module Sound.MIDI.Message (
   T(..),
   get, getWithStatus, getIncompleteWithStatus,
   put, putWithStatus,
   maybeFromByteString, toByteString,
   ) where

import qualified Sound.MIDI.Message.Channel as Channel
import qualified Sound.MIDI.Message.System  as System

import qualified Sound.MIDI.Parser.Status as StatusParser
import qualified Sound.MIDI.Parser.Class  as Parser
import           Sound.MIDI.Parser.Primitive (get1)
import qualified Sound.MIDI.Parser.ByteString as ParserByteString

import qualified Sound.MIDI.Writer.Status as StatusWriter
import qualified Sound.MIDI.Writer.Basic  as Writer
import Sound.MIDI.Monoid ((+#+))

import qualified Sound.MIDI.Parser.Report as Report

import qualified Control.Monad.Exception.Asynchronous as Async

import Control.Monad (liftM, )

import qualified Data.ByteString.Lazy as B


data T =
     Channel Channel.T
   | System  System.T
-- Show instance requires Show instance of System.T
--     deriving (Show)


get :: Parser.C parser => Parser.Fragile parser T
get :: forall (parser :: * -> *). C parser => Fragile parser T
get =
   forall (parser :: * -> *). C parser => Fragile parser Int
get1 forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Int
code ->
   if Int
code forall a. Ord a => a -> a -> Bool
>= Int
0xF0
     then forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM T -> T
System  forall a b. (a -> b) -> a -> b
$ forall (parser :: * -> *). C parser => Int -> Fragile parser T
System.get Int
code
     else forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM T -> T
Channel forall a b. (a -> b) -> a -> b
$ (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry forall (parser :: * -> *).
C parser =>
Int -> Channel -> Int -> Fragile parser T
Channel.get (Int -> (Int, Channel)
Channel.decodeStatus Int
code) forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (parser :: * -> *). C parser => Fragile parser Int
get1)
--     else liftM Channel $ StatusParser.run (Channel.getWithStatus code)

getWithStatus :: Parser.C parser => Parser.Fragile (StatusParser.T parser) T
getWithStatus :: forall (parser :: * -> *). C parser => Fragile (T parser) T
getWithStatus =
   forall (parser :: * -> *) a.
Monad parser =>
Fragile parser a -> Fragile (T parser) a
StatusParser.lift forall (parser :: * -> *). C parser => Fragile parser Int
get1 forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Int
code ->
   if Int
code forall a. Ord a => a -> a -> Bool
>= Int
0xF0
     then forall (parser :: * -> *).
Monad parser =>
Status -> Fragile (T parser) ()
StatusParser.set forall a. Maybe a
Nothing forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
          (forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM T -> T
System forall a b. (a -> b) -> a -> b
$ forall (parser :: * -> *) a.
Monad parser =>
Fragile parser a -> Fragile (T parser) a
StatusParser.lift forall a b. (a -> b) -> a -> b
$ forall (parser :: * -> *). C parser => Int -> Fragile parser T
System.get Int
code)
     else forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM T -> T
Channel forall a b. (a -> b) -> a -> b
$ forall (parser :: * -> *). C parser => Int -> Fragile (T parser) T
Channel.getWithStatus Int
code

getIncompleteWithStatus ::
   Parser.C parser => Parser.Partial (Parser.Fragile (StatusParser.T parser)) T
getIncompleteWithStatus :: forall (parser :: * -> *).
C parser =>
Partial (Fragile (T parser)) T
getIncompleteWithStatus =
   forall (parser :: * -> *) a.
Monad parser =>
Fragile parser a -> Fragile (T parser) a
StatusParser.lift forall (parser :: * -> *). C parser => Fragile parser Int
get1 forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Int
code ->
   if Int
code forall a. Ord a => a -> a -> Bool
>= Int
0xF0
     then forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap T -> T
System) forall a b. (a -> b) -> a -> b
$ forall (parser :: * -> *) a.
Monad parser =>
Fragile parser a -> Fragile (T parser) a
StatusParser.lift forall a b. (a -> b) -> a -> b
$ forall (parser :: * -> *).
C parser =>
Int -> Partial (Fragile parser) T
System.getIncomplete Int
code
     else forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall a e. a -> Exceptional e a
Async.pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. T -> T
Channel) forall a b. (a -> b) -> a -> b
$ forall (parser :: * -> *). C parser => Int -> Fragile (T parser) T
Channel.getWithStatus Int
code

maybeFromByteString :: B.ByteString -> Report.T T
maybeFromByteString :: ByteString -> T T
maybeFromByteString =
   forall a. Fragile T a -> ByteString -> T a
ParserByteString.run forall (parser :: * -> *). C parser => Fragile parser T
get




put :: Writer.C writer => T -> writer
put :: forall writer. C writer => T -> writer
put T
msg =
   case T
msg of
      Channel T
s -> forall writer. C writer => T -> writer
Channel.put T
s
      System  T
s -> forall writer. C writer => T -> writer
System.put  T
s

putWithStatus ::
   (StatusWriter.Compression compress, Writer.C writer) =>
   T -> StatusWriter.T compress writer
putWithStatus :: forall compress writer.
(Compression compress, C writer) =>
T -> T compress writer
putWithStatus T
msg =
   case T
msg of
      Channel T
s -> forall compress writer.
(Compression compress, C writer) =>
T -> T compress writer
Channel.putWithStatus T
s
      System  T
s -> forall compress writer.
(Compression compress, Monoid writer) =>
T compress writer
StatusWriter.clear forall m. Monoid m => m -> m -> m
+#+ forall (t :: * -> *) m. (C t, Monoid m) => m -> t m
StatusWriter.lift (forall writer. C writer => T -> writer
System.put T
s)

toByteString :: T -> B.ByteString
toByteString :: T -> ByteString
toByteString =
   ByteString -> ByteString
Writer.runByteString forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall writer. C writer => T -> writer
put