我正在处理存储在.wav文件中的传感器数据。样本表示-1和1之间的浮点数。
我正在将.wav文件中的示例作为ByteString
来读取,我需要一种方法将此ByteString
转换为Float
。所以我正在寻找一个具有以下签名的函数:
toFloat :: ByteString -> Float
例如。我正在使用包含1个通道的.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)。
答案 0 :(得分:3)
这样的事情会有所帮助:
getFloat
我的想法是24位值是整数,并且您希望将它们标准化为介于-1和1之间的浮点数(但排除正数1)。如果是这种情况,我认为您可以使用Data.Binary.Get
和{{1}}一次解析您的信息流。
答案 1 :(得分:0)
我使用它来转换为Double
,它似乎也可以帮助浮点数 - 它假设底层数字的二进制表示与内存中的表示形式相同:
https://hackage.haskell.org/package/reinterpret-cast
wordToFloat :: Word32 -> Float
然而,似乎WAV中的24位将具有与您的底层平台不同的内存特性 - 如果您找到正确的尾数/指数长度,应该很容易将其转换为正确的32位浮点并使用此功能进行转换。