Saturday, 15 March 2014

audio - Speed up reading .wav and analyse in Haskell? -



audio - Speed up reading .wav and analyse in Haskell? -

i'm trying read in .wav file , maybe play around info i'm stuck. reading file in, storing in struct, , writing file takes long time. added processing take longer.

i've posted code straight forward. must missing , making programme more complicated or redundant necessary.

class="lang-hs prettyprint-override">import qualified data.char dc import qualified data.word dw import qualified data.int di import qualified data.binary.get bg import qualified data.bytestring.lazy bl import qualified data.bytestring.lazy.internal bli import qualified system.environment se import qualified system.io sio main = (fstfilename:sndfilename:_) <- se.getargs fstfile <- sio.openfile fstfilename sio.readmode input <- bl.hgetcontents fstfile raw_wav <- homecoming $ bg.runget parsewav input sndfile <- sio.openfile sndfilename sio.writemode sio.hputstr sndfile (show (wavdata raw_wav)) info sample = onechannel {mono :: integer} | twochannel {leftchannel :: integer, rightchannel :: integer} instance show sample show (onechannel m) = show m ++ " " show (twochannel l r) = show l ++ "-" ++ show r ++ " " info rawavfile = rawavfile {numchannels :: integer, samplerate :: integer, bitspersample :: integer, wavdata :: [sample]} deriving (show) parsewav :: bg.get rawavfile parsewav = bg.skip 22 num_channels <- bg.getword16le sample_rate <- bg.getword32le bg.skip 6 bits_per_sample <- bg.getword16le rem <- bg.getremaininglazybytestring wav_data <- homecoming $ bl.drop 8 (bl.dropwhile ((/=) (fromintegral (dc.ord 'd') :: dw.word8)) rem) nc <- homecoming $ tointeger num_channels sr <- homecoming $ tointeger sample_rate bps <- homecoming $ tointeger bits_per_sample homecoming $ 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" 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

why slow.

you using integer storing individual samples. integer special type storing arbitrary precision integers. such, there amount of overhead every read/write of these values. avoid @ costs. suggest using sized types such int8/int16. should parametrise on these types.

you storing samples tagged union of channel types. each sample. that's lot of overhead. expect number of channels alter mid-file? not.

you using list store samples introduces lot of overhead when talking continuous streams of bytes.

how create fast

parametrise type on bit depth of sample. suggest straight using int8/int16 8 , 16 bit tracks 2 mutual formats used. want stick them learning project.

import data.int

use unboxed vectors store data. avoids massive overhead of (lazy) lists , thunks, , cut down memory consumption boot.

import data.vector.unboxed v

don't store number of tracks. length $ tracks $ wavfile time need it. eliminate usages of integer in code (unless really need store number greater 2^64)

data rawavfile b = rawavfile { samplerate :: int, tracks :: [vector b] } deriving (show)

use types guide you. binary polymorphic on homecoming types. inquire type want, , parse right number of bytes without intervention.

parsewav :: bl.bytestring -> bg.get (rawavfile b) wav <- parsewav input :: bg.get (rawavfile int16)

you should using bg.runget once, run parser against bytestring.

haskell audio wav

No comments:

Post a Comment