packages feed

opus-0.3.0.0: test/OpusCompare.hs

-- | This module is a wrapper around opus_compare.c.
-- Calling 'compareFiles' is equivalent to running the opus_compare executable.
-- Due to conflicting definitions of "main" (one in opus_compare and one in our
-- Haskell program), we assume that opus_compare has been compiled with a define
-- that renames its main function to "opus_compare_main".
module OpusCompare where

import           Codec.Audio.Opus.Internal.Opus
import           Foreign
import           Foreign.C.Types
import           Foreign.C.String

-- | Channel type
data Channel = Mono | Stereo
  deriving (Eq, Show)

-- | Compares two Opus files using the opus_compare executable code. The result
-- is True if the files are quality-wise identical (which doesn't necessarily
-- mean that they are byte-wise identical due to entropy in the Opus encoding).
-- The result is False if the files are measurably different.
compareFiles :: Channel -> SamplingRate -> FilePath -> FilePath -> IO Bool
compareFiles channel samplingRate filePath1 filePath2 =
    withCString "opus_compare" $ \cProgramName ->
      withCString "-r" $ \cSROpt ->  -- sampling rate option
        withCString (show $ unSamplingRate samplingRate) $ \cSRVal -> -- sampling rate value
          withCString filePath1 $ \cFile1 -> -- first file
            withCString filePath2 $ \cFile2 -> -- second file
              if channel == Mono
                then allocaArray 5 $ \p -> do
                  pokeArray p [cProgramName, cSROpt, cSRVal, cFile1, cFile2]
                  c_opus_compare_main 5 p >>= \r -> return (r == 0)
                else withCString "-s" $ \cSOpt -> -- stereo option
                  allocaArray 6 $ \p -> do
                    pokeArray p [cProgramName, cSOpt, cSROpt, cSRVal, cFile1, cFile2]
                    c_opus_compare_main 6 p >>= \r -> return (r == 0)

-- | Call the opus_compare_main function, which should be the main function
-- within opus_compare.c. We assume that when compiling opus_compare.c, a
-- define was used to rename the main function to "opus_compare_main".
foreign import ccall unsafe "opus_compare_wrapper.c opus_compare_main"
    c_opus_compare_main
      :: Int
      -- ^ number of arguments
      -> Ptr (Ptr CChar)
      -- ^ arguments
      -> IO Int