View Source MIDIex notebook
Mix.install([{:midiex, path: "/Users/haubie/Development/midiex"}])
==> midiex
Compiling 1 file (.ex)
Compiling crate midiex in release mode (native/midiex)
Compiling midiex v0.1.0 (/Users/haubie/Development/midiex/native/midiex)
Finished release [optimized] target(s) in 0.55s
:ok
setup
Setup
finding-devices-ports
Finding devices (ports)
how-many-ports-are-there
How many ports are there?
Midiex.port_count()
%{input: 4, output: 4}
list-devices-ports
List devices (ports)
ports = Midiex.ports()
[
%Midiex.MidiPort{
direction: :input,
name: "IAC Driver Bus 1",
num: 0,
port_ref: #Reference<0.522475107.1026162712.215786>
},
%Midiex.MidiPort{
direction: :input,
name: "Arturia MicroFreak",
num: 1,
port_ref: #Reference<0.522475107.1026162712.215787>
},
%Midiex.MidiPort{
direction: :input,
name: "KeyStep Pro",
num: 2,
port_ref: #Reference<0.522475107.1026162712.215788>
},
%Midiex.MidiPort{
direction: :input,
name: "MiniFuse 2",
num: 3,
port_ref: #Reference<0.522475107.1026162712.215789>
},
%Midiex.MidiPort{
direction: :output,
name: "IAC Driver Bus 1",
num: 0,
port_ref: #Reference<0.522475107.1026162712.215790>
},
%Midiex.MidiPort{
direction: :output,
name: "Arturia MicroFreak",
num: 1,
port_ref: #Reference<0.522475107.1026162712.215791>
},
%Midiex.MidiPort{
direction: :output,
name: "KeyStep Pro",
num: 2,
port_ref: #Reference<0.522475107.1026162712.215792>
},
%Midiex.MidiPort{
direction: :output,
name: "MiniFuse 2",
num: 3,
port_ref: #Reference<0.522475107.1026162712.215793>
}
]
filter-to-show-input-or-output-ports
Filter to show input or output ports
Midiex.ports(:output)
[
%Midiex.MidiPort{
direction: :output,
name: "IAC Driver Bus 1",
num: 0,
port_ref: #Reference<0.522475107.1026162712.215798>
},
%Midiex.MidiPort{
direction: :output,
name: "Arturia MicroFreak",
num: 1,
port_ref: #Reference<0.522475107.1026162712.215799>
},
%Midiex.MidiPort{
direction: :output,
name: "KeyStep Pro",
num: 2,
port_ref: #Reference<0.522475107.1026162712.215800>
},
%Midiex.MidiPort{
direction: :output,
name: "MiniFuse 2",
num: 3,
port_ref: #Reference<0.522475107.1026162712.215801>
}
]
out_port = Midiex.ports("Arturia", :output) |> List.first()
%Midiex.MidiPort{
direction: :output,
name: "Arturia MicroFreak",
num: 1,
port_ref: #Reference<0.522475107.1026162712.215807>
}
out_conn = Midiex.open(out_port)
%Midiex.OutConn{
conn_ref: #Reference<0.522475107.1026162689.216660>,
name: "Arturia MicroFreak",
port_num: 1
}
Midiex.send_msg(out_conn, <<0x90, 60, 127>>)
%Midiex.OutConn{
conn_ref: #Reference<0.522475107.1026162689.216660>,
name: "Arturia MicroFreak",
port_num: 1
}
Midiex.ports(:input)
[
%Midiex.MidiPort{
direction: :input,
name: "IAC Driver Bus 1",
num: 0,
port_ref: #Reference<0.522475107.1026162712.215810>
},
%Midiex.MidiPort{
direction: :input,
name: "Arturia MicroFreak",
num: 1,
port_ref: #Reference<0.522475107.1026162712.215811>
},
%Midiex.MidiPort{
direction: :input,
name: "KeyStep Pro",
num: 2,
port_ref: #Reference<0.522475107.1026162712.215812>
},
%Midiex.MidiPort{
direction: :input,
name: "MiniFuse 2",
num: 3,
port_ref: #Reference<0.522475107.1026162712.215813>
}
]
filter-by-port-name
Filter by port name
Midiex.ports("IAC", :input)
[
%Midiex.MidiPort{
direction: :input,
name: "IAC Driver Bus 1",
num: 0,
port_ref: #Reference<0.522475107.1026162712.215818>
}
]
virtual-devices
Virtual devices
virtual_conn = Midiex.create_virtual_output("My Virtual Connection")
%Midiex.OutConn{
conn_ref: #Reference<0.522475107.1026162689.216746>,
name: "My Virtual Connection",
port_num: 4
}
Note that although you've created this virtual output, on your system it will appear as an import port to be discoverable by other MIDI software or devices.
If you call Midiex.ports/1
you'll see it as an input:
ports = Midiex.ports(:input)
[
%Midiex.MidiPort{
direction: :input,
name: "IAC Driver Bus 1",
num: 0,
port_ref: #Reference<0.522475107.1026162712.215826>
},
%Midiex.MidiPort{
direction: :input,
name: "Arturia MicroFreak",
num: 1,
port_ref: #Reference<0.522475107.1026162712.215827>
},
%Midiex.MidiPort{
direction: :input,
name: "KeyStep Pro",
num: 2,
port_ref: #Reference<0.522475107.1026162712.215828>
},
%Midiex.MidiPort{
direction: :input,
name: "MiniFuse 2",
num: 3,
port_ref: #Reference<0.522475107.1026162712.215829>
},
%Midiex.MidiPort{
direction: :input,
name: "My Virtual Connection",
num: 4,
port_ref: #Reference<0.522475107.1026162712.215830>
}
]
make-a-connection-to-a-device
Make a connection to a device
connect-to-an-output-device-and-send-a-message
Connect to an output device and send a message
out_conn =
Midiex.ports("IAC", :output)
|> List.first()
|> Midiex.open()
%Midiex.OutConn{
conn_ref: #Reference<0.522475107.1026162689.216766>,
name: "IAC Driver Bus 1",
port_num: 0
}
Midiex.Backend.get_subscribed_ports()
[]
Midiex.Backend.listen(Midiex.ports(:input) |> Enum.at(2))
[
%Midiex.MidiPort{
direction: :input,
name: "KeyStep Pro",
num: 2,
port_ref: #Reference<0.522475107.1026162712.215846>
}
]
in_port = Midiex.ports("Key", :input) |> List.first()
%Midiex.MidiPort{
direction: :input,
name: "KeyStep Pro",
num: 2,
port_ref: #Reference<0.522475107.1026162712.215855>
}
1..10//1
|> Enum.map(fn i ->
:timer.sleep(1000)
Midiex.Backend.test(in_port)
end)
warning: variable "i" is unused (if the variable is not meant to be used, prefix it with an underscore)
livebook/midiex_notebook.livemd#cell:7euaccszbergu2jit2isskr7ejpvc65q:2
[:ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok]
# Midiex.Backend.clear_subscribed_ports()
nil
connect-and-listen-to-an-input-device
Connect and listen to an input device
defmodule MyMidiServer do
use GenServer
@impl true
def init(state \\ []) do
IO.inspect(state, label: "INIT")
{:ok, state}
end
@impl true
def handle_info(msg, state) do
case msg do
msg ->
IO.inspect(msg, label: "FROM RUST")
msg
_ ->
msg
end
{:noreply, state}
end
def listen_to(device_name \\ "IAC Driver") do
Midiex.ports()
|> Midiex.filter_port_name_contains(device_name, direction: :input)
|> List.first()
|> Midiex.listen()
end
def listen(pid, device_name) do
GenServer.cast(pid, {:listen, device_name})
end
@impl true
def handle_cast({:listen, device_name}, state) do
listen_to(device_name)
{:noreply, state}
end
def subscribe(pid) do
GenServer.cast(pid, :subscribe)
end
@impl true
def handle_cast(:subscribe, state) do
Midiex.subscribe()
{:noreply, state}
end
end
warning: clauses with the same name and arity (number of arguments) should be grouped together, "def handle_cast/2" was previously defined (livebook/midiex_notebook.livemd#cell:7rfguhfubcggnj6q6hoiiqg7lbqbjlab:36)
livebook/midiex_notebook.livemd#cell:7rfguhfubcggnj6q6hoiiqg7lbqbjlab:46
warning: this clause cannot match because a previous clause at line 13 always matches
livebook/midiex_notebook.livemd#cell:7rfguhfubcggnj6q6hoiiqg7lbqbjlab:17
warning: Midiex.filter_port_name_contains/3 is undefined or private
livebook/midiex_notebook.livemd#cell:7rfguhfubcggnj6q6hoiiqg7lbqbjlab:26: MyMidiServer.listen_to/1
{:module, MyMidiServer, <<70, 79, 82, 49, 0, 0, 21, ...>>, {:handle_cast, 2}}
{:ok, pid} = GenServer.start_link(MyMidiServer, [])
INIT: []
{:ok, #PID<0.264.0>}
# MyMidiServer.listen(pid, "KeyStep")
# MyMidiServer.listen(pid, "MicroFreak")
nil
MyMidiServer.subscribe(pid)
:ok
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
Midiex.Backend.listen(Midiex.ports(:input) |> Enum.at(1))
[
%Midiex.MidiPort{
direction: :input,
name: "Arturia MicroFreak",
num: 1,
port_ref: #Reference<0.522475107.1026162712.215863>
},
%Midiex.MidiPort{
direction: :input,
name: "KeyStep Pro",
num: 2,
port_ref: #Reference<0.522475107.1026162712.215846>
}
]
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
FROM RUST: %{"port_name" => "Arturia MicroFreak", "port_num" => 1}
FROM RUST: %{"port_name" => "KeyStep Pro", "port_num" => 2}
Midiex.Backend.get_subscribed_ports()
[
%Midiex.MidiPort{
direction: :input,
name: "IAC Driver Bus 1",
num: 0,
port_ref: #Reference<0.2084832073.4240834584.3914>
},
%Midiex.MidiPort{
direction: :input,
name: "My Virtual Connection",
num: 1,
port_ref: #Reference<0.2084832073.4240834584.3918>
}
]
FROM RUST: %{"port_name" => "IAC Driver Bus 1", "port_num" => 0}
FROM RUST: %{"port_name" => "My Virtual Connection", "port_num" => 1}
FROM RUST: %{"port_name" => "IAC Driver Bus 1", "port_num" => 0}
FROM RUST: %{"port_name" => "My Virtual Connection", "port_num" => 1}
FROM RUST: %{"port_name" => "IAC Driver Bus 1", "port_num" => 0}
FROM RUST: %{"port_name" => "My Virtual Connection", "port_num" => 1}
Midiex.Backend.clear_subscribed_ports()
[]