Thomas Vanhelden
Thomas Vanhelden

Reputation: 897

Efficiently converting and writing a vector to a handle

I'm writing a program that performs a transformation on sample data in a file. I do this by reading the file, turning the content into a vector, performing the transformation on the vector and then writing the vector back to the file. I already (think) I have an efficient way of reading the file and turning its content into a vector but I'm still looking for an efficient way to write the resulting vector back to memory.

The samples in the file are 24 bit integers (3 bytes) and I transform them to floats by normalizing them.

I turn the file's content into a vector by reading all samples via ByteString.hGet. I can then simply use Vector.generate to convert every 3 bytes of the ByteString into a sample.

My problem is with writing the result back to a file. At least I think there is a problem. I'm currently converting the vector and writing it to a file as follows:

import Data.Vector.Unboxed as U
import Data.ByteString as BS

putSamples :: Handle -> U.Vector Float -> IO ()
putSamples h vec = U.forM_ vec (BS.hPut h . BS.pack . unconvert 3 . Int)

As you can see, I first convert the Float back to an Int by de-normalizing it,turn the Int into 3 bytes via unconvert 3, pack the result into a ByteString of 3 bytes via ByteString.pack and then write the result to a handle via ByteString.hPut.

This seems terribly inefficient because I'm calling hPut for every single sample. Is there a way to do this more efficiently?

Upvotes: 2

Views: 92

Answers (1)

ryachza
ryachza

Reputation: 4540

Example shell creating a Serialize instance:

import qualified Data.Vector.Unboxed as U
import qualified Data.Serialize as S

newtype MyVec = MyVec (U.Vector Float)

instance S.Serialize MyVec where
  put (MyVec vec) =
    U.forM_ vec $ \_ ->
      let word1 = 0; word2 = 0; word3 = 0
      in do
        S.putWord8 word1
        S.putWord8 word2
        S.putWord8 word3
  get = error "MyVec::S.Serialize: not implemented"

test = S.encode $ MyVec $ U.singleton 0

Upvotes: 1

Related Questions