packages feed

flaccuraterip-0.1: CD/CDDB.hs

{-# 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)