Run this notebook

Use Livebook to open this notebook and explore new ideas.

It is easy to get started, on your machine or the cloud.

Click below to open and run it in your Livebook at .

(or change your Livebook location)

<!-- livebook:{"persist_outputs":true} --> # MIDIex notebook ```elixir Mix.install([{:midiex, "~> 0.6.3"}]) ``` <!-- livebook:{"output":true} --> ``` * Getting midiex (https://github.com/haubie/midiex.git) remote: Enumerating objects: 717, done. remote: Counting objects: 100% (174/174), done. remote: Compressing objects: 100% (87/87), done. remote: Total 717 (delta 79), reused 139 (delta 52), pack-reused 543 origin/HEAD set to main Resolving Hex dependencies... Resolution completed in 0.257s New: jason 1.4.1 rustler 0.26.0 toml 0.7.0 * Getting rustler (Hex package) * Getting jason (Hex package) * Getting toml (Hex package) ==> toml Compiling 10 files (.ex) Generated toml app ==> jason Compiling 10 files (.ex) Generated jason app ==> rustler Compiling 7 files (.ex) Generated rustler app ==> midiex Compiling 10 files (.ex) Compiling crate midiex in release mode (native/midiex) Compiling memchr v2.5.0 Compiling core-foundation-sys v0.8.3 Compiling libc v0.2.138 Compiling proc-macro2 v1.0.63 Compiling unicode-ident v1.0.5 Compiling coremidi-sys v3.1.0 Compiling quote v1.0.28 Compiling regex-syntax v0.6.28 Compiling void v1.0.2 Compiling heck v0.4.0 Compiling rustler v0.29.0 Compiling lazy_static v1.4.0 Compiling unreachable v1.0.0 Compiling block v0.1.6 Compiling bitflags v1.3.2 Compiling aho-corasick v0.7.20 Compiling regex v1.7.0 Compiling rustler_sys v2.3.0 Compiling core-foundation v0.9.3 Compiling coremidi v0.6.0 Compiling coremidi v0.7.0 Compiling midir v0.9.1 Compiling syn v2.0.22 Compiling rustler_codegen v0.29.0 Compiling midiex v0.1.0 (/Users/haubie/Library/Caches/mix/installs/elixir-1.15.2-erts-14.0.2/56c7aef4f3fb67cf9f7eb75d4a18b401/deps/midiex/native/midiex) Finished release [optimized] target(s) in 6.13s Generated midiex app ``` <!-- livebook:{"output":true} --> ``` :ok ``` ## Introduction ### Learning objectives This will get you started with Midiex. By the end of this Livebook you'll be able to: * **Find** and **connect** to MIDI ports on your system * **Create virtual ports** (on supported systems, like MacOS and Linux) * **Send** and **recieve** messages. ### Setup Just to make our code a bit more compact when experimenting with live-music coding, we'll alias the `Midiex.Message` module as `M`. Midiex function names have been kept compact as possible with live-music coding in mind. ```elixir alias Midiex.Listener alias Midiex.Message, as: M ``` <!-- livebook:{"output":true} --> ``` Midiex.Message ``` ## MIDI concepts Skip this section you're familiar with MIDI concepts and want to start playing with the library. At it's most basic, MIDI consists of: * **Ports**, which represent input or output connections to MIDI hardware or software. You can recieve MIDI messages from a MIDI input, or send MIDI messages to a MIDI output. * **Connections**, just like with all IO operations, you'll need to make a connection with a MIDI port to send or recieve messages to it. * **Messages**, which are usually music related, such switching a note on or off. <!-- livebook:{"break_markdown":true} --> ![](images/grokking_midi.png) ## Finding devices (ports) Note that on Apple Mac, you may wish to call `Midiex.hotplug()` first so that Midiex will be able to see devices plugged in or removed. ```elixir Midiex.hotplug() ``` <!-- livebook:{"output":true} --> ``` :ok ``` ### How many ports are there? ```elixir Midiex.port_count() ``` <!-- livebook:{"output":true} --> ``` %{input: 4, output: 3} ``` ### List devices (ports) ```elixir ports = Midiex.ports() ``` <!-- livebook:{"output":true} --> ``` [ %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 1", num: 0, port_ref: #Reference<0.34604515.3318349847.1170> }, %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 2", num: 1, port_ref: #Reference<0.34604515.3318349847.1171> }, %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 3", num: 2, port_ref: #Reference<0.34604515.3318349847.1172> }, %Midiex.MidiPort{ direction: :input, name: "My Out", num: 3, port_ref: #Reference<0.34604515.3318349847.1173> }, %Midiex.MidiPort{ direction: :output, name: "IAC Driver Bus 1", num: 0, port_ref: #Reference<0.34604515.3318349847.1174> }, %Midiex.MidiPort{ direction: :output, name: "IAC Driver Bus 2", num: 1, port_ref: #Reference<0.34604515.3318349847.1175> }, %Midiex.MidiPort{ direction: :output, name: "IAC Driver Bus 3", num: 2, port_ref: #Reference<0.34604515.3318349847.1176> } ] ``` ### Filter to show input or output ports ```elixir Midiex.ports(:input) ``` <!-- livebook:{"output":true} --> ``` [ %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 1", num: 0, port_ref: #Reference<0.34604515.3318349847.1177> }, %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 2", num: 1, port_ref: #Reference<0.34604515.3318349847.1178> }, %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 3", num: 2, port_ref: #Reference<0.34604515.3318349847.1179> }, %Midiex.MidiPort{ direction: :input, name: "My Out", num: 3, port_ref: #Reference<0.34604515.3318349847.1180> } ] ``` ```elixir Midiex.ports(:output) ``` <!-- livebook:{"output":true} --> ``` [ %Midiex.MidiPort{ direction: :output, name: "IAC Driver Bus 1", num: 0, port_ref: #Reference<0.34604515.3318349847.1188> }, %Midiex.MidiPort{ direction: :output, name: "IAC Driver Bus 2", num: 1, port_ref: #Reference<0.34604515.3318349847.1189> }, %Midiex.MidiPort{ direction: :output, name: "IAC Driver Bus 3", num: 2, port_ref: #Reference<0.34604515.3318349847.1190> } ] ``` ### Filtering ports by name You can include a regular expression as the first parameter to search for matching ports. For example, to get the output ports from any Arturia device plugged into your system, you could do the following: ```elixir Midiex.ports(~r/Arturia/, :output) ``` <!-- livebook:{"output":true} --> ``` [] ``` If you know the name of the port, you can pass it as a string as the first parameter: ```elixir Midiex.ports("IAC Driver Bus 1", :input) ``` <!-- livebook:{"output":true} --> ``` [ %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 1", num: 0, port_ref: #Reference<0.34604515.3318349847.1198> } ] ``` ## Connecting to output devices If you wanted to connect to the first Arturia output port on your system you could: ```elixir # Get the port out_port = Midiex.ports(~r/Arturia/, :output) |> List.first() ``` <!-- livebook:{"output":true} --> ``` nil ``` ```elixir # Make a connection out_conn = Midiex.open(out_port) ``` You can now send a message to the device via the output connection, for example: ```elixir Midiex.send_msg(out_conn, <<0x90, 60, 127>>) ``` <!-- livebook:{"output":true} --> ``` error: undefined variable "out_conn" livebook/midiex_notebook.livemd#cell:752gysgdtdthfmkq2ehlkt5iw5bnzkyw:1 ``` ## Virtual devices A virtual output creates an output connection you can send messages to, but to other devices on your system, it wll appear as a MIDI input connection they can consume. For example, you might have a software synth installed on your PC that can consume these MIDI messages. ```elixir virtual_conn = Midiex.create_virtual_output("My Virtual Connection") ``` <!-- livebook:{"output":true} --> ``` %Midiex.OutConn{ conn_ref: #Reference<0.34604515.3318349831.2664>, 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: ```elixir ports = Midiex.ports(:input) ``` <!-- livebook:{"output":true} --> ``` [ %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 1", num: 0, port_ref: #Reference<0.34604515.3318349847.1212> }, %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 2", num: 1, port_ref: #Reference<0.34604515.3318349847.1213> }, %Midiex.MidiPort{ direction: :input, name: "IAC Driver Bus 3", num: 2, port_ref: #Reference<0.34604515.3318349847.1214> }, %Midiex.MidiPort{ direction: :input, name: "My Out", num: 3, port_ref: #Reference<0.34604515.3318349847.1215> }, %Midiex.MidiPort{ direction: :input, name: "My Virtual Connection", num: 4, port_ref: #Reference<0.34604515.3318349847.1216> } ] ```
See source

Have you already installed Livebook?

If you already installed Livebook, you can configure the default Livebook location where you want to open notebooks.
Livebook up Checking status We can't reach this Livebook (but we saved your preference anyway)
Run notebook

Not yet? Install Livebook in just a minute

Livebook is open source, free, and ready to run anywhere.

Run on your machine

with Livebook Desktop

Run in the cloud

on select platforms

To run on Linux, Docker, embedded devices, or Elixir’s Mix, check our README.

PLATINUM SPONSORS
SPONSORS
Code navigation with go to definition of modules and functions Read More ×