Current section

Files

Jump to
wavex lib wavex.ex
Raw

lib/wavex.ex

defmodule Wavex do
@moduledoc """
Read PCM WAVE data.
"""
alias Wavex.{DataChunk, Error, FormatChunk, RIFFHeader}
alias Wavex.Error.{DataSizeMismatch}
defstruct [:riff_header, :format_chunk, :data_chunk]
@type t :: %__MODULE__{
riff_header: RIFFHeader.t(),
format_chunk: FormatChunk.t(),
data_chunk: DataChunk.t()
}
@riff_header_size 12
@format_chunk_size 24
@non_data_size @riff_header_size + @format_chunk_size + 8
@spec verify_data_size(non_neg_integer, non_neg_integer) ::
:ok | {:error, UnexpectedDataSize.t()}
defp verify_data_size(data_size, data_size), do: :ok
defp verify_data_size(expected_data_size, actual_data_size) do
{:error, %DataSizeMismatch{expected: expected_data_size, actual: actual_data_size}}
end
@doc ~S"""
Read PCM WAVE data.
For more details, see `Wavex.RIFFHeader.read/1`, `Wavex.FormatChunk.read/1`,
and `Wavex.DataChunk.read/2`.
## Examples
iex Wavex.read(<<
...> 0x52, 0x49, 0x46, 0x46, # R I F F
...> 0x34, 0x00, 0x00, 0x00, # 52
...> 0x57, 0x41, 0x56, 0x45, # W A V E
...> 0x66, 0x6D, 0x74, 0x20, # f m t \s
...> 0x10, 0x00, 0x00, 0x00, # 16
...> 0x01, 0x00, 0x02, 0x00, # 1 2
...> 0x22, 0x56, 0x00, 0x00, # 22050
...> 0x88, 0x58, 0x01, 0x00, # 88200
...> 0x04, 0x00, 0x10, 0x00, # 4 16
...> 0x64, 0x61, 0x74, 0x61, # d a t a
...> 0x02, 0x00, 0x00, 0x00, # 2
...> 0x00, 0x00, 0x00, 0x00, # 0
...> 0x00, 0x00, 0x00, 0x00 # 0
...> >>)
{:ok,
%Wavex{
data_chunk: %Wavex.DataChunk{
data: <<0, 0, 0, 0, 0, 0, 0, 0>>,
size: 6
},
format_chunk: %Wavex.FormatChunk{
bits_per_sample: 16,
block_align: 4,
byte_rate: 88_200,
channels: 2,
sample_rate: 22_050
},
riff_header: %Wavex.RIFFHeader{size: 52}
}}
iex> Wavex.read(<<
...> 0x52, 0x49, 0x46, 0x46, # R I F F
...> 0x30, 0x00, 0x00, 0x00, # 48
...> 0x57, 0x41, 0x56, 0x45, # W A V E
...> 0x66, 0x6D, 0x74, 0x20, # f m t \s
...> 0x10, 0x00, 0x00, 0x00, # 16
...> 0x01, 0x00, 0x01, 0x00, # 1 1
...> 0x11, 0x2B, 0x00, 0x00, # 11025
...> 0x22, 0x56, 0x00, 0x00, # 22050
...> 0x02, 0x00, 0x10, 0x00, # 2 16
...> 0x64, 0x61, 0x74, 0x61, # d a t a
...> 0x02, 0x00, 0x00, 0x00, # 2
...> 0x00, 0x00, 0xFE, 0xFF # 0 0 254 255
...> >>)
{:ok,
%Wavex{
data_chunk: %Wavex.DataChunk{data: <<0, 0, 254, 255>>, size: 2},
format_chunk: %Wavex.FormatChunk{
bits_per_sample: 16,
block_align: 2,
byte_rate: 22050,
channels: 1,
sample_rate: 11025
},
riff_header: %Wavex.RIFFHeader{size: 48}
}}
"""
@spec read(binary) :: {:ok, t} | {:error, Error.t()}
def read(binary) when is_binary(binary) do
with {:ok, %RIFFHeader{size: size} = riff_header, etc} <- RIFFHeader.read(binary),
{:ok, %FormatChunk{block_align: block_align} = format_chunk, etc} <-
FormatChunk.read(etc),
{:ok, %DataChunk{size: data_size} = data_chunk} <- DataChunk.read(etc, block_align),
:ok <- verify_data_size(size - @non_data_size, block_align * data_size) do
{:ok, %Wavex{riff_header: riff_header, format_chunk: format_chunk, data_chunk: data_chunk}}
else
{:error, _} = error -> error
end
end
end