MobMedia.PCM (mob_media v0.1.0)

Copy Markdown View Source

Helpers for signed 16-bit little-endian interleaved PCM, the format MobMedia.audio_pcm/2 returns, plus the reference conversion the Android decoder implements and MobMedia.Engine.Fake uses.

Conversion

convert/5 maps channels, then resamples each channel:

  • Channels. Same count: unchanged. To mono: the average of every channel (truncated). Mono to stereo: the sample on both sides. More than two channels to stereo: the first two (front left, front right).
  • Downsampling (in_rate > out_rate): output frame k is the average of input frames floor(k * in / out) up to, not including, floor((k + 1) * in / out): a box filter, which is enough of a low-pass for speech recognition. A box is emitted once all of its input frames exist.
  • Upsampling (in_rate < out_rate): output frame k sits at input position k * in / out and is linearly interpolated between its two neighbours (the last input frame stands alone), rounded half up. Emitted while that position is inside the input.

So n input frames give about n * out / in output frames (within one). iOS uses Core Audio's own converter instead, so its samples differ slightly; the length is the same within a few milliseconds.

This is integer arithmetic only, so a streaming implementation (the Kotlin bridge converts one decoder buffer at a time) produces exactly the same samples as this one.

Summary

Functions

Convert pcm from in_rate Hz / in_channels to out_rate Hz / out_channels (1 or 2). See the moduledoc for the algorithm. A trailing partial frame is dropped.

Length of pcm in milliseconds at rate Hz and channels channels (rounded down).

Parse a WAV file holding 16-bit integer PCM (format 1, or WAVE_FORMAT_EXTENSIBLE with the PCM subformat). {:error, :unsupported} for anything else.

A WAV file (RIFF, 16-bit PCM) holding pcm at rate Hz with channels channels.

Functions

convert(pcm, in_rate, in_channels, out_rate, out_channels)

@spec convert(binary(), pos_integer(), pos_integer(), pos_integer(), 1 | 2) ::
  binary()

Convert pcm from in_rate Hz / in_channels to out_rate Hz / out_channels (1 or 2). See the moduledoc for the algorithm. A trailing partial frame is dropped.

duration_ms(pcm, rate, channels)

@spec duration_ms(binary(), pos_integer(), pos_integer()) :: non_neg_integer()

Length of pcm in milliseconds at rate Hz and channels channels (rounded down).

parse_wav(arg1)

@spec parse_wav(binary()) ::
  {:ok, %{rate: pos_integer(), channels: pos_integer(), pcm: binary()}}
  | {:error, :unsupported}

Parse a WAV file holding 16-bit integer PCM (format 1, or WAVE_FORMAT_EXTENSIBLE with the PCM subformat). {:error, :unsupported} for anything else.

wav(pcm, rate, channels)

@spec wav(binary(), pos_integer(), pos_integer()) :: binary()

A WAV file (RIFF, 16-bit PCM) holding pcm at rate Hz with channels channels.