我试图读取.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
。您可能还应该对这些类型进行参数化。 如何使其快速
Int8
/ Int16
,因为8位和16位轨道是最常用的两种格式。您可能想坚持学习他们的项目。import Data.Int
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/