View Source Midiex.Listener (Midiex v0.5.3)
GenServer for subscribing to MIDI input ports and responding to the MIDI messages (Midiex.MidiMessage
) received.
how-this-works
How this works
This GenServer works by:
Subscribing to one or more MIDI input ports (using
Midiex.subscribe/1
). For each MIDI input port,Midiex.subscribe/1
will create a new OS thread (in Rust) which establishes a connection to the port and listens to messages. Incoming messages are then forwarded to the calling Elixir process (in this case, theMidiex.Listener
process.)A subscription can be established on the
start_link/1
orsubscribe/2
functions, e.g.:# Get the first MIDI input port input_port = Midiex.ports(:input) |> List.first() # Start a lister for this MIDI input port {:ok, listener} = Midiex.Listener.start_link(port: input_port)
Receieves MIDI messages in the form of a
Midiex.MidiMessage
struct, and passes it onto one or more Elixir handler functions. The handler takes one parameter representing the MIDI message, e.g.:# Add a simple message handler which inspects each message received: Midiex.Listener.add_handler(listener, fn (midi_msg) -> IO.inspect(midi_msg) end)
example
Example
alias Midiex.Listener
# Get the first MIDI input port
input_port = Midiex.ports(:input) |> List.first()
# Start a lister for this MIDI input port
{:ok, listner} = Listener.start_link(port: input_port)
# Create a handler than inspects the MIDI messages received:
my_msg_hander = fn (midi_msg) -> IO.inspect(midi_msg, label: "MIDI message") end
Listener.add_handler(listener, &my_msg_hander/1)
# Stop listening to the input port
Listener.unsubscribe(listner, input_port)
Link to this section Summary
Functions
Add one or more callback function(s) which will recieve and handle MIDI messages.
Returns a specification to start this module under a supervisor.
Gets the servers state, returns %Midiex.Listener{}
struct.
Creates a new %Midiex.Server{} struct.
Start the Midiex.Server GenServer.
Subscribe to one or more MIDI input ports.
Stops listening to the MIDI input port by unsubscribing to it.
Link to this section Functions
Add one or more callback function(s) which will recieve and handle MIDI messages.
A single callback function or multiple callback functions can be provided in a list.
example
Example
# Start your Listener process
{:ok, listener} = Listener.start_link(port: input_port)
# Add a single handler
Listener.add_handler(listener, fn msg -> IO.inspect msg, label: "Inspecting msg" end)
# Add multiple handlers in a list
Listener.add_handler(
listener,
[
fn msg -> IO.inspect msg, label: "Msg handler 1" end,
fn msg -> IO.inspect msg, label: "Msg handler 1" end,
]
)
# If you've defined your hander function in a module function, pass it the usual way:
Listener.add_handler(listener, &MyModule.function_name/1)
Returns a specification to start this module under a supervisor.
See Supervisor
.
Gets the servers state, returns %Midiex.Listener{}
struct.
Creates a new %Midiex.Server{} struct.
Takes an optional keyword list as the first parameter which can be used to populate individual struct keys.
The struct holds the following key-values:
:port
which holds a list of MIDI input ports to listen to. These can be device ports%Midiex.MidiPort{direction: :input}
or virtual ports%Midiex.VirtualMidiPort{}
:callback
which holds a list of functions called when a message is received for an input port. The callback must be of single arity and take it's first parameter a message. Seeadd_handler/2
for an example.
Start the Midiex.Server GenServer.
Takes an optional keyword list as the first parameter which can be used to populate individual %Midiex.Listener{} struct keys. See new/1
for informaton.
examples
Examples
# Start with no options
{:ok, listener} = Midiex.Listener.start_link()
# Start, already passing the first available input port to listen to
first_port = Midiex.ports(:input) |> List.first()
{:ok, listener} = Midiex.Listener.start_link(ports: first_port)
# Start, already passing a list of all input ports available to listen to
{:ok, listener} = Midiex.Listener.start_link(ports: Midiex.ports(:input))
@spec subscribe( pid(), %Midiex.MidiPort{ direction: :input, name: term(), num: term(), port_ref: term() } | %Midiex.VirtualMidiPort{direction: term(), name: term(), num: term()} | [ %Midiex.MidiPort{ direction: :input, name: term(), num: term(), port_ref: term() } | %Midiex.VirtualMidiPort{direction: term(), name: term(), num: term()} ] ) :: :ok
Subscribe to one or more MIDI input ports.
This accepts both ports listed on your device %Midiex.MidiPort{direction: :input}
and virtual ports %Midiex.VirtualMidiPort{}
you've created.
It accepts as it's second parameter either:
- a single MIDI input port
- a list of MIDI input ports
:all
atom which will stop all MIDI input ports subscribed to.
example
Example
# Subscribe to the input port of the Arturia KeyStep Pro keyboard
keystep_in_port = Midiex.port("KeyStep Pro", :input)
# Returns a list with matching port names, in this case:
[
%Midiex.MidiPort{
direction: :input,
name: "KeyStep Pro",
num: 2,
port_ref: #Reference<0.3139841870.4103995416.58432>
}
]
# Create and start a listener process
{:ok, keyboard} = Midiex.Listener.start_link()
# Listen to MIDI messages from the keyboard
Midiex.Listener.subscribe(keyboard, keystep_in_port)
# Any keys you push on the keyboard will be listened to. Add one or more handlers with Midiex.Listener.add_handler/2 to process messages.
@spec unsubscribe( pid(), %Midiex.MidiPort{ direction: :input, name: term(), num: term(), port_ref: term() } | %Midiex.VirtualMidiPort{direction: term(), name: term(), num: term()} | [ %Midiex.MidiPort{ direction: :input, name: term(), num: term(), port_ref: term() } | %Midiex.VirtualMidiPort{direction: term(), name: term(), num: term()} ] | :all ) :: :ok
Stops listening to the MIDI input port by unsubscribing to it.
This accepts both ports listed on your device %Midiex.MidiPort{direction: :input}
and virtual ports %Midiex.VirtualMidiPort{}
you've created.
It accepts as it's second parameter either:
- a single MIDI input port
- a list of MIDI input ports
:all
atom which will stop all MIDI input ports subscribed to.
Important
This stops the Rust OS thread from sending messages from that MIDI input port. If other Elixir processes have also subscribed to that port, they will also stop recieving messages.