我正在处理存储在 .wav 文件中的传感器数据。样本表示 -1 和 1 之间的浮点数。
我正在从 .wav 文件中读取样本为 ByteString
s,我需要一种方法来转换此 ByteString
到 Float
.所以我正在寻找具有以下签名的函数:toFloat :: ByteString -> Float
例如。我正在处理一个包含 1 个 channel 的 .wav 文件,帧率为 48kHz,样本由 24 位组成。这意味着每个样本由 3 个字节组成,我可以从 .wav 文件中读取它,如下所示:hGet h 3
.
在这里,h
是 .wav 文件的句柄。
如何转换我从 hGet
获得的这个 ByteString到 Float
(在 -1 和 1 之间)?
正如你在我的 previous question 中看到的,我目前正在转换 ByteString
到 Double
首先将其转换为 Int32
(基于 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)
ByteString
作为 bsToDouble
的输入直接来自 hGet h 3
整数是样本中的字节数(即 3)。
最佳答案
这样的事情有帮助吗:
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 位。
关于haskell - 将 wav 音频格式 ByteString 转换为 Floats,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41599845/