HCodecs-0.3: src/Tests/Main.hs
module Main where
import Codec.Midi
import qualified Codec.Wav as Wav
import qualified Codec.SoundFont as SF
import Data.Audio
import Data.Arbitrary
import Data.ByteString.Parser
import Data.ByteString.Builder
import Test.QuickCheck hiding ((.&.))
import Data.Int
import Data.Word
import Data.Bits
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Control.Monad
import Data.Monoid
import Debug.Trace
import System.FilePath
test :: Testable prop => prop -> IO ()
test = quickCheck
roundTrip :: (Eq a, Show a) => (a -> Builder) -> Parser a -> a -> Bool
roundTrip b p a = if Right a == ea'
then True
else trace (unlines $ [show ea']) $ False
where ea' = runParser p bs
bs = toLazyByteString $ b a
testAudio :: IO ()
testAudio = do
putStrLn "TESTING Inctances of Audible"
test (prop_audible :: Word8 -> Bool)
test (prop_audible :: Word16 -> Bool)
test (prop_audible :: Word32 -> Bool)
-- 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)
-- 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
prop_audible :: (Eq a, Audible a) => a -> Bool
prop_audible a = (a == fromSample s) && (s >= -1.0) && (s <= 1.0)
where s = toSample a
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
sequence_ $ map f midiFiles
return ()
where
f n = do
putStr $ "Parsing " ++ n ++ " ... "
r <- importFile n
m <- case r of
Left e -> fail $ "\n Failed: " ++ e ++ "\n"
Right m -> return m
putStrLn $ "OK"
putStr "Testing ... "
when (not $ roundTrip buildMidi parseMidi m) $ fail "Failed\n"
putStrLn "OK"
exportFile ("./tmp/" ++ (takeBaseName n) ++ ".mid") m
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
sequence_ $ map f wavFiles
return ()
where
f n = do
putStr $ "Parsing " ++ n ++ " ... "
r <- Wav.importFile n
a <- case r of
Left e -> fail $ "\n Failed: " ++ e ++ "\n"
Right a -> return $! (a :: Audio Int16)
putStrLn $ "OK"
putStr "Testing ... "
when (not $ roundTrip Wav.buildWav Wav.parseWav a) $ 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
sequence_ $ map f soundFontFiles
return ()
where
f n = do
putStr $ "Parsing " ++ n ++ " ... "
r <- SF.importFile n
sf <- case r of
Left e -> fail $ "\n Failed: " ++ e ++ "\n"
Right sf -> return sf
putStrLn $ "OK"
putStr "Testing ... "
when (not $ roundTrip SF.buildSoundFont SF.parseSoundFont sf) $ fail "Failed\n"
putStrLn "OK"
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
test $ \w -> roundTrip putWord24be getWord24be (w .&. 0xFFFFFF)
test $ \w -> roundTrip putWord24le getWord24le (w .&. 0xFFFFFF)
test $ roundTrip putWord32be getWord32be
test $ roundTrip putWord32le getWord32le
test $ roundTrip putWord64be getWord64be
test $ roundTrip putWord64le getWord64le
test $ roundTrip putInt8 getInt8
test $ roundTrip putInt16be getInt16be
test $ roundTrip putInt16le getInt16le
test $ roundTrip putInt32be getInt32be
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 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
main :: IO ()
main = do
testAudio
testParserBuilder
testMidi
testWav
testSoundFont