packages feed

HCodecs 0.1 → 0.2

raw patch · 10 files changed

+186/−205 lines, 10 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.Audio: instance (Arbitrary a, IArray DiffUArray a) => Arbitrary (Audio a)
- Data.Audio: instance (Eq a, IArray DiffUArray a) => Eq (Audio a)
- Data.Audio: instance (Eq e, Ix i, IArray (IOToDiffArray a) e) => Eq (IOToDiffArray a i e)
- Data.Audio: instance (Show a, IArray DiffUArray a) => Show (Audio a)
+ Data.Audio: instance (Arbitrary a, IArray UArray a) => Arbitrary (Audio a)
+ Data.Audio: instance (Eq a, IArray UArray a) => Eq (Audio a)
+ Data.Audio: instance (Show a, IArray UArray a) => Show (Audio a)
- Codec.Midi: fromAbsTime :: (Num a) => Track a -> Track a
+ Codec.Midi: fromAbsTime :: Num a => Track a -> Track a
- Codec.Midi: toAbsTime :: (Num a) => Track a -> Track a
+ Codec.Midi: toAbsTime :: Num a => Track a -> Track a
- Codec.Wav: bitsPerSample :: (AudibleInWav a) => a -> Int
+ Codec.Wav: bitsPerSample :: AudibleInWav a => a -> Int
- Codec.Wav: buildSample :: (AudibleInWav a) => a -> Builder
+ Codec.Wav: buildSample :: AudibleInWav a => a -> Builder
- Codec.Wav: buildWav :: (IArray DiffUArray a, Audible a, AudibleInWav a) => Audio a -> Builder
+ Codec.Wav: buildWav :: (IArray UArray a, Audible a, AudibleInWav a) => Audio a -> Builder
- Codec.Wav: exportFile :: (IArray DiffUArray a, Audible a, AudibleInWav a) => FilePath -> Audio a -> IO ()
+ Codec.Wav: exportFile :: (IArray UArray a, Audible a, AudibleInWav a) => FilePath -> Audio a -> IO ()
- Codec.Wav: importFile :: (IArray DiffUArray a, Audible a, AudibleInWav a) => FilePath -> IO (Either String (Audio a))
+ Codec.Wav: importFile :: (MArray IOUArray a IO, IArray UArray a, Audible a, AudibleInWav a) => FilePath -> IO (Either String (Audio a))
- Codec.Wav: parseSample :: (AudibleInWav a) => Parser a
+ Codec.Wav: parseSample :: AudibleInWav a => Parser a
- Codec.Wav: parseWav :: (IArray DiffUArray a, Audible a, AudibleInWav a) => Parser (Audio a)
+ Codec.Wav: parseWav :: (MArray IOUArray a IO, IArray UArray a, Audible a, AudibleInWav a) => Parser (Audio a)
- Data.Audio: buildSampleData :: (IArray DiffUArray a) => (a -> Builder) -> SampleData a -> Builder
+ Data.Audio: buildSampleData :: IArray UArray a => (a -> Builder) -> SampleData a -> Builder
- Data.Audio: convert :: (Audible a, Audible b, IArray DiffUArray a, IArray DiffUArray b) => SampleData a -> SampleData b
+ Data.Audio: convert :: (Audible a, Audible b, IArray UArray a, IArray UArray b) => SampleData a -> SampleData b
- Data.Audio: fromSample :: (Audible a) => Sample -> a
+ Data.Audio: fromSample :: Audible a => Sample -> a
- Data.Audio: parseSampleData :: (IArray DiffUArray a) => Int -> Parser a -> Parser (SampleData a)
+ Data.Audio: parseSampleData :: (MArray IOUArray a IO, IArray UArray a) => Int -> Parser a -> Parser (SampleData a)
- Data.Audio: sampleNumber :: (IArray DiffUArray a) => SampleData a -> Int
+ Data.Audio: sampleNumber :: IArray UArray a => SampleData a -> Int
- Data.Audio: sampleType :: (IArray DiffUArray a) => SampleData a -> a
+ Data.Audio: sampleType :: IArray UArray a => SampleData a -> a
- Data.Audio: toSample :: (Audible a) => a -> Sample
+ Data.Audio: toSample :: Audible a => a -> Sample
- Data.Audio: type SampleData a = DiffUArray Int a
+ Data.Audio: type SampleData a = UArray Int a

Files

HCodecs.cabal view
@@ -1,5 +1,5 @@ name: HCodecs-version: 0.1+version: 0.2 cabal-Version: >= 1.2 license: BSD3 license-file: LICENSE@@ -11,7 +11,7 @@ stability: experimental synopsis: A library to read, write and manipulate MIDI, WAVE, and SoundFont2 files. description:-  The library provides functions to read, write and manipulate MIDI, WAVE and SoundFont2 multimedia files. It is written entirely in Haskell (without any FFI). It uses efficient parsing and building combinators for binary data stored in ByteStrings (based on the one in 'binary' package).+  The library provides functions to read, write and manipulate MIDI, WAVE and SoundFont2 multimedia files. It is written entirely in Haskell (without any FFI). It uses efficient  parsing and building combinators for binary data stored in ByteStrings (based on the one in 'binary' package).   .   Correctness of significant parts of the library has been validated with QuickCheck and Haskell Program Coverage (HPC) tool-kits.   .@@ -20,16 +20,14 @@ extra-source-files: src/Tests/Main.hs  library-  hs-source-dirs:  src-  ghc-options : -O3 -Wall -fno-warn-name-shadowing-  build-Depends: base < 5, bytestring, QuickCheck < 2, random, array+  hs-source-dirs: src+  ghc-options : -O3 -Wall+  build-Depends: base < 5, bytestring, random, array, QuickCheck < 2   exposed-modules:     Codec.Midi     Codec.Wav     Codec.SoundFont-         Data.Audio-     Data.ByteString.Parser     Data.ByteString.Builder   other-modules:
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2007-2008 George Giorgidze+Copyright (c) 2007-2010 George Giorgidze  All rights reserved. 
src/Codec/Midi.hs view
@@ -8,7 +8,7 @@ -- Stability   : Experimental -- Portability : Portable ----- Module for reading, writing and maniplating of standard MIDI files.+-- Reading, writing and maniplating of standard MIDI files -- ----------------------------------------------------------------------------- @@ -66,7 +66,7 @@ import Data.ByteString.Builder import Data.Arbitrary () -import Data.Word
+import Data.Word import qualified Data.ByteString.Lazy as L import Data.Bits import Data.Maybe@@ -281,10 +281,10 @@   where trk' = (concat $ map removeTrackEnds trks) ++ [(0,TrackEnd)]  merge :: (Num a, Ord a) => Track a -> Track a -> Track a-merge trk1 trk2 = (fromAbsTime $ f trk1' trk2') ++ [(0,TrackEnd)]+merge track1 track2 = (fromAbsTime $ f trk1' trk2') ++ [(0,TrackEnd)]   where-  trk1' = toAbsTime $ removeTrackEnds trk1-  trk2' = toAbsTime $ removeTrackEnds trk2+  trk1' = toAbsTime $ removeTrackEnds track1+  trk2' = toAbsTime $ removeTrackEnds track2   f trk [] = trk   f [] trk = trk   f ((dt1,m1) : trk1) ((dt2,m2) : trk2) = if dt1 <= dt2@@ -344,8 +344,8 @@  parseMidi :: Parser Midi parseMidi = do-  string "MThd"-  word32be 6+  _ <- string "MThd"+  _ <- word32be 6   formatType' <- getWord16be   trackNumber' <- getWord16be   timeDivision' <- getWord16be@@ -384,8 +384,8 @@    parseTrack :: Parser (Track Ticks) parseTrack = do-  string "MTrk"-  getWord32be -- trackSize +  _ <- string "MTrk"+  _ <- getWord32be -- trackSize    track' <- parseMessages Nothing   return track'  @@ -436,7 +436,7 @@ parseChannel mPreMsg isNeededMsg msgCode = p1 <|> p2   where   p1 = do-    lookAhead (satisfy ( < 0x80))+    _ <- lookAhead (satisfy ( < 0x80))     guard $ (isJust mPreMsg) && (isNeededMsg $ fromJust mPreMsg)     return $! channel (fromJust mPreMsg)   p2 = do@@ -513,7 +513,7 @@    parseMetaMessage :: Parser Message parseMetaMessage = do-  word8 0xFF+  _ <- word8 0xFF   choice [       parseSequenceNumber     , parseText@@ -583,114 +583,114 @@  parseSequenceNumber :: Parser Message parseSequenceNumber = do-  word8 0x00-  varLenBe 2+  _ <- word8 0x00+  _ <- varLenBe 2   n <- getWord16be   return $! SequenceNumber (fromIntegral n)  parseText :: Parser Message parseText = do-  word8 0x01+  _ <- word8 0x01   l <- getVarLenBe   s <- getString (fromIntegral l)   return $! Text s  parseCopyright :: Parser Message parseCopyright = do-  word8 0x02+  _ <- word8 0x02   l <- getVarLenBe   s <- getString (fromIntegral l)   return $! Copyright s  parseTrackName :: Parser Message parseTrackName = do-  word8 0x03+  _ <- word8 0x03   l <- getVarLenBe   s <- getString (fromIntegral l)   return $! TrackName s  parseInstrumentName :: Parser Message parseInstrumentName = do-  word8 0x04+  _ <- word8 0x04   l <- getVarLenBe   s <- getString (fromIntegral l)   return $! InstrumentName s  parseLyrics :: Parser Message parseLyrics = do-  word8 0x05+  _ <- word8 0x05   l <- getVarLenBe   s <- getString (fromIntegral l)   return $! Lyrics s  parseMarker :: Parser Message parseMarker = do-  word8 0x06+  _ <- word8 0x06   l <- getVarLenBe   s <- getString (fromIntegral l)   return $! Marker s  parseCuePoint :: Parser Message parseCuePoint = do-  word8 0x07+  _ <- word8 0x07   l <- getVarLenBe   s <- getString (fromIntegral l)   return $! CuePoint s  parseProgramName :: Parser Message parseProgramName = do-  word8 0x08+  _ <- word8 0x08   l <- getVarLenBe   s <- getString (fromIntegral l)   return $! ProgramName s  parseDeviceName :: Parser Message parseDeviceName = do-  word8 0x09+  _ <- word8 0x09   l <- getVarLenBe   s <- getString (fromIntegral l)   return $! DeviceName s  parseChannelPrefix :: Parser Message parseChannelPrefix = do-  word8 0x20-  varLenBe 1+  _ <- word8 0x20+  _ <- varLenBe 1   p <- getWord8   return $! ChannelPrefix (fromIntegral p)  parseTrackEnd :: Parser Message parseTrackEnd =  do-  word8 0x2F-  varLenBe 0+  _ <- word8 0x2F+  _ <- varLenBe 0   return $! TrackEnd  parseTempoChange :: Parser Message parseTempoChange = do-  word8 0x51-  varLenBe 3+  _ <- word8 0x51+  _ <- varLenBe 3   t <- getWord24be   return $! TempoChange (fromIntegral t)  parseSMPTEOffset :: Parser Message parseSMPTEOffset = do-  word8 0x54-  varLenBe 5+  _ <- word8 0x54+  _ <- varLenBe 5   bs <- getLazyByteString 5    let [n1,n2,n3,n4,n5] = map fromIntegral (L.unpack bs)   return $! SMPTEOffset n1 n2 n3 n4 n5  parseTimeSignature :: Parser Message parseTimeSignature = do-  word8 0x58-  varLenBe 4+  _ <- word8 0x58+  _ <- varLenBe 4   bs <- getLazyByteString 4   let [n1,n2,n3,n4] = map fromIntegral (L.unpack bs)   return $! TimeSignature n1 n2 n3 n4  parseKeySignature :: Parser Message parseKeySignature = do-  word8 0x59-  varLenBe 2+  _ <- word8 0x59+  _ <- varLenBe 2   n1 <- getInt8   n2 <- getWord8   return $! KeySignature (fromIntegral n1) (fromIntegral n2)
src/Codec/SoundFont.hs view
@@ -118,11 +118,11 @@ instance Arbitrary Sdta where   arbitrary = do     sn <- choose (1,1024)-    smpl <- arrayGen sn+    smpl1 <- arrayGen sn     oneof [-        return $! Sdta smpl Nothing-      , do sm24 <- arrayGen sn-           return $! Sdta smpl (Just sm24)+        return $! Sdta smpl1 Nothing+      , do sm24' <- arrayGen sn+           return $! Sdta smpl1 (Just sm24')       ]   coarbitrary = undefined @@ -456,9 +456,9 @@  parseSoundFont :: Parser SoundFont parseSoundFont = do-  string "RIFF"-  getWord32le -- chunkSize-  string "sfbk"+  _ <- string "RIFF"+  _ <- getWord32le -- chunkSize+  _ <- string "sfbk"   infos' <- parseInfos   sdta' <- parseSdta   pdta' <- parsePdta@@ -486,14 +486,14 @@  parseInfos :: Parser (Array Word Info) parseInfos = do-  string "LIST"-  getWord32le -- chunkSize-  string "INFO"+  _ <- string "LIST"+  _ <- getWord32le -- chunkSize+  _ <- string "INFO"   infos' <- many p   return $! listArray (0, genericLength infos' - 1) infos'   where   p = choice [-      do n <- getString 4; word32le 4; w1 <- getWord16le; w2 <- getWord16le;+      do n <- getString 4; _ <- word32le 4; w1 <- getWord16le; w2 <- getWord16le;          case n of            "ifil" -> return $! Version (fromIntegral w1) (fromIntegral w2)            "iver" -> return $! RomVersion (fromIntegral w1) (fromIntegral w2)@@ -559,10 +559,10 @@    parseSdta :: Parser Sdta parseSdta = do-  string "LIST"+  _ <- string "LIST"   sdtaSize <- getWord32le >>= return .fromIntegral-  string "sdta"-  string "smpl"+  _ <- string "sdta"+  _ <- string "smpl"   smplSize <- getWord32le  >>= return .fromIntegral   when (odd smplSize) $ fail "'smplSize' must not be odd number"   let sn = div smplSize 2@@ -570,45 +570,45 @@   choice [       do guard (smplSize == (sdtaSize - 12))          return $! Sdta {smpl = smpl', sm24 =  Nothing}-    , do string "sm24"+    , do _ <- string "sm24"          let sm24Size = if odd sn then sn + 1 else sn -         word32le (fromIntegral sm24Size)+         _ <- word32le (fromIntegral sm24Size)          sm24' <- Audio.parseSampleData sn getInt8          skip (fromIntegral $ sm24Size - sn)          return $! Sdta{ smpl = smpl', sm24 = Just sm24'}     ]  buildSdta :: Sdta -> Builder-buildSdta (Sdta smpl Nothing) = mconcat [+buildSdta (Sdta smpl1 Nothing) = mconcat [     putString "LIST"   , putWord32le $ fromIntegral $ sdtaSize   , putString "sdta"   , putString "smpl"   , putWord32le $ fromIntegral $ smplSize-  , Audio.buildSampleData putInt16le smpl]-  where smplSize = (Audio.sampleNumber smpl) * 2+  , Audio.buildSampleData putInt16le smpl1]+  where smplSize = (Audio.sampleNumber smpl1) * 2         sdtaSize = 4 + 4 + 4 + smplSize-buildSdta (Sdta smpl (Just sd8)) = mconcat [+buildSdta (Sdta smpl1 (Just sd8)) = mconcat [     putString "LIST"   , putWord32le $ fromIntegral $ sdtaSize   , putString "sdta"   , putString "smpl"   , putWord32le $ fromIntegral $ smplSize-  , Audio.buildSampleData putInt16le smpl+  , Audio.buildSampleData putInt16le smpl1   , putString "sm24"   , putWord32le $ fromIntegral $ sm24Size   , Audio.buildSampleData putInt8 sd8   , mconcat $ genericReplicate (sm24Size - sn) $ putWord8 0]-  where sn = Audio.sampleNumber smpl+  where sn = Audio.sampleNumber smpl1         smplSize = sn * 2         sm24Size = if odd sn then sn + 1 else sn         sdtaSize = 4 + 4 + 4 + smplSize + 4 + 4 + sm24Size  parsePdta :: Parser Pdta parsePdta = do-  string "LIST"-  getWord32le -- pdtaSize-  string "pdta"+  _ <- string "LIST"+  _ <- getWord32le -- pdtaSize+  _ <- string "pdta"   phdrs' <- parseSubchunk "phdr" 38 parsePhdr   pbags' <- parseSubchunk "pbag" 4 parseBag   pmods' <- parseSubchunk "pmod" 10 parseMod@@ -621,7 +621,7 @@   return $! Pdta phdrs' pbags' pmods' pgens' insts' ibags' imods' igens' shdrs'  buildPdta :: Pdta -> Builder-buildPdta pdta = mconcat [+buildPdta pdta1 = mconcat [     putString "LIST"   , putWord32le $ fromIntegral chunkSize   , fromLazyByteString bs]@@ -629,22 +629,22 @@   chunkSize = L.length bs   bs = toLazyByteString $ mconcat [       putString "pdta"-    , buildSubchunk "phdr" 38 buildPhdr (phdrs pdta)-    , buildSubchunk "pbag"  4 buildBag  (pbags pdta)-    , buildSubchunk "pmod" 10 buildMod  (pmods pdta)-    , buildSubchunk "pgen"  4 buildGen  (pgens pdta)-    , buildSubchunk "inst" 22 buildInst (insts pdta)-    , buildSubchunk "ibag"  4 buildBag  (ibags pdta)-    , buildSubchunk "imod" 10 buildMod  (imods pdta)-    , buildSubchunk "igen"  4 buildGen  (igens pdta)    -    , buildSubchunk "shdr" 46 buildShdr (shdrs pdta)    +    , buildSubchunk "phdr" 38 buildPhdr (phdrs pdta1)+    , buildSubchunk "pbag"  4 buildBag  (pbags pdta1)+    , buildSubchunk "pmod" 10 buildMod  (pmods pdta1)+    , buildSubchunk "pgen"  4 buildGen  (pgens pdta1)+    , buildSubchunk "inst" 22 buildInst (insts pdta1)+    , buildSubchunk "ibag"  4 buildBag  (ibags pdta1)+    , buildSubchunk "imod" 10 buildMod  (imods pdta1)+    , buildSubchunk "igen"  4 buildGen  (igens pdta1)    +    , buildSubchunk "shdr" 46 buildShdr (shdrs pdta1)         ]  -- For some subchunks minimal number of records is two -- but this check can be done later I am skiping it here parseSubchunk :: String -> Word -> (Parser a) -> Parser (Array Word a) parseSubchunk s size p = do-  string s+  _ <- string s   chunkSize <- expect (\w -> mod w size == 0) (getWord32le >>= return . fromIntegral)   let n = div chunkSize size   cs <- sequence (genericReplicate n p)@@ -773,9 +773,9 @@   , int16le 40 >> getInt16le  >>= return . KeyToVolEnvDecay . fromIntegral        , int16le 41 >> getWord16le >>= return . InstIndex . fromIntegral-  , do int16le 43; a <- getWord8 >>= return . fromIntegral;+  , do _ <- int16le 43; a <- getWord8 >>= return . fromIntegral;        b <- getWord8 >>= return . fromIntegral; return $ KeyRange a b;-  , do int16le 44; a <- getWord8 >>= return . fromIntegral;+  , do _ <- int16le 44; a <- getWord8 >>= return . fromIntegral;        b <- getWord8 >>= return . fromIntegral; return $ VelRange a b;        , int16le 45 >> getInt16le  >>= return . LoopStartAddressCoarseOffset . fromIntegral@@ -787,7 +787,7 @@   , int16le 51 >> getInt16le  >>= return . CoarseTune . fromIntegral   , int16le 52 >> getInt16le  >>= return . FineTune . fromIntegral   , int16le 53 >> getWord16le >>= return . SampleIndex . fromIntegral-  , do int16le  54;  a <- getInt16le;+  , do _ <- int16le  54;  a <- getInt16le;        case a of          1 -> return $ SampleMode Audio.ContLoop          3 -> return $ SampleMode Audio.PressLoop@@ -926,14 +926,3 @@     , putWord16le $ fromIntegral $ sampleLink shdr     , putWord16le $ fromIntegral $ sampleType shdr     ]---- data SampleType = ---  MonoSample |---   RightSample |---   LeftSample |---   LinkedSample |---   RomMonoSample |---   RomRightSample |---   RomLeftSample |---   RomLinkedSample---   deriving Show
src/Codec/Wav.hs view
@@ -30,8 +30,9 @@ import Data.Int import qualified Data.ByteString.Lazy as L import Data.Monoid-import Data.List-import Data.Array.Diff+import Data.Array.Unboxed+import Data.Array.IO+import Data.Bits   import Control.Monad@@ -65,37 +66,38 @@ parserSelector :: (Audible a, AudibleInWav a) => Int -> Parser a parserSelector 8  = (parseSample :: Parser Word8) >>= return . fromSample . toSample parserSelector 16 = (parseSample :: Parser Int16) >>= return . fromSample . toSample+parserSelector 24 = ((getWord24le >>= return . fromIntegral . (flip shiftL) 8) :: Parser Int32) >>= return . fromSample . toSample parserSelector 32 = (parseSample :: Parser Int32) >>= return . fromSample . toSample parserSelector 64 = (parseSample :: Parser Int64) >>= return . fromSample . toSample-parserSelector n = fail $ show n ++ " bitsPerSample is not supported"+parserSelector n  = fail $ show n ++ " bitsPerSample is not supported"  bytesPerSample :: (AudibleInWav a) => a -> Int bytesPerSample a = div (bitsPerSample a) 8  -importFile :: (IArray DiffUArray a, Audible a, AudibleInWav a) => FilePath -> IO (Either String (Audio a))+importFile :: (MArray IOUArray a IO, IArray UArray a, Audible a, AudibleInWav a) => FilePath -> IO (Either String (Audio a)) importFile n = do   bs <- L.readFile n   return $! runParser parseWav bs -exportFile :: (IArray DiffUArray a, Audible a, AudibleInWav a) => FilePath -> Audio a ->  IO ()+exportFile :: (IArray UArray a, Audible a, AudibleInWav a) => FilePath -> Audio a ->  IO () exportFile f w = L.writeFile f (toLazyByteString $ buildWav w)  -- All numerical values are stored in little endian format ---parseWav :: (IArray DiffUArray a, Audible a, AudibleInWav a) => Parser (Audio a)+parseWav :: (MArray IOUArray a IO, IArray UArray a, Audible a, AudibleInWav a) => Parser (Audio a) parseWav = do-  string "RIFF"+  _ <- string "RIFF" --  n <- remaining --  expect (\w -> fromIntegral w ==  n - 4) getWord32le-  getWord32le -- chunkSize-  string "WAVE"-  many parseUnknownChunk-  (sampleRate,channelNumber,bitsPerSample) <- parseFmt-  many parseUnknownChunk-  sampleData <- parseData channelNumber bitsPerSample-  return $! (Audio sampleRate channelNumber sampleData)+  _ <- getWord32le -- chunkSize+  _ <- string "WAVE"+  _ <- many parseUnknownChunk+  (sampleRate1,channelNumber1,bitsPerSample1) <- parseFmt+  _ <- many parseUnknownChunk+  sampleData1 <- parseData channelNumber1 bitsPerSample1+  return $! (Audio sampleRate1 channelNumber1 sampleData1) -buildWav :: (IArray DiffUArray a, Audible a, AudibleInWav a) => Audio a -> Builder+buildWav :: (IArray UArray a, Audible a, AudibleInWav a) => Audio a -> Builder buildWav a = mconcat [     putString "RIFF"   , putWord32le $ fromIntegral chunkSize@@ -113,22 +115,22 @@  parseFmt :: Parser (Int,Int,Int) parseFmt = do-  string "fmt "+  _ <- string "fmt "   chunkSize <- getWord32le >>= return . fromIntegral-  word16le 1 -- compression code-  channelNumber <- getWord16le >>= return . fromIntegral-  sampleRate <- getWord32le >>= return . fromIntegral+  _ <- word16le 1 -- compression code+  channelNumber1 <- getWord16le >>= return . fromIntegral+  sampleRate1 <- getWord32le >>= return . fromIntegral   avgBytesPerSec <- getWord32le >>= return . fromIntegral   bytesPerSampleSlice <- getWord16le >>= return . fromIntegral-  when (avgBytesPerSec /= sampleRate * bytesPerSampleSlice) $ +  when (avgBytesPerSec /= sampleRate1 * bytesPerSampleSlice) $      fail "avgBytesPerSec /= sampleRate * bytesPerSampleSlise"-  bitsPerSample <- expect (\w -> (mod w 8 == 0) && w <= 64) getWord16le >>= return . fromIntegral-  when (bytesPerSampleSlice /= (div bitsPerSample 8) * channelNumber) $ +  bitsPerSample1 <- expect (\w -> (mod w 8 == 0) && w <= 64) getWord16le >>= return . fromIntegral+  when (bytesPerSampleSlice /= (div bitsPerSample1 8) * channelNumber1) $      fail "bytesPerSampleSlice /= (div bitsPerSample 8) * channelNumber"   skip (chunkSize - 16) -- skip extra fromat bytes-  return $! (sampleRate,channelNumber,bitsPerSample)+  return $! (sampleRate1,channelNumber1,bitsPerSample1) -buildFmt :: (IArray DiffUArray a, Audible a, AudibleInWav a) => Audio a -> Builder+buildFmt :: (IArray UArray a, Audible a, AudibleInWav a) => Audio a -> Builder buildFmt a = mconcat [     putString   $ "fmt "   , putWord32le $ 16 -- chunk size@@ -146,10 +148,10 @@   bytesPerSampleSlice = bytesPS * channelNumber a   avgBytesPerSec = sampleRate a * bytesPerSampleSlice   -parseData :: (IArray DiffUArray a, Audible a, AudibleInWav a)+parseData :: (MArray IOUArray a IO, IArray UArray a, Audible a, AudibleInWav a)   => Int -> Int -> Parser (SampleData a) parseData cn bitsPS = do-  string "data"+  _ <- string "data"   let bytesPS = div bitsPS 8   chunkSize <- expect (\w -> mod (fromIntegral w) bytesPS == 0) getWord32le                >>= return . fromIntegral@@ -157,7 +159,7 @@   when (mod sn (fromIntegral cn) /= 0) $ fail "mod sampelNumber channelNumber /= 0)"   parseSampleData sn (parserSelector bitsPS)   -buildData :: (IArray DiffUArray a, Audible a, AudibleInWav a) => Audio a -> Builder+buildData :: (IArray UArray a, Audible a, AudibleInWav a) => Audio a -> Builder buildData a = mconcat [     putString "data"   , putWord32le $ fromIntegral $ chunkSize@@ -168,7 +170,7 @@  parseUnknownChunk :: Parser () parseUnknownChunk = do-  expect (\s -> s /= "data" && s /= "fmt ") (getString 4)+  _ <- expect (\s -> s /= "data" && s /= "fmt ") (getString 4)   chunkSize <- getWord32le   skip(fromIntegral chunkSize)   return ()
src/Data/Arbitrary.hs view
@@ -21,18 +21,22 @@   , stringNulGen   ) where + import Test.QuickCheck -import Data.Word-import Data.Int import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L-import Data.Array.IArray-import Data.List++import Data.Word+import Data.Int import Data.Char +import Data.List+import Data.Array.IArray+ import System.Random + instance Random Word8 where   randomR = integralRandomR   random = randomR (minBound,maxBound)@@ -70,9 +74,8 @@   random = randomR (minBound,maxBound)  integralRandomR :: (Integral a, RandomGen g) => (a,a) -> g -> (a,g)-integralRandomR  (a,b) g = case randomR (fromIntegral a :: Integer,-                                         fromIntegral b :: Integer) g of-                            (x,g) -> (fromIntegral x, g)+integralRandomR  (a,b) g = case randomR (fromIntegral a :: Integer,fromIntegral b :: Integer) g of+                             (x1,g1) -> (fromIntegral x1, g1)  instance Arbitrary Word8 where     arbitrary       = choose (minBound, maxBound)@@ -110,8 +113,6 @@     arbitrary       = choose (minBound, maxBound)     coarbitrary     = undefined ------------------------------------------------------------------------ instance Arbitrary Char where     arbitrary = choose (0, 255) >>= return . toEnum     coarbitrary = undefined@@ -124,8 +125,6 @@   arbitrary = B.pack `fmap` arbitrary   coarbitrary s = coarbitrary (B.unpack s)   ------------------------------------------------ instance (Arbitrary e, Num i, IArray Array e, Ix i) =>  Arbitrary (Array i e) where   arbitrary = do     n <- choose (1, 128)
src/Data/Audio.hs view
@@ -3,7 +3,7 @@ -- Module      : Data.Audio -- Copyright   : George Giorgidze -- License     : BSD3--- +-- -- Maintainer  : George Giorgidze <http://cs.nott.ac.uk/~ggg/> -- Stability   : Experimental -- Portability : Portable@@ -12,7 +12,7 @@ -- ----------------------------------------------------------------------------- -{-# LANGUAGE FlexibleContexts, UndecidableInstances  #-}+{-# LANGUAGE FlexibleContexts, UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}  module Data.Audio (@@ -34,19 +34,26 @@ import Data.ByteString.Parser import Data.ByteString.Builder +import Test.QuickCheck+ import Data.Word import Data.Int-import Data.Array.Diff-import Data.List++import Data.Array.Unboxed+import Data.Array.IO+ import Data.Monoid-import Test.QuickCheck +import System.IO.Unsafe++ type Sample = Double+type SampleData a = UArray Int a  class Audible a where   toSample :: a -> Sample   fromSample :: Sample -> a-  + -- It is required that sampleNummer `mod` channelNumber == 0 data Audio a = Audio {     sampleRate :: Int@@ -54,67 +61,55 @@   , sampleData :: SampleData a   } -instance (Eq a, IArray DiffUArray a) => Eq (Audio a) where+instance (Eq a, IArray UArray a) => Eq (Audio a) where   a1 == a2 = and [       sampleRate a1 == sampleRate a2     , channelNumber a1 == channelNumber a2     , assocs (sampleData a1) == assocs (sampleData a2)] -instance (Eq e, Ix i, IArray (IOToDiffArray a) e) => Eq (IOToDiffArray a i e) where-  a1 == a2 = assocs a1 == assocs a2 -type SampleData a = DiffUArray Int a--instance (Show a, IArray DiffUArray a) => Show (Audio a) where+instance (Show a, IArray UArray a) => Show (Audio a) where   show a = "Sample Rate: " ++ (show $ sampleRate a) ++ "\n" ++            "Channel Number: " ++ (show $ channelNumber a) ++ "\n" ++            "Sample Data Array Bounds: " ++ (show $ bounds $ sampleData a)  -instance (Arbitrary a, IArray DiffUArray a)-  => Arbitrary (Audio a)-  where+instance (Arbitrary a, IArray UArray a) => Arbitrary (Audio a) where   arbitrary = do     sr <- choose (1, 44100 * 8)     cn <- choose (1, 64)     sn <- choose (1, 1024) >>= return . (fromIntegral cn *)     sd <- arrayGen sn-    return $! Audio sr cn sd+    return (Audio sr cn sd)   coarbitrary = undefined -sampleNumber :: (IArray DiffUArray a) => SampleData a -> Int-sampleNumber sd = (snd $ bounds sd) + 1+sampleNumber :: (IArray UArray a) => SampleData a -> Int+sampleNumber sd = (snd (bounds sd)) + 1 -sampleType :: (IArray DiffUArray a) => SampleData a -> a+sampleType :: (IArray UArray a) => SampleData a -> a sampleType sd = undefined `asTypeOf` (sd ! 0) -convert :: (Audible a, Audible b, IArray DiffUArray a, IArray DiffUArray b) => SampleData a -> SampleData b+convert :: (Audible a, Audible b, IArray UArray a, IArray UArray b) => SampleData a -> SampleData b convert sd = amap (fromSample . toSample) sd ---- It is very important to implement this parser efficiently--- It seems that DiffUArray leaks memmory.--- When I am profilling, profiler shows that function retains memmory which is--- a same size as an array created by parser.--- However when I am running compiled binary almoust twice as much memmory is--- consumed from the system, this behaviour seems very strange to me.--- Updating an array every time when sample is parsed--- results in a poor preformance that is why currently I am using--- list buffer and apdating array with 64 samples at once.-parseSampleData :: (IArray DiffUArray a) => Int -> Parser a -> Parser (SampleData a)-parseSampleData sn p = pAux 0 (array (0, sn - 1) []) []+parseSampleData :: (MArray IOUArray a IO, IArray UArray a) => Int -> Parser a -> Parser (SampleData a)+parseSampleData sn p = pAux 0 unsafeNewArray   where-  pAux i acc buf | (i == sn) = return $! acc // buf-  pAux i acc buf | mod i 64 == 0 = do-    s <- p-    let acc' = seq s $ acc // ((i,s) : buf) in seq acc' $ pAux (i + 1) acc' []-  pAux i acc buf = do+  pAux i acc | (i == sn) = seq i $ seq acc $ return acc+  pAux i acc | otherwise = seq i $ seq acc $ do     s <- p-    seq s $ pAux (i + 1) acc ((i,s) : buf)+    seq s (pAux (i + 1) (unsafeWriteArray acc i s)) -buildSampleData :: (IArray DiffUArray a) => (a -> Builder) -> SampleData a -> Builder-buildSampleData b sd = mconcat $ map b $ elems sd  +  unsafeFreezeAux :: (MArray IOUArray a IO, IArray UArray a) => IOUArray Int a -> IO (SampleData a)+  unsafeFreezeAux = unsafeFreeze +  unsafeNewArray         = unsafePerformIO (newArray_ (0, sn - 1) >>= unsafeFreezeAux )+  unsafeWriteArray a i e = unsafePerformIO (do a' <- unsafeThaw a; writeArray a' i e; unsafeFreezeAux a';)+++buildSampleData :: (IArray UArray a) => (a -> Builder) -> SampleData a -> Builder+buildSampleData b = mconcat . map b . elems+ instance Audible Int8 where   toSample a = (fromIntegral a) / (2 ** 7)   fromSample s = round $ s * (2 ** 7)@@ -141,16 +136,15 @@   fromSample s = round $ (s + 1.0) * (2 ** 63)  instance Audible Float where-  toSample = realToFrac +  toSample = realToFrac   fromSample = realToFrac  instance Audible Double where   toSample = id   fromSample = id-  -data SampleMode = NoLoop | ContLoop | PressLoop-  deriving (Eq, Show)-  ++data SampleMode = NoLoop | ContLoop | PressLoop deriving (Eq, Show)+ instance Arbitrary SampleMode where   arbitrary = oneof [return NoLoop, return ContLoop, return PressLoop]   coarbitrary = undefined
src/Data/ByteString/Builder.hs view
@@ -64,13 +64,12 @@  import Foreign import Data.Monoid-import Data.Word import qualified Data.ByteString      as S import qualified Data.ByteString.Lazy as L  import Data.ByteString.Internal (inlinePerformIO,c2w) import qualified Data.ByteString.Internal as S-import qualified Data.ByteString.Lazy.Internal as L+  ------------------------------------------------------------------------ 
src/Data/ByteString/Parser.hs view
@@ -8,7 +8,7 @@ -- Stability   : experimental -- Portability : Portable ----- The Parser monad. A monad for efficiently building structures from+-- A monad for efficiently building structures from -- encoded lazy ByteStrings. -- -----------------------------------------------------------------------------
src/Tests/Main.hs view
@@ -37,10 +37,10 @@   -- test (prop_audible :: Word64 -> Bool)   test (prop_audible :: Int8 -> Bool)   test (prop_audible :: Int16 -> Bool)-  test (prop_audible :: Int32 -> Bool)  -  -- test (prop_audible :: Int64 -> Bool)  +  test (prop_audible :: Int32 -> Bool)+  -- test (prop_audible :: Int64 -> Bool) -  -- These to tests are commented, because they fail+  -- These two tests are commented, because they fail   -- Reason for that is the fact that Double is not abble to accomodate   -- 64 bit numbers in full precision   where@@ -51,18 +51,18 @@ testMidi :: IO () testMidi =  do   putStrLn "TESTING PARSING AND BUILDING of Midi"-  +   test $ roundTrip buildMessage (parseMessage Nothing)   test $ roundTrip buildMidi parseMidi   test $ \trk -> trk == fromAbsTime (toAbsTime trk :: Track Ticks)   test $ \trk td -> trk == fromRealTime td (toRealTime td trk)-  +   test $ \m -> (not $ null $ tracks m) ==>                let (Midi SingleTrack _ trks) = toSingleTrack m                in   length (concat $ tracks m) - length (concat trks) == length (tracks m) - 1    c <- readFile "mid.txt"-  let midiFiles = lines c +  let midiFiles = lines c   sequence_ $ map f midiFiles   return ()   where@@ -81,13 +81,13 @@ testWav :: IO () testWav =  do   putStrLn "TESTING PARSING AND BUILDING of Wav"- +   test $ roundTrip (Wav.buildWav :: Audio Word8 -> Builder) Wav.parseWav   test $ roundTrip (Wav.buildWav :: Audio Int16 -> Builder) Wav.parseWav   test $ roundTrip (Wav.buildWav :: Audio Int32 -> Builder) Wav.parseWav    c <- readFile "wav.txt"-  let wavFiles = lines c +  let wavFiles = lines c   sequence_ $ map f wavFiles   return ()   where@@ -100,21 +100,21 @@     putStrLn $ "OK"     putStr "Testing  ... "     when (not $ roundTrip Wav.buildWav Wav.parseWav a) $ fail "Failed\n"-    let sd = (convert $ sampleData a) :: SampleData Word8-    when (not $ roundTrip Wav.buildWav Wav.parseWav (a {sampleData = sd})) $ fail "Failed\n"-    let sd = (convert $ sampleData a) :: SampleData Int32-    when (not $ roundTrip Wav.buildWav Wav.parseWav (a {sampleData = sd})) $ fail "Failed\n"+    let sd1 = (convert $ sampleData a) :: SampleData Word8+    when (not $ roundTrip Wav.buildWav Wav.parseWav (a {sampleData = sd1})) $ fail "Failed\n"+    let sd2 = (convert $ sampleData a) :: SampleData Int32+    when (not $ roundTrip Wav.buildWav Wav.parseWav (a {sampleData = sd2})) $ fail "Failed\n"     putStrLn "OK"     Wav.exportFile ("./tmp/" ++ (takeBaseName n) ++ ".wav") a  testSoundFont :: IO () testSoundFont =  do   putStrLn "TESTING PARSING AND BUILDING of SoundFont"-  +   test $ roundTrip SF.buildSoundFont SF.parseSoundFont- +   c <- readFile "sf2.txt"-  let soundFontFiles = lines c +  let soundFontFiles = lines c   sequence_ $ map f soundFontFiles   return ()   where@@ -128,12 +128,12 @@     putStr "Testing  ... "     when (not $ roundTrip SF.buildSoundFont SF.parseSoundFont sf) $ fail "Failed\n"     putStrLn "OK"-    SF.exportFile ("./tmp/" ++ (takeBaseName n) ++ ".wav") sf+    SF.exportFile ("./tmp/" ++ (takeBaseName n) ++ ".sf2") sf  testParserBuilder :: IO () testParserBuilder = do   putStrLn "TESTING PARSING AND BUILDING OF NUMERICAL TYPES"-  +   test $ roundTrip putWord8 getWord8   test $ roundTrip putWord16be getWord16be   test $ roundTrip putWord16le getWord16le@@ -143,7 +143,7 @@   test $ roundTrip putWord32le getWord32le   test $ roundTrip putWord64be getWord64be   test $ roundTrip putWord64le getWord64le-  +   test $ roundTrip putInt8 getInt8   test $ roundTrip putInt16be getInt16be   test $ roundTrip putInt16le getInt16le@@ -151,27 +151,27 @@   test $ roundTrip putInt32le getInt32le   test $ roundTrip putInt64be getInt64be   test $ roundTrip putInt64le getInt64le-  +   test $ roundTrip putWordHost getWordHost   test $ roundTrip putWord16host getWord16host-  test $ roundTrip putWord32host getWord32host  +  test $ roundTrip putWord32host getWord32host   test $ roundTrip putWord64host getWord64host-  +   test $ roundTrip putVarLenBe getVarLenBe   test $ roundTrip putVarLenLe getVarLenLe-  +   putStrLn "TESTING PARSING AND BUILDING OF String and ByteString"-  +   test $ \s1 s2 -> roundTrip (\s -> putString s `mappend` putString s2) (getString $ length s1) s1   test $ \s1 s2 -> roundTrip (\s -> fromByteString s `mappend` fromByteString s2) (getByteString $ B.length s1) s1   test $ \s1 s2 -> roundTrip (\s -> fromLazyByteString s `mappend` fromLazyByteString s2) (getLazyByteString $  L.length s1) s1-  test $ \bs -> roundTrip fromLazyByteString getRemainingLazyByteString bs  -  +  test $ \bs -> roundTrip fromLazyByteString getRemainingLazyByteString bs + main :: IO () main = do   testAudio   testParserBuilder   testMidi   testWav-  testSoundFont  +  testSoundFont