将 wav 音频格式 ByteString 转换为 Floats

Convert wav audio format ByteString to Floats

我正在处理存储在 .wav 文件中的传感器数据。样本表示介于 -1 和 1 之间的浮点数。

我正在以 ByteStrings 的形式从 .wav 文件中读取样本,我需要一种方法将此 ByteString 转换为 Float。所以我正在寻找具有以下签名的函数:

toFloat :: ByteString -> Float

例如。我正在处理一个包含 1 个通道的 .wav 文件,帧率为 48kHz,样本由 24 位组成。这意味着每个样本由 3 个字节组成,我可以像这样从 .wav 文件中读取它: hGet h 3。 这里,h 是 .wav 文件的句柄。

如何将从 hGet 获得的这个 ByteString 转换为 Float(在 -1 和 1 之间)?

正如您在我的 , I'm currently converting the ByteString to a Double by first converting it to an Int32 (based on Data.WAVE 中看到的那样。因为我的样本从不大于 32 位,所以我想使用 Floats 而不是 Doubles。我也在寻找一种更有效的方式来进行这种转换。

编辑 我目前正在先将 ByteString 转换为 Int32,然后再转换为 Double。这是由 bsToDouble:

完成的
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) 

作为 bsToDouble 输入的 ByteString 直接来自 hGet h 3,整数是样本中的字节数(即 3)。

我正在使用它来转换为 Double,它似乎对浮点数也有帮助 - 它假定基础数字的二进制表示与 in-memory 表示相同。: https://hackage.haskell.org/package/reinterpret-cast

wordToFloat :: Word32 -> Float

然而,WAV 中的 24 位似乎与您的底层平台具有不同的内存特性 - 如果您找到正确的 mantissa/exponent 长度,将它转换为正确的 32 位应该很容易浮动并使用此函数进行转换。

这样的事情有帮助吗:

import Data.Int (Int32)
import Data.Bits ((.|.),(.&.),unsafeShiftL)
import Data.Word (Word32)
import Data.Binary
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BSU

int32_24be :: BS.ByteString -> Int32
int32_24be = \s ->
  let x =   unsafeShiftL (fromIntegral (BSU.unsafeIndex s 0)) 16
        .|. unsafeShiftL (fromIntegral (BSU.unsafeIndex s 1))  8
        .|.               fromIntegral (BSU.unsafeIndex s 2)
        :: Int32
      y = fromIntegral x :: Word32
  in fromIntegral (if x .&. 0x00800000 > 0 then y .|. 0xFF000000 else y .&. 0x00FFFFFF)

getFloat :: BS.ByteString -> Float
getFloat = (/ 2^^23) . fromIntegral . int32_24be

我的想法是 24 位值是整数,您希望将它们标准化为介于 -1 和 1 之间的浮点数(但不包括正 1)。如果是这种情况,我认为您可以使用 getFloatData.Binary.Get 一次解析 24 位流。