midi 0.1.3.2 → 0.1.4
raw patch · 17 files changed
+210/−151 lines, 17 filesdep +monoid-transformerdep ~event-listPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: monoid-transformer
Dependency ranges changed: event-list
API changes (from Hackage documentation)
- Sound.MIDI.IO: openBinaryFile :: FilePath -> IOMode -> IO Handle
- Sound.MIDI.File.Event: put :: (C writer) => T -> T writer ()
+ Sound.MIDI.File.Event: put :: (C writer) => T -> T writer
- Sound.MIDI.File.Event.Meta: put :: (C writer) => T -> writer ()
+ Sound.MIDI.File.Event.Meta: put :: (C writer) => T -> writer
- Sound.MIDI.File.Event.SystemExclusive: put :: (C writer) => T -> writer ()
+ Sound.MIDI.File.Event.SystemExclusive: put :: (C writer) => T -> writer
- Sound.MIDI.Manufacturer: put :: (C writer) => T -> writer ()
+ Sound.MIDI.Manufacturer: put :: (C writer) => T -> writer
- Sound.MIDI.Message: put :: (C writer) => T -> writer ()
+ Sound.MIDI.Message: put :: (C writer) => T -> writer
- Sound.MIDI.Message: putWithStatus :: (C writer) => T -> T writer ()
+ Sound.MIDI.Message: putWithStatus :: (C writer) => T -> T writer
- Sound.MIDI.Message.Channel: put :: (C writer) => T -> writer ()
+ Sound.MIDI.Message.Channel: put :: (C writer) => T -> writer
- Sound.MIDI.Message.Channel: putWithStatus :: (C writer) => T -> T writer ()
+ Sound.MIDI.Message.Channel: putWithStatus :: (C writer) => T -> T writer
- Sound.MIDI.Message.Channel.Mode: put :: (C writer) => T -> writer ()
+ Sound.MIDI.Message.Channel.Mode: put :: (C writer) => T -> writer
- Sound.MIDI.Message.Channel.Voice: putWithStatus :: (C writer) => (Int -> T writer ()) -> T -> T writer ()
+ Sound.MIDI.Message.Channel.Voice: putWithStatus :: (C writer) => (Int -> T writer) -> T -> T writer
- Sound.MIDI.Message.System: put :: (C writer) => T -> writer ()
+ Sound.MIDI.Message.System: put :: (C writer) => T -> writer
- Sound.MIDI.Message.System.Common: put :: (C writer) => T -> writer ()
+ Sound.MIDI.Message.System.Common: put :: (C writer) => T -> writer
- Sound.MIDI.Message.System.Exclusive: put :: (C writer) => T -> writer ()
+ Sound.MIDI.Message.System.Exclusive: put :: (C writer) => T -> writer
- Sound.MIDI.Message.System.RealTime: put :: (C writer) => T -> writer ()
+ Sound.MIDI.Message.System.RealTime: put :: (C writer) => T -> writer
Files
- midi.cabal +10/−5
- src/Sound/MIDI/File/Event.hs +5/−5
- src/Sound/MIDI/File/Event/Meta.hs +14/−14
- src/Sound/MIDI/File/Event/SystemExclusive.hs +4/−3
- src/Sound/MIDI/File/Save.hs +22/−23
- src/Sound/MIDI/Manufacturer.hs +4/−3
- src/Sound/MIDI/Message.hs +4/−4
- src/Sound/MIDI/Message/Channel.hs +8/−8
- src/Sound/MIDI/Message/Channel/Mode.hs +1/−1
- src/Sound/MIDI/Message/Channel/Voice.hs +4/−2
- src/Sound/MIDI/Message/System.hs +1/−1
- src/Sound/MIDI/Message/System/Common.hs +6/−5
- src/Sound/MIDI/Message/System/Exclusive.hs +6/−5
- src/Sound/MIDI/Message/System/RealTime.hs +1/−1
- src/Sound/MIDI/Monoid.hs +26/−0
- src/Sound/MIDI/Writer/Basic.hs +57/−41
- src/Sound/MIDI/Writer/Status.hs +37/−30
midi.cabal view
@@ -1,5 +1,5 @@ Name: midi-Version: 0.1.3.2+Version: 0.1.4 License: GPL License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de>@@ -25,7 +25,7 @@ Source-Repository this type: darcs location: http://darcs.haskell.org/midi/- tag: 0.1.3.2+ tag: 0.1.4 Flag splitBase description: Choose the new smaller, split-up base package.@@ -35,10 +35,12 @@ default: False Library- Build-Depends: event-list >=0.0.6 && < 0.1, non-negative>=0.0.1 && <0.1+ Build-Depends: event-list >=0.0.9 && < 0.1, non-negative>=0.0.1 && <0.1 Build-Depends: explicit-exception >=0.1 && <0.2 Build-Depends: bytestring >=0.9.0.1 && <0.10, binary >=0.4.2 && <0.5- Build-Depends: transformers >=0.0.1 && <0.2, QuickCheck >=1 && <2+ Build-Depends: transformers >=0.0.1 && <0.2+ Build-Depends: monoid-transformer >=0.0.1 && <0.1+ Build-Depends: QuickCheck >=1 && <2 If flag(splitBase) Build-Depends: base >= 2, random >=1 && <2 Else@@ -67,7 +69,6 @@ -- exports ByteList data type Sound.MIDI.IO Other-Modules:- Sound.MIDI.Bit -- Parser class and general parser functions Sound.MIDI.Parser.Class Sound.MIDI.Parser.Restricted@@ -79,8 +80,12 @@ Sound.MIDI.Parser.File Sound.MIDI.Parser.Stream Sound.MIDI.Parser.ByteString+ -- output basics Sound.MIDI.Writer.Basic Sound.MIDI.Writer.Status+ -- utilities+ Sound.MIDI.Bit+ Sound.MIDI.Monoid Sound.MIDI.String Sound.MIDI.Utility
src/Sound/MIDI/File/Event.hs view
@@ -29,12 +29,12 @@ import qualified Sound.MIDI.Parser.Status as StatusParser import qualified Sound.MIDI.Parser.Class as Parser -import Control.Monad.Trans (lift, ) import Control.Monad (liftM, liftM2, ) import qualified Sound.MIDI.Writer.Status as StatusWriter import qualified Sound.MIDI.Writer.Basic as Writer +import Sound.MIDI.Monoid ((+#+)) import Sound.MIDI.Utility (mapSnd) @@ -110,9 +110,9 @@ into the raw data of a standard MIDI file. -} -put :: Writer.C writer => T -> StatusWriter.T writer ()+put :: Writer.C writer => T -> StatusWriter.T writer put e = case e of- MIDIEvent m -> lift (ChannelMsg.put m)- MetaEvent m -> StatusWriter.clear >> lift (MetaEvent.put m)- SystemExclusive m -> StatusWriter.clear >> lift (SysEx.put m)+ MIDIEvent m -> StatusWriter.lift (ChannelMsg.put m)+ MetaEvent m -> StatusWriter.clear +#+ StatusWriter.lift (MetaEvent.put m)+ SystemExclusive m -> StatusWriter.clear +#+ StatusWriter.lift (SysEx.put m)
src/Sound/MIDI/File/Event/Meta.hs view
@@ -18,6 +18,8 @@ import qualified Sound.MIDI.Writer.Basic as Writer import qualified Sound.MIDI.Bit as Bit +import Sound.MIDI.Monoid ((+#+))+ import qualified Numeric.NonNegative.Wrapper as NonNeg import Sound.MIDI.IO (ByteList, listCharFromByte, listByteFromChar, ) @@ -206,9 +208,9 @@ -put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put ev =- Writer.putByte 255 >>+ Writer.putByte 255 +#+ case ev of SequenceNum num -> putInt 0 2 num TextEvent s -> putStr 1 s@@ -235,24 +237,22 @@ Unknown typ s -> putByteList typ s -putByteList :: Writer.C writer => Int -> ByteList -> writer ()+putByteList :: Writer.C writer => Int -> ByteList -> writer putByteList code bytes =- do- Writer.putIntAsByte code- Writer.putLenByteList bytes+ Writer.putIntAsByte code +#++ Writer.putLenByteList bytes -putInt :: Writer.C writer => Int -> Int -> Int -> writer ()+putInt :: Writer.C writer => Int -> Int -> Int -> writer putInt code numBytes x =- do- Writer.putIntAsByte code- Writer.putVar $ fromIntegral numBytes- Writer.putByteList $- map fromIntegral $ Bit.someBytes numBytes x+ Writer.putIntAsByte code +#++ Writer.putVar (fromIntegral numBytes) +#++ Writer.putByteList+ (map fromIntegral $ Bit.someBytes numBytes x) -putStr :: Writer.C writer => Int -> String -> writer ()+putStr :: Writer.C writer => Int -> String -> writer putStr code = putByteList code . listByteFromChar -putList :: Writer.C writer => Int -> [Int] -> writer ()+putList :: Writer.C writer => Int -> [Int] -> writer putList code = putByteList code . map fromIntegral
src/Sound/MIDI/File/Event/SystemExclusive.hs view
@@ -7,6 +7,7 @@ import qualified Sound.MIDI.Parser.Class as Parser import qualified Sound.MIDI.Writer.Basic as Writer+import Sound.MIDI.Monoid ((+#+)) import Control.Monad (liftM, ) @@ -37,8 +38,8 @@ 0xF7 -> liftM Escape $ getBigN =<< getVar _ -> Parser.giveUp "SystemExclusive: unkown message type" -put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put sysex = case sysex of- Regular bytes -> Writer.putByte 0xF0 >> Writer.putLenByteList bytes- Escape bytes -> Writer.putByte 0xF7 >> Writer.putLenByteList bytes+ Regular bytes -> Writer.putByte 0xF0 +#+ Writer.putLenByteList bytes+ Escape bytes -> Writer.putByte 0xF7 +#+ Writer.putLenByteList bytes
src/Sound/MIDI/File/Save.hs view
@@ -19,9 +19,12 @@ import qualified Sound.MIDI.Writer.Status as StatusWriter import qualified Sound.MIDI.Writer.Basic as Writer+import qualified Sound.MIDI.Monoid as M+import Sound.MIDI.Monoid ((+#+)) -import Control.Monad.Trans.Reader (ask, )-import Control.Monad.Trans (lift, )+import qualified Data.Monoid.Reader as Reader+import qualified Data.Monoid.Transformer as Trans+ import Sound.MIDI.IO (ByteList, writeBinaryFile, ) import qualified Data.ByteString.Lazy as B@@ -78,43 +81,39 @@ -put :: Writer.C writer => MIDIFile.T -> StatusWriter.T writer ()+put :: Writer.C writer => MIDIFile.T -> StatusWriter.T writer put (MIDIFile.Cons mft divisn trks) =- do- putChunk "MThd" $ lift $- do- Writer.putInt 2 (fromEnum mft) -- format (type 0, 1 or 2)- Writer.putInt 2 (length trks) -- number of tracks to come- putDivision divisn -- time unit- mapM_ putTrack trks+ (putChunk "MThd" $ StatusWriter.lift $+ Writer.putInt 2 (fromEnum mft) +#+ -- format (type 0, 1 or 2)+ Writer.putInt 2 (length trks) +#+ -- number of tracks to come+ putDivision divisn) -- time unit+ +#+ M.concatMap putTrack trks -putDivision :: Writer.C writer => Division -> writer ()+putDivision :: Writer.C writer => Division -> writer putDivision (Ticks nticks) = Writer.putInt 2 (NonNeg.toNumber nticks) putDivision (SMPTE mode nticks) =- do- Writer.putIntAsByte (256-mode)- Writer.putIntAsByte nticks+ Writer.putIntAsByte (256-mode) +#++ Writer.putIntAsByte nticks -putTrack :: Writer.C writer => Track -> StatusWriter.T writer ()+putTrack :: Writer.C writer => Track -> StatusWriter.T writer putTrack trk = putChunk "MTrk" $- EventList.mapM_ (lift . Writer.putVar) Event.put $+ EventList.concatMapMonoid (StatusWriter.lift . Writer.putVar) Event.put $ EventList.snoc trk 0 (Event.MetaEvent MetaEvent.EndOfTrack) putChunk :: Writer.C writer =>- String -> StatusWriter.T writer () -> StatusWriter.T writer ()+ String -> StatusWriter.T writer -> StatusWriter.T writer putChunk tag m =- do- lift $ putTag tag- compress <- StatusWriter.Cons ask- lift $ Writer.putLengthBlock 4 $- StatusWriter.toWriter compress m+ StatusWriter.lift (putTag tag) +#++ StatusWriter.Cons (Reader.Cons $ \compress ->+ Trans.lift $ Writer.putLengthBlock 4 $+ StatusWriter.toWriter compress m) -putTag :: Writer.C writer => String -> writer ()+putTag :: Writer.C writer => String -> writer putTag tag@(_:_:_:_:[]) = Writer.putStr tag putTag tag = error ("SaveMIDI.putChunk: Chunk name " ++ tag ++
src/Sound/MIDI/Manufacturer.hs view
@@ -52,6 +52,7 @@ import qualified Sound.MIDI.Parser.Class as Parser import qualified Sound.MIDI.Writer.Basic as Writer+import Sound.MIDI.Monoid ((+#+)) import Control.Monad (liftM2, ) @@ -356,11 +357,11 @@ then liftM2 Extended getByte getByte else return $ Short subId -put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put subId = case subId of Short n -> Writer.putByte n Extended hi lo ->- Writer.putByte 0 >>- Writer.putByte hi >>+ Writer.putByte 0 +#++ Writer.putByte hi +#+ Writer.putByte lo
src/Sound/MIDI/Message.hs view
@@ -20,12 +20,12 @@ 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.Trans (lift, ) import Control.Monad (liftM, ) import qualified Data.ByteString.Lazy as B@@ -67,17 +67,17 @@ -put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put msg = case msg of Channel s -> Channel.put s System s -> System.put s -putWithStatus :: Writer.C writer => T -> StatusWriter.T writer ()+putWithStatus :: Writer.C writer => T -> StatusWriter.T writer putWithStatus msg = case msg of Channel s -> Channel.putWithStatus s- System s -> StatusWriter.clear >> lift (System.put s)+ System s -> StatusWriter.clear +#+ StatusWriter.lift (System.put s) toByteString :: T -> B.ByteString toByteString =
src/Sound/MIDI/Message/Channel.hs view
@@ -22,13 +22,14 @@ import Sound.MIDI.Parser.Status (Channel, fromChannel, toChannel, ) -import Control.Monad.Trans (lift, ) import Control.Monad (liftM, liftM2, when, ) import qualified Sound.MIDI.Writer.Status as StatusWriter import qualified Sound.MIDI.Writer.Basic as Writer import qualified Sound.MIDI.Bit as Bit +import Sound.MIDI.Monoid ((+#+))+ import Sound.MIDI.Utility ({-checkRange,-} mapSnd, ) -- import Data.Ix (Ix) @@ -108,18 +109,17 @@ else liftM Voice (Voice.get code firstData) -put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put = StatusWriter.toWriterWithoutStatus . putWithStatus -putWithStatus :: Writer.C writer => T -> StatusWriter.T writer ()+putWithStatus :: Writer.C writer => T -> StatusWriter.T writer putWithStatus (Cons c e) = case e of Voice v -> Voice.putWithStatus (putChannel c) v- Mode m -> putChannel c 11 >> lift (Mode.put m)+ Mode m -> putChannel c 11 +#+ StatusWriter.lift (Mode.put m) -- | output a channel + message code-putChannel :: Writer.C writer => Channel -> Int -> StatusWriter.T writer ()+putChannel :: Writer.C writer => Channel -> Int -> StatusWriter.T writer putChannel chan code =- do b <- StatusWriter.change (Just (code, chan))- when b $ lift $- Writer.putIntAsByte (16*code + fromChannel chan)+ StatusWriter.change (Just (code, chan)) $+ Writer.putIntAsByte (16*code + fromChannel chan)
src/Sound/MIDI/Message/Channel/Mode.hs view
@@ -94,7 +94,7 @@ ("Invalid value for " ++ name ++ ": " ++ show value) -put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put mode = let (code, value) = toControllerValue mode in Writer.putByteList [code, value]
src/Sound/MIDI/Message/Channel/Voice.hs view
@@ -47,6 +47,8 @@ import qualified Sound.MIDI.Writer.Basic as Writer import qualified Sound.MIDI.Bit as Bit +import Sound.MIDI.Monoid ((+#+))+ import Data.Ix (Ix) import Sound.MIDI.Utility (checkRange, quantityRandomR, boundedQuantityRandom, chooseQuantity,@@ -425,10 +427,10 @@ putWithStatus :: Writer.C writer =>- (Int -> StatusWriter.T writer ()) -> T -> StatusWriter.T writer ()+ (Int -> StatusWriter.T writer) -> T -> StatusWriter.T writer putWithStatus putChan e = let putC code bytes =- putChan code >>+ putChan code +#+ StatusWriter.fromWriter (Writer.putByteList (map fromIntegral bytes)) in case e of NoteOff p v -> putC 8 [fromPitch p, fromVelocity v]
src/Sound/MIDI/Message/System.hs view
@@ -51,7 +51,7 @@ else Parser.giveUp ("invalid System message code " ++ show code) -put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put msg = case msg of Exclusive s -> Exclusive.put s
src/Sound/MIDI/Message/System/Common.hs view
@@ -12,6 +12,7 @@ import Control.Monad (liftM, liftM2, ) import qualified Sound.MIDI.Writer.Basic as Writer+import Sound.MIDI.Monoid ((+#+)) import qualified Sound.MIDI.Bit as Bit @@ -54,19 +55,19 @@ 0xF6 -> return TuneRequest _ -> Parser.giveUp ("invalid System Common code:" ++ show code) -put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put msg = case msg of TimeCodeQuarterFrame nibble value ->- Writer.putByte 0xF1 >>+ Writer.putByte 0xF1 +#+ Writer.putIntAsByte (Bit.shiftL 4 (fromEnum nibble) + value) SongPositionPointer pos ->- Writer.putByte 0xF2 >>+ Writer.putByte 0xF2 +#+ let (msb,lsb) = Bit.splitAt 7 pos- in Writer.putIntAsByte lsb >>+ in Writer.putIntAsByte lsb +#+ Writer.putIntAsByte msb SongSelect song ->- Writer.putByte 0xF3 >>+ Writer.putByte 0xF3 +#+ Writer.putIntAsByte song TuneRequest -> Writer.putByte 0xF6
src/Sound/MIDI/Message/System/Exclusive.hs view
@@ -12,6 +12,7 @@ import qualified Sound.MIDI.Parser.Class as Parser import qualified Sound.MIDI.Writer.Basic as Writer+import Sound.MIDI.Monoid ((+#+)) import Control.Monad.Trans (MonadTrans, lift, ) import qualified Control.Monad.Exception.Asynchronous as Async@@ -63,18 +64,18 @@ {- | It is not checked whether SysEx messages contain only 7-bit values. -}-put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put sysex = case sysex of Commercial manu body ->- Manufacturer.put manu >>+ Manufacturer.put manu +#+ Writer.putByteList body NonCommercial body ->- Manufacturer.put Manufacturer.nonCommercial >>+ Manufacturer.put Manufacturer.nonCommercial +#+ Writer.putByteList body NonRealTime (NonRealTimeCons body) ->- Manufacturer.put Manufacturer.nonRealTime >>+ Manufacturer.put Manufacturer.nonRealTime +#+ Writer.putByteList body RealTime (RealTimeCons body) ->- Manufacturer.put Manufacturer.realTime >>+ Manufacturer.put Manufacturer.realTime +#+ Writer.putByteList body
src/Sound/MIDI/Message/System/RealTime.hs view
@@ -36,7 +36,7 @@ 0xFF -> return Reset _ -> Parser.giveUp ("unknown System Real Time message code " ++ show code) -put :: Writer.C writer => T -> writer ()+put :: Writer.C writer => T -> writer put msg = case msg of TimingClock -> Writer.putByte 0xF8
+ src/Sound/MIDI/Monoid.hs view
@@ -0,0 +1,26 @@+module Sound.MIDI.Monoid where++import Data.Monoid (Monoid, mappend, mconcat, )+import Prelude hiding (concatMap, )++++infixr 5 +#+++(+#+) :: Monoid m => m -> m -> m+(+#+) = mappend+++genAppend :: (Monoid m) =>+ (m -> a) -> (a -> m) -> a -> a -> a+genAppend cons decons x y =+ cons $ mappend (decons x) (decons y)++genConcat :: (Monoid m) =>+ (m -> a) -> (a -> m) -> [a] -> a+genConcat cons decons =+ cons . concatMap decons++concatMap :: (Monoid m) =>+ (a -> m) -> [a] -> m+concatMap f = mconcat . map f
src/Sound/MIDI/Writer/Basic.hs view
@@ -3,19 +3,25 @@ import qualified Numeric.NonNegative.Wrapper as NonNeg import qualified Sound.MIDI.Bit as Bit-import Data.Bits ((.|.)) import qualified Sound.MIDI.IO as MIO+import qualified Sound.MIDI.Monoid as M+import qualified Data.Monoid as Monoid++import Data.Bits ((.|.)) import Sound.MIDI.IO (listByteFromChar, )-import Control.Monad.Trans.Writer (Writer, execWriter, tell, )+import Data.Monoid (Monoid, mempty, mappend, mconcat, )+import Sound.MIDI.Monoid ((+#+), genAppend, genConcat, )+ import Control.Monad.Trans.Reader (ReaderT, runReaderT, ask, ) import Control.Monad.Trans (lift, )+ import Data.List (genericLength, ) import Data.Word (Word8, ) import Data.Char (chr, ) import qualified Data.ByteString.Lazy as B-import qualified Data.Binary as Binary-import Data.Binary.Put (PutM, runPut, putLazyByteString, )+import qualified Data.Binary.Builder as Builder+import Data.Binary.Builder (Builder, fromLazyByteString, ) import Control.Exception (bracket, ) import qualified System.IO as IO@@ -26,45 +32,54 @@ -class Monad m => C m where- putByte :: Word8 -> m ()+class Monoid m => C m where+ putByte :: Word8 -> m {- | @putLengthBlock n writeBody@ write @n@ bytes indicating the number of bytes written by @writeBody@ and then it runs @writeBody@. -}- putLengthBlock :: Int -> m () -> m ()+ putLengthBlock :: Int -> m -> m -newtype ByteList a =- ByteList {unByteList :: Writer MIO.ByteList a}+-- differences list+newtype ByteList =+ ByteList {unByteList :: Monoid.Endo MIO.ByteList} -instance Monad ByteList where- return = ByteList . return- x >>= y = ByteList $ unByteList . y =<< unByteList x+instance Monoid ByteList where+ mempty = ByteList mempty+ mappend = genAppend ByteList unByteList+ mconcat = genConcat ByteList unByteList instance C ByteList where- putByte = ByteList . tell . (:[])+ putByte = ByteList . Monoid.Endo . (:) putLengthBlock n writeBody = let body = runByteList writeBody- in putInt n (length body) >> putByteList body+ in putInt n (length body) `mappend`+ putByteListSpec body -- we could call 'writeBody' but this would recompute the data -runByteList :: ByteList () -> MIO.ByteList-runByteList = execWriter . unByteList+-- | 'putByteList' specialised to 'ByteList'+putByteListSpec :: MIO.ByteList -> ByteList+putByteListSpec = ByteList . Monoid.Endo . (++) +runByteList :: ByteList -> MIO.ByteList+runByteList = flip Monoid.appEndo [] . unByteList -newtype ByteString a =- ByteString {unByteString :: PutM a} -instance Monad ByteString where- return = ByteString . return- x >>= y = ByteString $ unByteString . y =<< unByteString x +newtype ByteString =+ ByteString {unByteString :: Builder}++instance Monoid ByteString where+ mempty = ByteString $ mempty+ mappend = genAppend ByteString unByteString+ mconcat = genConcat ByteString unByteString+ instance C ByteString where- putByte = ByteString . Binary.putWord8+ putByte = ByteString . Builder.singleton putLengthBlock n writeBody = let body = runByteString writeBody len = B.length body@@ -72,21 +87,22 @@ if len >= div (256^n) 2 then error "Chunk too large" else fromIntegral len- in putInt n errLen >> ByteString (putLazyByteString body)+ in putInt n errLen +#+ ByteString (fromLazyByteString body) -runByteString :: ByteString () -> B.ByteString-runByteString = runPut . unByteString+runByteString :: ByteString -> B.ByteString+runByteString = Builder.toLazyByteString . unByteString -newtype SeekableFile a =- SeekableFile {unSeekableFile :: ReaderT Handle IO a}+newtype SeekableFile =+ SeekableFile {unSeekableFile :: ReaderT Handle IO ()} -instance Monad SeekableFile where- return = SeekableFile . return- x >>= y = SeekableFile $ unSeekableFile . y =<< unSeekableFile x+instance Monoid SeekableFile where+ mempty = SeekableFile $ return ()+ mappend x y = SeekableFile $ unSeekableFile x >> unSeekableFile y+ mconcat xs = SeekableFile $ mapM_ unSeekableFile xs instance C SeekableFile where putByte c =@@ -110,36 +126,36 @@ IO.hSetPosn contPos -runSeekableFile :: FilePath -> SeekableFile () -> IO ()+runSeekableFile :: FilePath -> SeekableFile -> IO () runSeekableFile name w = bracket (openBinaryFile name WriteMode) hClose (flip runSeekableHandle w) -runSeekableHandle :: Handle -> SeekableFile () -> IO ()+runSeekableHandle :: Handle -> SeekableFile -> IO () runSeekableHandle h w = runReaderT (unSeekableFile w) h -putInt :: C writer => Int -> Int -> writer ()+putInt :: C writer => Int -> Int -> writer putInt a = putByteList . map fromIntegral . Bit.someBytes a -putStr :: C writer => String -> writer ()+putStr :: C writer => String -> writer putStr = putByteList . listByteFromChar -putIntAsByte :: C writer => Int -> writer ()+putIntAsByte :: C writer => Int -> writer putIntAsByte x = putByte $ fromIntegral x -putByteList :: C writer => MIO.ByteList -> writer ()-putByteList = mapM_ putByte+putByteList :: C writer => MIO.ByteList -> writer+putByteList = M.concatMap putByte -putLenByteList :: C writer => MIO.ByteList -> writer ()+putLenByteList :: C writer => MIO.ByteList -> writer putLenByteList bytes =- do putVar (genericLength bytes)- putByteList bytes+ putVar (genericLength bytes) +#++ putByteList bytes {- | Numbers of variable size are represented by sequences of 7-bit blocks@@ -148,7 +164,7 @@ (0) that this is the last block. -} -putVar :: C writer => NonNeg.Integer -> writer ()+putVar :: C writer => NonNeg.Integer -> writer putVar n = let bytes = map fromIntegral $ Bit.toBase 128 n in case bytes of
src/Sound/MIDI/Writer/Status.hs view
@@ -1,57 +1,64 @@-module Sound.MIDI.Writer.Status where+module Sound.MIDI.Writer.Status (+ module Sound.MIDI.Writer.Status,+ lift,+ ) where -- import qualified Sound.MIDI.Writer.Basic as Writer import Sound.MIDI.Parser.Status (Channel) -import Control.Monad.Trans.State (StateT, evalStateT, get, put, )-import Control.Monad.Trans.Reader (ReaderT, runReaderT, ask, )-import Control.Monad.Trans (MonadTrans, lift, )+import qualified Data.Monoid.State as State+import qualified Data.Monoid.Reader as Reader+import qualified Data.Monoid.Transformer as Trans+import Data.Monoid.Transformer (lift, ) +import Data.Monoid (Monoid, mempty, mappend, mconcat, )+import Sound.MIDI.Monoid (genAppend, genConcat, ) + type Status = Maybe (Int,Channel) {- | The ReaderT Bool handles whether running status should be respected (True) or ignored (False). -}-newtype T writer a =- Cons {decons :: ReaderT Bool (StateT (Maybe Status) writer) a}+newtype T writer =+ Cons {decons :: Reader.T Bool (State.T (Maybe Status) writer)} -instance Monad writer => Monad (T writer) where- return = Cons . return- x >>= y = Cons $ decons . y =<< decons x+instance Monoid writer => Monoid (T writer) where+ mempty = Cons $ mempty+ mappend = genAppend Cons decons+ mconcat = genConcat Cons decons --- | returns 'True' if status must be submitted (e.g. because it was changed)-change :: (Monad writer) => Status -> T writer Bool-change x = Cons $- do b <- ask- if not b- then return True- else- lift $- let mx = Just x- in do my <- get- put mx- return (mx/=my)+{- |+Given a writer that emits a status, generate a stateful writer,+that decides whether to run the status emittor.+-}+change :: (Monoid writer) => Status -> writer -> T writer+change x emit =+ Cons $+ Reader.Cons $ \b ->+ State.Cons $ \my ->+ let mx = Just x+ in (if not b || mx/=my then emit else mempty, mx) -clear :: (Monad writer) => T writer ()-clear = Cons $ lift $ put Nothing+clear :: (Monoid writer) => T writer+clear = Cons $ lift $ State.put Nothing -instance MonadTrans T where+instance Trans.C T where lift = fromWriter -fromWriter :: (Monad writer) => writer a -> T writer a+fromWriter :: (Monoid writer) => writer -> T writer fromWriter = Cons . lift . lift -toWriter :: (Monad writer) => Bool -> T writer a -> writer a-toWriter withStatus w =- evalStateT (runReaderT (decons w) withStatus) Nothing+toWriter :: (Monoid writer) => Bool -> T writer -> writer+toWriter withStatus =+ State.evaluate Nothing . flip Reader.run withStatus . decons -toWriterWithStatus :: (Monad writer) => T writer a -> writer a+toWriterWithStatus :: (Monoid writer) => T writer -> writer toWriterWithStatus = toWriter True -toWriterWithoutStatus :: (Monad writer) => T writer a -> writer a+toWriterWithoutStatus :: (Monoid writer) => T writer -> writer toWriterWithoutStatus = toWriter False