ByteString representation of a Double conversion

2019-08-04 16:23发布

问题:

I'm writing my own WAVE parser that uses Conduit so I can stream values, one by one, through a pipeline.

I get a sample from a .wav file via hGet (n is the number of bytes per sample for that wav file):

bytes <- hGet h n

This gives me a ByteString with a representation of the Double value of the sample. E.g.:

"\131\237\242" represents -0.10212671756744385

"g\238\242" represents -0.10209953784942627

"\215\238\242" represents -0.10208618640899658.

The possible values are between -1 and +1.

Is there any convenient way to do this conversion? Is there a library available to do this?

I've taken a look at existing WAVE parsers for Haskell. Data.WAVE parses a .wav file and returns the samples as left-justified Int32 values. I've found a workaround where I use it's library functions to convert my ByteString to a left-justified Int32 and then convert it to a Double using the library's sampleToDouble function. This works, but I'm wondering if there is a more direct way of solving this problem.

Another possible solution would be to convert the ByteString to [Word8] with ByteString.unpack, convert [Word8] to Word32 and then convert this value to a Float using the conversion functions from Data.Binary.IEEE754. Would this be a good solution? One problem is that I currently don't know how to convert a four-element list of [Word8] to Word32.

回答1:

This is my current solution to turn the ByteString into a double:

convertNBytesLen :: [Word8] -> Int32
convertNBytesLen = foldr accum 0
  where accum bs a = 256 * a + fromIntegral bs


bsToDouble :: S.ByteString -> Int -> Double
bsToDouble bs n = if intV >= 0
                   then fromIntegral intV / 2147483647
                   else - (fromIntegral intV / (-2147483648))
  where intV = convertNBytesLen (S.unpack bs) `shift` (32 - 8 * n)

I'm wondering if this can be done in a more efficient manner.