lib/supercollider/synthdef/encoder.ex

defmodule SuperCollider.SynthDef.Encoder do

  @moduledoc """
  Helper functions to encode Elixir data types into the binary format used by SuperCollider.
  """

  ## Encoder helpers

  @doc """
  Takes a string and encodes it into SuperCollider's pstring format.
  """
  def write_pstring(string) do
    string_length = String.length(string)
    <<
      string_length::big-integer-8,
      string::binary,
    >>
  end

  @doc """
  Takes an number and encodes it into SuperCollider's 32-bit integer format.
  """
  def write_32(num), do: <<num::big-signed-32>>

  @doc """
  Takes an number and encodes it into SuperCollider's 16-bit integer format.
  """
  def write_16(num), do: <<num::big-signed-16>>

  @doc """
  Takes an number and encodes it into SuperCollider's 8-bit integer format.
  """
  def write_8(num), do: <<num::big-integer-8>>

  @doc """
  Takes an number and encodes it into SuperCollider's 32-bit float format.
  """
  def write_float(num), do: <<num::big-float-32>>

  @doc """
  Takes a list of numbers and encodes it into SuperCollider's 32-bit float array format.
  """
  def write_floats(numbers) when is_list(numbers) do
    numbers |> Enum.map(fn num -> write_float(num) end) |> Enum.join(<<>>)
  end

  @doc """
  Takes a list of key-value pairs and encodes it into SuperCollider's dictionary format.

  In this function, the key-value pairs must be of the following types:
  * key: is a string
  * value: is an integer.
  """
  def write_name_integer_pairs(name_value_pairs) do
    name_value_pairs
    |> Enum.map(fn %{parameter_index: parameter_index, parameter_name: parameter_name} ->
      <<
        String.length(parameter_name)::big-integer-8,
        parameter_name::binary,
        parameter_index::big-integer-32
      >>
    end)
    |> Enum.join(<<>>)
  end

  @doc """
  Takes a list of key-value pairs and encodes it into SuperCollider's dictionary format.

  In this function, the key-value pairs must be of the following types:
  * key: is a string
  * value: is a float.
  """
  def write_name_float_pairs(name_value_pairs) do
    name_value_pairs
    |> Enum.map(fn %{parameter_index: parameter_index, parameter_name: parameter_name} ->
      <<
        String.length(parameter_name)::big-integer-8,
        parameter_name::binary,
        parameter_index::big-float-32
      >>
    end)
    |> Enum.join(<<>>)
  end


end