{-# LANGUAGE GeneralizedNewtypeDeriving #-} module CD.CDDB where import Control.DeepSeq import Data.Binary import Data.Binary.Get import Data.Binary.Put import Data.Bits import Data.Char newtype DiscID = DiscID Word32 deriving (Eq, NFData) instance Binary DiscID where put (DiscID w) = putWord32le w get = getWord32le >>= return . DiscID instance Enum DiscID where succ (DiscID w) = DiscID $ succ w pred (DiscID w) = DiscID $ pred w toEnum n = DiscID $ toEnum n fromEnum (DiscID w) = fromEnum w enumFrom (DiscID w) = map DiscID (enumFrom w) enumFromThen (DiscID v) (DiscID w) = map DiscID (enumFromThen v w) enumFromTo (DiscID v) (DiscID w) = map DiscID (enumFromTo v w) enumFromThenTo (DiscID u) (DiscID v) (DiscID w) = map DiscID (enumFromThenTo u v w) instance Show DiscID where show (DiscID w) = (intToDigit $ fromIntegral ((shiftR w 28) .&. 15)) : (intToDigit $ fromIntegral ((shiftR w 24) .&. 15)) : (intToDigit $ fromIntegral ((shiftR w 20) .&. 15)) : (intToDigit $ fromIntegral ((shiftR w 16) .&. 15)) : (intToDigit $ fromIntegral ((shiftR w 12) .&. 15)) : (intToDigit $ fromIntegral ((shiftR w 8) .&. 15)) : (intToDigit $ fromIntegral ((shiftR w 4) .&. 15)) : (intToDigit $ fromIntegral (w .&. 15)) : [] -- |Calculate CDDB DiscID: the result is XXYYYYZZ where XX is the number of tracks, YYYY is the total length of the CD is seconds, and ZZ is ... cddbDiscId :: [Int] -> DiscID cddbDiscId xs = toEnum $ length xs + shiftL (quot (last xs) 75) 8 + shiftL (rem (foldl (\x y -> x + sumDigits(2 + quot y 75)) 0 (0:init xs)) 255 ) 24 where sumDigits 0 = 0 sumDigits n = (rem n 10) + sumDigits (quot n 10)