我正在处理存储在.wav文件中的传感器数据。样本表示-1到1之间的浮点数。
我正在将.wav文件中的示例作为ByteString读取,我需要一种将该ByteString转换为Float的方法。因此,我正在寻找一个具有以下签名的函数:
toFloat :: ByteString -> Float
例如。我正在处理一个包含一个通道的.wav文件,它的帧数为48 and,样本由24位组成。这意味着每个示例由3个字节组成,我可以从.wav文件中读取它,如下所示:hGet h 3。在这里,h是.wav文件的句柄。
如何将从hGet获得的hGet转换为Float (介于-1和1之间)?
正如您在我的前一个问题中所看到的,我目前正在通过首先将ByteString转换为Int32 (基于Data.WAVE)将其转换为Double。由于我的样本从未超过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) ByteString作为bsToDouble的输入直接来自hGet h 3,整数是示例中的字节数(即3)。
发布于 2017-01-13 14:02:02
像这样的东西有帮助吗?
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位。
发布于 2017-01-12 14:50:42
我使用它来转换为Double,它似乎对浮动也有帮助-它假设底层数字的二进制表示与内存中的表示相同。:https://hackage.haskell.org/package/reinterpret-cast。
wordToFloat :: Word32 -> Float然而,与底层平台相比,WAV中的24位似乎具有不同的内存特性--如果您找到了正确的尾数/指数长度,那么应该很容易将其转换为适当的32位浮点数,并使用此函数进行转换。
https://stackoverflow.com/questions/41599845
复制相似问题