{- | Bit manipulation. Taken from Haskore. Bit operations work with numbers on the level of ones and zeros. These functions should be called something like \"pseudo-bit-operations\". They do not reach into the ones and zeros, but they do duplicate the effects using regular math. Note that these bitops, though convenient, are no more efficient than the high-level arithmetic that does the same thing. (This is different than in other languages such as C.) -} module Sound.MIDI.Bit where import Sound.MIDI.Utility (toMaybe, swap) import Data.Word(Word8) import qualified Data.List as List import qualified Data.Bits as Bits {- | Shift bitwise to the left and right. -} shiftL, shiftR :: Bits.Bits a => Int -> a -> a shiftL = flip Bits.shiftL shiftR = flip Bits.shiftR {- | The call @toBase n x@ takes a given number x and "chops it up," returning its digits in base b. Its output is in the form of a big-endian list of ints. divMod is used because it gives the correct rounding for negative numbers. Ex. toBytes 1000 -> toBase 256 1000 -> (256*3) + 232 -> [ 3 , 232 ] -} toBase :: Integral a => a -> a -> [a] toBase b = reverse . List.unfoldr (\n -> toMaybe (n>0) (swap (divMod n b))) toBits, toOctal, toHex, toBytes :: Integral a => a -> [a] toBytes = toBase 256 toHex = toBase 16 toOctal = toBase 8 toBits = toBase 2 {- | Get only n of the least significant bytes of x. If it takes less than n digits to express x, then fill the extra digits with zeros. -} someBytes :: Integral a => Int -> a -> [Word8] someBytes n = reverse . take n . map fromIntegral . List.unfoldr (Just . swap . flip divMod (2^(8::Int))) {- | The fromBase function converts a list of digits in another base into a single base-10 number. fromBase b [x,y,z] = x*b^2 + y*b^1 + z*b^0 -} fromBase :: Integral a => a -> [a] -> a fromBase base xs = foldl (\a x -> base*a+x) 0 xs fromBits, fromOctal, fromHex, fromBytes :: Integral a => [a] -> a fromBytes = fromBase 256 fromHex = fromBase 16 fromOctal = fromBase 8 fromBits = fromBase 2 {- | Like 'replicate' but for big numbers. It chops the list into blocks of tractable sizes (e.g. @maxBound::Int@). -} replicateBig :: Integer -> Integer -> a -> [a] replicateBig base x c = let loopSizes = map fromInteger (toBase base x) b = fromInteger base in foldl (\cs n -> concat (replicate b cs) ++ replicate n c) [] loopSizes {- | @trunc b n@ takes the b least significant bits of n. -} trunc :: Integral a => Int -> a -> a trunc b n = n `mod` (2^b) {- | @splitAt b n@ splits a number into a tuple: (before bit b, after bit b). -} splitAt :: Integral a => Int -> a -> (a, a) splitAt b n = n `divMod` (2^b)