Un envoltorio de elixir para la biblioteca Rtmidi. Inspirado en parte por Python-Rtmidi.
ADVERTENCIA: Esta biblioteca se considera experimental/prealfa hasta que se abordan algunos de los problemas a continuación.
Considere verificar la pestaña "Problemas" si está buscando ayudar.
Esta biblioteca funciona como es, pero no soy un programador C ++. Cualquier contribución es bienvenida, pero la ayuda en estas áreas específicas sería de gran ayuda:
C ++
src/ex_rtmidi_{output,input}.cpp podría utilizar mucho mejor OOP y plantillas para reducir la duplicación de códigoinput_callback y attach_listener en src/ex_rtmidi_input.cpp necesita un buen aspecto. Nuevamente, un refactor de antemano es preferibledetach_listener no debe imprimir un error si se llama sin un oyenteElixir
init para entradas/salidas lleva más tiempo de lo recomendado para un NIF. Ver lib/ex_rtmidi/{output,input}.ex comentariosopenVirtualPort de RtmidiMix.Tasks.Compile.Rtmidi fuera de mix.exs . Ver comentario en mix.exsGeneral
C ++ es un lenguaje OO, Elixir no lo es. Me desgarraron si expresar las cosas de manera más funcional o más en línea con las convenciones OO. Al final se eligió un enfoque más funcional.
Para crear una instancia de RTMIDI, se llama a un método init con un identificador de instancia. En C ++, la instancia se almacena como un valor en un mapa donde el identificador es la clave. Las llamadas futuras a los métodos de instancia de RTMIDI requieren que se aprobe el identificador para saber a qué instancia apuntar.
Los NIF son principalmente una construcción de Erlang, por lo que verá que el envoltorio de elixir hace mucha converstion hacia y desde las charlistas. Esto se debe a que las cadenas en Erlang son charlistas en elixir, por lo tanto, los métodos de cadena de NIF realmente toman y devuelven a Charlists en lugar de String.t() .
Los oyentes en los puertos de entrada pasados a C ++ como PID. Al recibir un mensaje, el NIF analiza y pasa el mensaje Async al PID especificado.
Hasta que se resuelvan algunos de los problemas más apremiantes de C ++, no quiero promover esta biblioteca para uso público. Hasta entonces, tendrás que obtenerlo de GitHub:
def deps do
[
{ :ex_rtmidi , git: "https://github.com/kieraneglin/ex_rtmidi" }
]
end Actualmente, esta biblioteca adopta un enfoque más básico para manejar mensajes de lo que puede esperar. Puede obtener valor de un pequeño envoltorio alrededor de enviar y analizar mensajes adaptados a su caso de uso.
He esbozado algunos casos de uso básicos, pero debería ver lib/ex_rtmidi/{output,input}.ex para una documentación más profunda.
alias ExRtmidi.Output
{ :ok , instance } = Output . init ( :my_instance_name ) # Instance name can be whatever you want - it's unrelated to available MIDI devices
Output . get_port_count ( instance )
# iex> {:ok, 2}
Output . get_ports ( instance )
# iex> {:ok, ["IAC Midi", "Dummy MIDI"]}
Output . open_port ( instance , 0 ) # Or `Output.open_port(instance, "IAC Midi")`
# iex> :ok
Output . send_message ( instance , [ 0x90 , 60 , 100 ] )
# iex> :ok
Output . close_port ( instance )
# iex> :okHay un envoltorio para los mensajes MIDI que mejora la experiencia de crear mensajes. Esto es principalmente para la salida y no se ha portado para deconstruir mensajes entrantes (consulte la sección "Ayuda necesaria").
Para obtener una lista completa de mensajes, consulte lib/ex_rtmidi/message/spec.ex .
alias ExRtmidi.Output
alias ExRtmidi.Message
# Assume `init` has been run and a port has been opened as in the instance above
message = Message . compose ( :note_on , channel: 0 , note: 60 , velocity: 100 )
Output . send_message ( instance , message ) # In midi_input_server.ex
defmodule MidiInputServer do
use GenServer
def init ( state \ [ ] ) do
{ :ok , state }
end
def handle_info ( { :midi_input , midi_message } , state ) do
IO . inspect ( midi_message )
{ :noreply , state }
end
end
# In another file
alias ExRtmidi.Input
# Much of setup including init, listing ports, and opening a port is the same as in the Output example above.
# Setup will be omitted for brevity. Assume we have an instance at our disposal.
{ :ok , midi_listener_pid } = GenServer . start_link ( MidiInputServer , [ ] )
# You should attach the listener before opening the port to ensure no messages get missed
Input . attach_listener ( instance , midi_listener_pid )
# iex> :ok
Input . open_port ( instance )
# iex> :ok
# Messages will be handled from this point on
# When you're done, be sure to detatch the listener before closing the port
Input . detatch_listener ( instance )
# iex> :ok
Input . close_port ( instance )
# iex> :ok Copyright 2021
El permiso se otorga, de forma gratuita, a cualquier persona que obtenga una copia de este software y archivos de documentación asociados (el "software"), para tratar en el software sin restricción, incluidos los derechos de los derechos de usar, copiar, modificar, fusionar, publicar, distribuir, sublicense y/o vender copias del software, y para permitir que las personas a quienes se les proporciona el software para hacer, sujeto a las siguientes condiciones: las siguientes condiciones: las siguientes condiciones: las siguientes condiciones:
El aviso de derechos de autor anterior y este aviso de permiso se incluirán en todas las copias o porciones sustanciales del software.
El software se proporciona "tal cual", sin garantía de ningún tipo, expresa o implícita, incluidas, entre otros, las garantías de comerciabilidad, idoneidad para un propósito particular y no infracción. En ningún caso los autores o titulares de derechos de autor serán responsables de cualquier reclamo, daños u otra responsabilidad, ya sea en una acción de contrato, agravio o de otra manera, que surge, de o en relación con el software o el uso u otros tratos en el software.