{-# OPTIONS -fno-implicit-prelude #-} module Sox.File where import qualified BinarySample as BinSmp import qualified Sox as Sox import System.Cmd(rawSystem) import System.Exit(ExitCode) import Data.List(isSuffixOf) import qualified Algebra.RealField as RealField import qualified Algebra.Field as Field import PreludeBase import NumericPrelude render :: (RealField.C a, BinSmp.C v) => FilePath -> a -> (a -> [v]) -> IO ExitCode render fileName sampleRate renderer = write fileName sampleRate (renderer sampleRate) renderMono :: (RealField.C a) => FilePath -> a -> (a -> [a]) -> IO ExitCode renderMono fileName sampleRate renderer = writeMono fileName sampleRate (renderer sampleRate) renderStereo :: (RealField.C a) => FilePath -> a -> (a -> [(a,a)]) -> IO ExitCode renderStereo fileName sampleRate renderer = writeStereo fileName sampleRate (renderer sampleRate) write :: (RealField.C a, BinSmp.C v) => FilePath -> a -> [v] -> IO ExitCode write fileName sampleRate signal = writeSignalRaw fileName [] sampleRate (BinSmp.numChannels (head signal)) (BinSmp.signalToBinary signal) writeMono :: (RealField.C a) => FilePath -> a -> [a] -> IO ExitCode writeMono fileName sampleRate signal = writeSignalRaw fileName [] sampleRate 1 (BinSmp.signalToBinaryMono signal) writeStereo :: (RealField.C a) => FilePath -> a -> [(a,a)] -> IO ExitCode writeStereo fileName sampleRate signal = writeSignalRaw fileName [] sampleRate 2 (BinSmp.signalToBinaryStereo signal) writeSignalRaw :: (RealField.C a) => FilePath -> [String] -> a -> Int -> [Int] -> IO ExitCode writeSignalRaw fileName soxOptions sampleRate numChannels stream = let fileNameRaw = fileName ++ ".sw" in do BinSmp.writeInt16Stream fileNameRaw stream rawToAIFF fileName soxOptions sampleRate numChannels encode fileName rawToAIFF :: (RealField.C a) => FilePath -> [String] -> a -> Int -> IO ExitCode rawToAIFF fileName soxOptions sampleRate numChannels = let fileNameRaw = fileName ++ ".sw" fileNameAIFF = fileName ++ ".aiff" in rawSystem "sox" (soxOptions ++ Sox.sampleRateOption sampleRate ++ Sox.channelOption numChannels ++ [fileNameRaw, fileNameAIFF]) encode :: FilePath -> IO ExitCode encode fileName = let fileNameAIFF = fileName ++ ".aiff" --fileNameOGG = fileName ++ ".ogg" fileNameMP3 = fileName ++ ".mp3" in do rawSystem "oggenc" ["--quality", "5", fileNameAIFF] rawSystem "lame" ["-h", fileNameAIFF, fileNameMP3] {- This implementation doesn't work properly. It seems like readFile is run after all system calls to Sox are performed. Aren't the calls serialized? readAIFFMono :: (RealField.C a, Floating a) => FilePath -> IO [a] readAIFFMono file = do putStrLn ("sox "++file++" /tmp/sample.sw") system ("sox "++file++" /tmp/sample.sw") str <- readFile "/tmp/sample.sw" return (binaryToSignalMono str) -} readAIFFMono :: (Field.C a) => FilePath -> IO [a] readAIFFMono file = let stem = if isSuffixOf ".aiff" file then take (length file - 5) file else file tmp = stem ++ ".sw" in do --putStrLn ("sox "++file++" "++tmp) rawSystem "sox" [file, tmp] fmap (map BinSmp.int16ToNum) (BinSmp.readInt16Stream tmp)