Um invólucro elixir da biblioteca RTMIDI. Inspirado em parte por Python-Rtmidi.
AVISO: Esta biblioteca é considerada experimental/pré-alfa até que alguns dos problemas abaixo sejam abordados.
Considere verificar a guia "Problemas" se você estiver procurando ajudar.
Esta biblioteca funciona como é, mas não sou um programador C ++. Quaisquer contribuições são bem -vindas, mas a ajuda nessas áreas específicas percorreria um longo caminho:
C ++
src/ex_rtmidi_{output,input}.cpp poderia muito melhor utilizar OOP e modelos para reduzir a duplicação de códigoinput_callback e attach_listener em src/ex_rtmidi_input.cpp precisam de uma boa aparência. Novamente, é preferível um refator de antemãodetach_listener não deve imprimir um erro se chamado sem um ouvinteElixir
init para entradas/saídas leva mais tempo do que o recomendado para um NIF. Consulte lib/ex_rtmidi/{output,input}.ex ComentáriosopenVirtualPort da RTMIDIMix.Tasks.Compile.Rtmidi fora de mix.exs . Veja o comentário no mix.exsEm geral
C ++ é uma linguagem OO, o elixir não é. Fiquei dividido em expressar as coisas de maneira mais funcional ou mais alinhada com as convenções OO. No final, uma abordagem mais funcional foi escolhida.
Para criar uma instância RTMIDI, um método init é chamado com um identificador de instância. Em C ++, a instância é armazenada como um valor em um mapa em que o identificador é a chave. As chamadas futuras para os métodos de instância RTMIDI exigem que o identificador seja aprovado para saber qual instância segmentar.
Os NIFs são principalmente um construto Erlang, então você verá que o invólucro Elixir faz muita conversação de e para os charlistas. Isso ocorre porque as cordas em Erlang são charlists no elixir; portanto, os métodos de string nif realmente pegam e retornam charlists em vez de String.t() .
Os ouvintes nas portas de entrada passadas para C ++ como um PID. Após o recebimento de uma mensagem, o NIF passa e passa a mensagem assíncrona para o PID especificado.
Até que alguns dos problemas mais prementes do C ++ sejam resolvidos, não quero promover esta biblioteca para uso público. Até lá, você terá que obtê -lo do Github:
def deps do
[
{ :ex_rtmidi , git: "https://github.com/kieraneglin/ex_rtmidi" }
]
end Atualmente, essa biblioteca adota uma abordagem mais nua para lidar com mensagens do que você poderia esperar. Você pode obter valor de um pequeno invólucro em torno de enviar e analisar mensagens adaptadas ao seu caso de uso.
Descrevi alguns casos de uso básico, mas você deve ver lib/ex_rtmidi/{output,input}.ex para uma documentação mais aprofundada.
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> :okHá um invólucro para mensagens MIDI que melhora a experiência de criar mensagens. Isso é principalmente para saída e não foi portado para desconstruir mensagens recebidas (consulte a seção "Ajuda necessária").
Para obter uma lista completa de mensagens, 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
A permissão é concedida, gratuita, a qualquer pessoa que obtenha uma cópia deste software e arquivos de documentação associados (o "software"), para lidar com o software sem restrição, inclusive sem limitação os direitos de usar, copiar, modificar, mesclar, publicar, distribuir, mobilizar o software e/ou vender cópias do software e permitir que as pessoas a quem
O aviso de direitos autorais acima e este aviso de permissão devem ser incluídos em todas as cópias ou em partes substanciais do software.
O software é fornecido "como está", sem garantia de qualquer tipo, expresso ou implícito, incluindo, entre outros, as garantias de comercialização, aptidão para uma finalidade específica e não innoculação. Em nenhum caso os autores ou detentores de direitos autorais serão responsáveis por qualquer reclamação, danos ou outro passivo, seja em uma ação de contrato, delito ou não, decorrente de, fora ou em conexão com o software ou o uso ou outras negociações no software.