# `Midiex.Notifier`
[🔗](https://github.com/haubie/midiex/blob/main/lib/midiex/notifier.ex#L1)

GenServer for subscribing and responding to MIDI notifications on supported systems.

This is currently implemented for Mac only.

## How this works
On Mac, a callback function needs to be created to specially handle MIDI notification messages, such as when a device has been physically plugged (`:added`) or unplugged (`:removed`). This callback is implemented in the Rust side of this library using [coremidi](https://chris-zen.github.io/coremidi/coremidi/struct.Client.html#method.new_with_notifications).

The notifications will be delivered on MacOS to a Rust thread with the specific 'run loop' (using [CFRunLoop from the core_foundation](https://docs.rs/core-foundation/latest/core_foundation/runloop/struct.CFRunLoop.html) Rust library) that was created when the `Midiex.notifications/0` function was first called. This function is called automatically when this GenServer is started.

Any (`:added`) or (`:removed`) notifications will be sent to this GenServer from the Rust thread.

The `Midiex.Notifier` GenServer then forwards these notifications to any handler functions added in with the `add_handler/2` function or passed to it through the `start/1` function.

## Example
```
# Start the Notifier GenServer
{:ok, pid} = Midiex.Notifier.start_link()

# Add a simple handler callback function. This will just inspect the notification.
Midiex.Notifier.add_handler(pid, fn msg -> IO.inspect(msg) end)

# KeyStep Pro keyboard has been hot-plugged into the Mac:
%Midiex.MidiNotification{
  notification_type: :added,
  parent_name: "KeyStep Pro",
  parent_id: 1384647386,
  parent_type: :entity,
  name: "KeyStep Pro",
  native_id: 493507367,
  direction: :input
}
%Midiex.MidiNotification{
  notification_type: :added,
  parent_name: "KeyStep Pro",
  parent_id: 1384647386,
  parent_type: :entity,
  name: "KeyStep Pro",
  native_id: 2688501783,
  direction: :output
}

# KeyStep Pro keyboard has been unplugged from the Mac:
%Midiex.MidiNotification{
  notification_type: :removed,
  parent_name: "KeyStep Pro",
  parent_id: 1384647386,
  parent_type: :entity,
  name: "KeyStep Pro",
  native_id: 493507367,
  direction: :input
}
%Midiex.MidiNotification{
  notification_type: :removed,
  parent_name: "KeyStep Pro",
  parent_id: 1384647386,
  parent_type: :entity,
  name: "KeyStep Pro",
  native_id: 2688501783,
  direction: :output
}
```

# `add_handler`

```elixir
@spec add_handler(pid(), function() | [function()]) :: :ok
```

Add one or more callback function(s) which will recieve and handle MIDI notifications.

The first parameter of the callback function will be used to recieve notification messages.

## Example
```
# Start the Notifier GenServer
{:ok, pid} = Midiex.Notifier.start_link()

# Add a simple handler callback function. This will just inspect the notification.
Midiex.Notifier.add_handler(pid, fn msg -> IO.inspect(msg) end)
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `clear_handlers`

Clears all handlers.

# `get_state`

```elixir
@spec get_state(pid()) :: %Midiex.Listener{callback: term(), port: term()}
```

Gets the servers state, returns `%Midiex.Listener{}` struct.

# `new`

Creates a new %Midiex.Notifier{} 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:
- `: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. See `add_handler/2` for an example.

# `start_link`

```elixir
@spec start_link(keyword()) :: :ignore | {:error, any()} | {:ok, pid()}
```

Start the Midiex.Notifier GenServer.

Takes an optional keyword list as the first parameter which can be used to populate individual %Midiex.Notifier{} struct keys. See `new/1` for informaton.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
