Reputation: 897
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
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