gpt4 book ai didi

haskell - 加快阅读 .wav 并在 Haskell 中进行分析?

转载 作者:行者123 更新时间:2023-12-02 22:21:10 25 4
gpt4 key购买 nike

我正在尝试读取 .wav 文件,并且最终可能会使用数据,但我被卡住了。只是读入文件,将其存储在结构中,然后将其写入另一个文件需要很长时间。任何增加的处理都需要更长的时间。

我已经发布了我的代码,该代码相当简单。我一定遗漏了一些东西,使程序比必要的更复杂或多余。

import qualified Data.Char as DC
import qualified Data.Word as DW
import qualified Data.Int as DI

import qualified Data.Binary.Get as BG
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Internal as BLI

import qualified System.Environment as SE
import qualified System.IO as SIO

main = do
(fstfilename:sndfilename:_) <- SE.getArgs
fstfile <- SIO.openFile fstfilename SIO.ReadMode
input <- BL.hGetContents fstfile

raw_wav <- return $ BG.runGet parseWav input

sndfile <- SIO.openFile sndfilename SIO.WriteMode
SIO.hPutStr sndfile (show (wavData raw_wav))

data Sample = OneChannel {mono :: Integer} |
TwoChannel {leftChannel :: Integer,
rightChannel :: Integer}

instance Show Sample where
show (OneChannel m) = show m ++ " "
show (TwoChannel l r) = show l ++ "-" ++ show r ++ " "

data RaWavFile = RaWavFile {numChannels :: Integer,
sampleRate :: Integer,
bitsPerSample :: Integer,
wavData :: [Sample]}
deriving (Show)

parseWav :: BG.Get RaWavFile
parseWav = do
BG.skip 22
num_channels <- BG.getWord16le
sample_rate <- BG.getWord32le
BG.skip 6
bits_per_sample <- BG.getWord16le

rem <- BG.getRemainingLazyByteString
wav_data <- return $ BL.drop 8 (BL.dropWhile
((/=) (fromIntegral (DC.ord 'd') :: DW.Word8)) rem)

nc <- return $ toInteger num_channels
sr <- return $ toInteger sample_rate
bps <- return $ toInteger bits_per_sample
return $ RaWavFile nc sr bps (orgSamples nc bps wav_data)

-- numChannels bitpersample wavData
orgSamples :: Integer -> Integer -> BL.ByteString -> [Sample]
orgSamples nc bps BLI.Empty = []
orgSamples nc bps bs
| nc == 1 = (OneChannel (rle fb)):(orgSamples nc bps rst)
| nc == 2 = (TwoChannel (rle fb) (rle sb)):(orgSamples nc bps rsst)
| otherwise = error "Number of channels not 1 or 2"
where nb = fromIntegral (bps `div` 8) :: DI.Int64
(fb, rst) = BL.splitAt nb bs
(sb, rsst) = BL.splitAt nb rst
rle = toInteger . BG.runGet BG.getWord16le

最佳答案

为什么慢。

  • 您正在使用 Integer用于存储单个样本。 Integer是一种用于存储任意精度整数的特殊类型。因此,每次读取/写入这些值都会产生大量开销。不惜一切代价避免。我建议使用特定大小的类型,例如 Int8/Int16 .您可能还应该对这些类型进行参数化。
  • 您将样本存储为 channel 类型的标记联合。对于每个样本。这是很多开销。你真的期望 channel 数量会改变中间文件吗?可能不是。
  • 您正在使用一个列表来存储您的样本,当您实质上是在谈论连续的字节流时,这会带来很多开销。

  • 如何让它快速
  • 在样本的位深度上参数化您的类型。我建议直接使用Int8/Int16因为 8 位和 16 位轨道是最常用的两种格式。您可能想坚持使用它们进行学习项目。
    import Data.Int
  • 使用Unboxed Vectors存储您的数据。这避免了(惰性)列表和 thunk 的大量开销,并将显着减少启动时的内存消耗。
    import Data.Vector.Unboxed as V
  • 不要存储轨道的数量。 length $ tracks $ wavFile将在您需要时随时取回。消除代码中对 Integer 的所有使用(除非您真的需要存储大于 2^64 的数字)
    data RaWavFile b = RaWavFile {
    sampleRate :: Int,
    tracks :: [Vector b] }
    deriving (Show)
  • 使用类型来指导您。 binary在返回类型上是多态的。只需向它询问您想要的类型,它就会在没有您干预的情况下解析正确的字节数。
    parseWav :: BL.ByteString -> BG.Get (RaWavFile b)
    wav <- parseWav input :: BG.Get (RaWavFile Int16)
  • 您应该只使用 BG.runGet一次,针对一个字节串运行你的解析器。
  • 关于haskell - 加快阅读 .wav 并在 Haskell 中进行分析?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24319431/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com