Skip to content

Instantly share code, notes, and snippets.

@jimm
Created January 31, 2019 14:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jimm/29bb05ebb7578b75a9dda04622dee317 to your computer and use it in GitHub Desktop.
Save jimm/29bb05ebb7578b75a9dda04622dee317 to your computer and use it in GitHub Desktop.
Sample Elixir GenServer
defmodule MyGenServer do
use GenServer
use Blister.MIDI.IO, type: :input
require Logger
defmodule State do
defstruct [:io, :connections, :listener]
end
# ================ Public API ================
def start_link(driver, name) do
{:ok, in_pid} = driver.open(:input, name)
listener = spawn_link(__MODULE__, :loop, [{nil, nil}])
state = %State{io: %Blister.MIDI.IO{driver: driver, port_pid: in_pid,
port_name: name},
connections: [],
listener: listener}
{:ok, pid} = GenServer.start_link(__MODULE__, state)
send(listener, {:set_state, {in_pid, pid}})
:ok = driver.listen(in_pid, listener)
{:ok, pid}
end
def add_connection(pid, connection) do
GenServer.call(pid, {:add_connection, connection})
end
def remove_connection(pid, connection) do
GenServer.call(pid, {:remove_connection, connection})
end
@doc "Used internally to process incoming MIDI messages."
def receive_messages(pid, messages) do
GenServer.call(pid, {:messages, messages})
end
# ================ GenServer ================
def handle_call({:add_connection, conn}, _from, state) do
{:reply, :ok, %{state | connections: [conn|state.connections]}}
end
def handle_call({:remove_connection, conn}, _from, state) do
{:reply, :ok, %{state | connections: List.delete(state.connections, conn)}}
end
def handle_call({:messages, []}, _from, state) do
{:reply, :ok, state}
end
def handle_call({:messages, messages}, _from, state) do
state.connections |> Enum.map(&(Blister.Connection.midi_in(&1, messages)))
{:reply, :ok, state}
end
def handle_cast(:stop, state) do
send(state.listener, :stop)
:ok = close(state)
{:stop, :normal, nil}
end
# ================ PortMidi listener ================
def loop({portmidi_input_pid, app_input_pid} = state) do
receive do
{^portmidi_input_pid, messages} ->
receive_messages(app_input_pid, messages)
loop(state)
{:set_state, state} ->
loop(state)
:stop ->
:ok
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment