RudolfVonKrugstein
How to convert binary data with primitive data types
Dear Community,
I have a binary of float32 representing audio data with floats in the range of [-1,1].
I want this audio data converted into a binary of signed 16 bit integers.
What is an efficient way of doing this in elexir? I tried:
def to_linear16(<<>>) do
<<>>
end
def to_linear16(<<v::float-size(32), r::binary>>) do
Logger.debug("#{inspect(v)}")
f =
if v < 0 do
<<trunc(v * 0x8000)::size(16)>>
else
<<trunc(v * 0x7FFF)::size(16)>>
end
f <> to_linear16(r)
end
But there is something wrong:
- I get an
no function clause matching in to_linear16/1also I am only giving it data, that is definitly multples of 4 bytes long. - I check the intermediate results via logging of the float32 extracted form the binary and they are not what I expect. In fact, if I put the same binary into
Nx.from_tensor(b,:f32)I get different results.
So I am very puzzled here.
- What is an efficient way of doing this in elixir or am I already on the right track here?
- What am I doing wrong in the pattern matching? I am always taking a 32bit float from the beginning of the binary.So how could the matching fail?
Thank you!
Marked As Solved
dimitarvp
Have you checked for endianness? Erlang assumes big-endian-arranged bytes when extracting floats the way you are doing it.
Demo:
bin = <<:math.pi()::float-32>> <> <<0, 0, 0>>
<<64, 73, 15, 219, 0, 0, 0>>
<<x::float-32, rest::binary>> = bin
<<64, 73, 15, 219, 0, 0, 0>>
x
3.1415927410125732
<<x::big-float-32, rest::binary>> = bin
<<64, 73, 15, 219, 0, 0, 0>>
x
3.1415927410125732
<<x::little-float-32, rest::binary>> = bin
<<64, 73, 15, 219, 0, 0, 0>>
x
-4.03314608963584e16
As you can see, by default big endian is used. So if your values are little-endian-arranged, you have to specify that explicitly.
In your example, try changing float-size(32) to little-float-size(32) and see if it works.
Also Liked
RudolfVonKrugstein
Well, I solved it exactly as you said:
def to_linear16(<<>>) do
<<>>
end
# use littel-float-size here, as it seems our floats are littel endian
def to_linear16(<<v::little-float-size(32), r::binary>>) do
Logger.debug("#{inspect(v)}")
f =
if v < 0 do
<<trunc(v * 0x8000)::size(16)>>
else
<<trunc(v * 0x7FFF)::size(16)>>
end
f <> to_linear16(r)
end
I am still not sure, if this is an efficient way, but it works.
I might switch to the membrance framework, as it seems to have functionality like this build in.
Last Post!
RudolfVonKrugstein
Well, I solved it exactly as you said:
def to_linear16(<<>>) do
<<>>
end
# use littel-float-size here, as it seems our floats are littel endian
def to_linear16(<<v::little-float-size(32), r::binary>>) do
Logger.debug("#{inspect(v)}")
f =
if v < 0 do
<<trunc(v * 0x8000)::size(16)>>
else
<<trunc(v * 0x7FFF)::size(16)>>
end
f <> to_linear16(r)
end
I am still not sure, if this is an efficient way, but it works.
I might switch to the membrance framework, as it seems to have functionality like this build in.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









