Un wrapper Elixir pour la bibliothèque RTMIDI. Inspiré en partie par Python-Rtmidi.
AVERTISSEMENT: Cette bibliothèque est considérée comme expérimentale / pré-alpha jusqu'à ce que certains des problèmes ci-dessous soient résolus.
Envisagez de vérifier l'onglet "Problèmes" si vous cherchez à vous aider.
Cette bibliothèque fonctionne tel quel, mais je ne suis pas un programmeur C ++. Toutes les contributions sont les bienvenues, mais l'aide dans ces domaines spécifiques irait très loin:
C ++
src/ex_rtmidi_{output,input}.cpp pourrait bien mieux utiliser la POO et les modèles pour réduire la duplication du codeinput_callback et attach_listener dans src/ex_rtmidi_input.cpp a besoin d'un bon look. Encore une fois, un refactor à l'avance est préférabledetach_listener ne doit pas imprimer une erreur si elle est appelée sans auditeurÉlixir
init pour les entrées / sorties prend plus de temps que celle recommandée pour un NIF. Voir lib/ex_rtmidi/{output,input}.exopenVirtualPort de RTMIDIMix.Tasks.Compile.Rtmidi de mix.exs . Voir commentaire dans mix.exsGénéral
C ++ est une langue OO, l'élixir ne l'est pas. Je devais exprimer des choses plus fonctionnellement ou plus conformes aux conventions OO. En fin de compte, une approche plus fonctionnelle a été choisie.
Pour créer une instance RTMIDI, une méthode init est appelée avec un identifiant d'instance. En C ++, l'instance est stockée comme une valeur sur une carte où l'identifiant est la clé. Les appels futurs vers les méthodes d'instance RTMIDI nécessitent que l'identifiant soit passé afin de savoir quelle instance cibler.
Les NIF sont principalement une construction Erlang, vous verrez donc que l'emballage Elixir fait beaucoup de converstion vers et depuis Charlist. En effet, les chaînes dans Erlang sont des charlistes dans Elixir, donc les méthodes de chaîne NIF prennent et renvoient des charlistes au lieu de String.t() .
Écouteurs sur les ports d'entrée tels qu'ils sont passés à C ++ en tant que PID. À la réception d'un message, le NIF analyse et transmet le message asynchronisé au PID spécifié.
Jusqu'à ce que certains des problèmes C ++ les plus pressants soient résolus, je ne veux pas promouvoir cette bibliothèque à usage public. Jusque-là, vous devrez l'obtenir de GitHub:
def deps do
[
{ :ex_rtmidi , git: "https://github.com/kieraneglin/ex_rtmidi" }
]
end Actuellement, cette bibliothèque adopte une approche plus nue pour gérer les messages que vous ne le pensez. Vous pouvez obtenir de la valeur d'un petit wrapper autour de l'envoi et des messages d'analyse adaptés à votre cas d'utilisation.
J'ai décrit certains cas d'utilisation de base, mais vous devriez voir lib/ex_rtmidi/{output,input}.ex pour une documentation plus approfondie.
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> :okIl existe un wrapper pour les messages MIDI qui améliore l'expérience de la création de messages. Ceci est principalement pour la sortie et n'a pas été porté pour déconstruire les messages entrants (voir la section "Aide nécessaire").
Pour une liste complète des messages, voir 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
L'autorisation est accordée gratuitement à toute personne qui obtient une copie de ce logiciel et des fichiers de documentation associés (le "logiciel"), pour traiter le logiciel sans restriction, y compris sans limiter les droits d'utilisation, de copie, de modification, de fusion, de publication, de distribution, de sublince et / ou de vendre des copies des conditions suivantes.
L'avis de droit d'auteur ci-dessus et le présent avis d'autorisation sont inclus dans toutes les copies ou des parties substantielles du logiciel.
Le logiciel est fourni "tel quel", sans garantie d'aucune sorte, express ou implicite, y compris, mais sans s'y limiter, les garanties de qualité marchande, d'adéquation à un usage particulier et de non-contrefaçon. En aucun cas, les auteurs ou les détenteurs de droits d'auteur ne seront pas responsables de toute réclamation, dommage ou autre responsabilité, que ce soit dans une action de contrat, de délit ou autre, découlant de, hors du logiciel ou de l'utilisation ou d'autres relations dans le logiciel.