midi-simple-0.1.0.0: src/Sound/MIDI.hs
module Sound.MIDI
(
-- * Encoding
encodeMidi,
encodeMidi',
encodeMidi1,
encodeMidi1',
-- * Decoding
decodeMidi,
decodeMidi1,
partitionRealtime,
-- * Parser and Serializer
--
-- | Top level parsing and serializing tools are exposed here. For
-- fine-grained access, see "Sound.MIDI.Parser" and "Sound.MIDI.Serialize".
midiParser,
midiSerializer,
-- * Re-exports
module Sound.MIDI.Types
)
where
import Control.Applicative
import Data.Functor.Identity
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.ByteString.Builder (toLazyByteString, Builder)
import qualified Data.Attoparsec.ByteString as A
import Sound.MIDI.Types
import qualified Sound.MIDI.Parser as P
import qualified Sound.MIDI.Serialize as S
-- | Encode some collection of 'MidiMessage's to a lazy 'BL.ByteString'
encodeMidi :: Foldable t => t MidiMessage -> BL.ByteString
encodeMidi = toLazyByteString . foldMap S.midiMessage
{-# SPECIALISE encodeMidi :: [MidiMessage] -> BL.ByteString #-}
-- | Strict version of 'encodeMidi'
encodeMidi' :: Foldable t => t MidiMessage -> BS.ByteString
encodeMidi' = BL.toStrict . encodeMidi
{-# SPECIALISE encodeMidi' :: [MidiMessage] -> BS.ByteString #-}
-- | Encode a single message to a lazy 'BL.ByteString'
encodeMidi1 :: MidiMessage -> BL.ByteString
encodeMidi1 = encodeMidi . Identity
-- | Strict version of 'encodeMidi1'
encodeMidi1' :: MidiMessage -> BS.ByteString
encodeMidi1' = encodeMidi' . Identity
-- | Decode raw MIDI data from a strict 'ByteString'. Any incomplete data at the
-- beginning will be skipped! This function assumes a normalized MIDI stream,
-- i.e. one in which events are /not/ interrupted by real-time events!
decodeMidi :: BS.ByteString -> Either String [MidiMessage]
decodeMidi = A.parseOnly (P.skipToStatus *> some P.midiMessage)
-- | Decode one event from raw MIDI data in a strict 'ByteString'. Any
-- incomplete data at the beginning will be skipped!
decodeMidi1 :: BS.ByteString -> Either String MidiMessage
decodeMidi1 = A.parseOnly (P.skipToStatus *> P.midiMessage)
-- | Partition an event stream into real-time events and other messages. The
-- first parameter returned will be the real-time events, the second element
-- will be the rest of the stream. Note that this effectively normalizes the
-- second element.
partitionRealtime :: BS.ByteString -> (BS.ByteString, BS.ByteString)
partitionRealtime = BS.partition isRT
where isRT x = x >= 0xF8 && x <= 0xFF
midiParser :: A.Parser MidiMessage
midiParser = P.midiMessage
midiSerializer :: MidiMessage -> Builder
midiSerializer = S.midiMessage