module Sound.Wav.Info
( parseWaveInfo
, updateWaveInfo
, getInfoData
, waveInfoToRiffChunks
) where
import Data.List (intercalate)
import Data.List.Split (splitOn)
import Data.Maybe (catMaybes, fromMaybe)
import qualified Data.Riff as R
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BLC
import Sound.Wav.Data
import Control.Applicative ((<$>))
updateWaveInfo
:: (WaveInfo -> WaveInfo)
-> WaveFile
-> WaveFile
updateWaveInfo updater waveFile = waveFile { waveInfo = updater <$> waveInfo waveFile }
getInfoData
:: WaveFile
-> WaveInfo
getInfoData = fromMaybe waveInfoDefault . waveInfo
waveInfoToRiffChunks :: WaveInfo -> [R.RiffChunk]
waveInfoToRiffChunks waveInfo = catMaybes $ fmap (\x -> x waveInfo)
[ convertString "IARL" . archiveLocation
, convertString "IART" . artist
, convertString "ICMS" . commissionedBy
, convertString "ICMT" . comments
, convertStringList "ICOP" . copyrights
, convertString "ICRD" . creationDate
, convertString "ICRP" . croppedDetails
, convertString "IDIM" . originalDimensions
, convertString "IDPI" . dotsPerInch
, convertStringList "IENG" . engineers
, convertString "IGNR" . genre
, convertStringList "IKEY" . keywords
, convertString "ILGT" . lightness
, convertString "IMED" . originalMedium
, convertString "INAM" . name
, convertString "IPLT" . coloursInPalette
, convertString "IPRD" . originalProduct
, convertString "ISBJ" . subject
, convertString "ISFT" . creationSoftware
, convertString "ISHP" . sharpness
, convertString "ISCR" . contentSource
, convertString "ISRF" . originalForm
, convertString "ITCH" . technician
]
where
convertString :: String -> Maybe String -> Maybe R.RiffChunk
convertString riffId = fmap (R.RiffChunkChild riffId . BLC.pack)
convertStringList :: String -> Maybe [String] -> Maybe R.RiffChunk
convertStringList riffId = convertString riffId . fmap (intercalate "; ")
parseWaveInfo :: [R.RiffChunk] -> WaveInfo
parseWaveInfo = foldr appendWaveInfo waveInfoDefault
appendWaveInfo :: R.RiffChunk -> WaveInfo -> WaveInfo
appendWaveInfo (R.RiffChunkChild riffId rawData) initial =
case riffId of
"IARL" -> initial { archiveLocation = Just asString}
"IART" -> initial { artist = Just asString}
"ICMS" -> initial { commissionedBy = Just asString}
"ICMT" -> initial { comments = Just asString}
"ICOP" -> initial { copyrights = Just asStringList}
"ICRD" -> initial { creationDate = Just asString}
"ICRP" -> initial { croppedDetails = Just asString}
"IDIM" -> initial { originalDimensions = Just asString}
"IDPI" -> initial { dotsPerInch = Just asString}
"IENG" -> initial { engineers = Just asStringList}
"IGNR" -> initial { genre = Just asString}
"IKEY" -> initial { keywords = Just asStringList}
"ILGT" -> initial { lightness = Just asString}
"IMED" -> initial { originalMedium = Just asString}
"INAM" -> initial { name = Just asString}
"IPLT" -> initial { coloursInPalette = Just asString}
"IPRD" -> initial { originalProduct = Just asString}
"ISBJ" -> initial { subject = Just asString}
"ISFT" -> initial { creationSoftware = Just asString}
"ISHP" -> initial { sharpness = Just asString}
"ISCR" -> initial { contentSource = Just asString}
"ISRF" -> initial { originalForm = Just asString}
"ITCH" -> initial { technician = Just asString}
_ -> initial
where
asString = parseInfoString rawData
asStringList = parseInfoStrings rawData
appendWaveInfo _ initial = initial
parseInfoString :: BL.ByteString -> String
parseInfoString = dropTrailingNull . BLC.unpack
dropTrailingNull :: String -> String
dropTrailingNull = reverse . dropWhile (== '\0') . reverse
parseInfoStrings :: BL.ByteString -> [String]
parseInfoStrings = splitOn "; " . parseInfoString