将 wav 音频格式 ByteString 转换为 Floats
Convert wav audio format ByteString to Floats
我正在处理存储在 .wav 文件中的传感器数据。样本表示介于 -1 和 1 之间的浮点数。
我正在以 ByteString
s 的形式从 .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 位,所以我想使用 Float
s 而不是 Double
s。我也在寻找一种更有效的方式来进行这种转换。
编辑
我目前正在先将 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)。如果是这种情况,我认为您可以使用 getFloat
和 Data.Binary.Get
一次解析 24 位流。
我正在处理存储在 .wav 文件中的传感器数据。样本表示介于 -1 和 1 之间的浮点数。
我正在以 ByteString
s 的形式从 .wav 文件中读取样本,我需要一种方法将此 ByteString
转换为 Float
。所以我正在寻找具有以下签名的函数:
toFloat :: ByteString -> Float
例如。我正在处理一个包含 1 个通道的 .wav 文件,帧率为 48kHz,样本由 24 位组成。这意味着每个样本由 3 个字节组成,我可以像这样从 .wav 文件中读取它:
hGet h 3
。
这里,h
是 .wav 文件的句柄。
如何将从 hGet
获得的这个 ByteString 转换为 Float
(在 -1 和 1 之间)?
正如您在我的 ByteString
to a Double
by first converting it to an Int32
(based on Data.WAVE 中看到的那样。因为我的样本从不大于 32 位,所以我想使用 Float
s 而不是 Double
s。我也在寻找一种更有效的方式来进行这种转换。
编辑
我目前正在先将 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)。如果是这种情况,我认为您可以使用 getFloat
和 Data.Binary.Get
一次解析 24 位流。