defmodule Strom.MixerTree do alias Strom.Composite alias Strom.Mixer @type event() :: any() @spec new( [Strom.stream_name()] | %{Strom.stream_name() => (event() -> as_boolean(any))}, Strom.stream_name(), list() ) :: Composite.t() @parts 10 def new(inputs, output, opts \\ []) when is_list(inputs) or (is_map(inputs) and map_size(inputs) > 0 and is_list(opts)) do {parts, opts} = Keyword.pop(opts, :parts, @parts) mixers = build_mixers(inputs, 0, parts, output, opts) Composite.new(mixers) end defp build_mixers(inputs, level, parts, final_output, opts) do {mixers, outputs, count} = inputs |> Enum.chunk_every(parts) |> Enum.reduce({[], [], 0}, fn stream_names, {acc, outputs, counter} -> output = String.to_atom("mixer_tree_#{level}_#{counter}") mixer = Mixer.new(stream_names, output, opts) {[mixer | acc], [output | outputs], counter + 1} end) if count > parts do mixers ++ build_mixers(outputs, level + 1, parts, final_output, opts) else mixers ++ [Mixer.new(outputs, final_output)] end end end