module Main where import Data.Binary import Data.Binary.Get import Data.Binary.Put import qualified Data.ByteString.Lazy.Char8 as L import Data.List.Split (chunksOf) import Foreign.C.Types import Foreign.Marshal.Alloc import Foreign.Marshal.Array import Foreign.Ptr import Foreign.Storable import Bindings.Codec2 import System.Environment main :: IO () main = do (fin:fout:_) <- getArgs let mode = c'CODEC2_MODE_3200 codec2 <- c'codec2_create mode nsam <- c'codec2_samples_per_frame codec2 nbit <- c'codec2_bits_per_frame codec2 buf <- mallocBytes $ sizeOf (0 :: CShort) * fromIntegral nsam :: IO (Ptr CShort) let nbyte = floor $ (fromIntegral (nbit + 7) / 8 :: Float) :: Int bits <- mallocBytes $ sizeOf (0 :: CUChar) * fromIntegral nbyte :: IO (Ptr CUChar) input <- L.readFile fin let samps = runGet getSamples input mapM_ (\x -> c2encode codec2 x buf bits nbyte fout) (chunksOf (fromIntegral nsam) samps) getSample :: Get CShort getSample = do s <- getWord16le return $! CShort (fromIntegral s) getSamples :: Get [CShort] getSamples = do empty <- isEmpty if empty then return [] else do samp <- getSample remaining' <- getSamples return (samp:remaining') -- | TODO: Is there a better way to do this? putCUChar :: [CUChar] -> Put putCUChar input = do mapM_ (put . inner) input return () where inner (CUChar i) = i c2encode :: Ptr C'CODEC2 -> [CShort] -- ^ A list that is @nsam@ elements in length. -> Ptr CShort -- ^ The pointer that the ['Word8'] above gets poked to. -> Ptr CUChar -- ^ The pointer that codec2_encode should store in. -> Int -- ^ How big the result is -> String -- ^ Output filename -> IO () c2encode codec2 frame poke' store nbyte fout = do pokeArray poke' frame c'codec2_encode codec2 store poke' -- And, for testing: written <- peekArray nbyte store let bs = runPut $ putCUChar written L.appendFile fout bs