spatialaudio / jackclient-python

🂻 JACK Audio Connection Kit (JACK) Client for Python :snake:
https://jackclient-python.readthedocs.io/
MIT License
132 stars 26 forks source link

Q: Alsa MIDI Connections #52

Closed mungewell closed 4 years ago

mungewell commented 6 years ago

Is it possible to control (make and break) the Alsa MIDI connections in the same way that the Jack MIDI connections can be made?

In QJackCtl these are on the third tab and remain persistent the app is quit - which makes me think that Jackd is handling them. jackclient_alsa_connection

I could receive the MIDI packets (with python-mido) and relay them, but I'm after a better (less latency) method.

mgeier commented 6 years ago

I guess if they are not listed in myclient.get_ports(), it's not possible. If somebody knows more, please correct me!

mungewell commented 6 years ago

I have discovered/confirmed that these connections are maintained within Alsa, and can be made/broken/listed with the 'aconnect' command.

simon@thevoid:~$ aconnect -l
client 0: 'System' [type=kernel]
    0 'Timer           '
    1 'Announce        '
    Connecting To: 128:0
client 14: 'Midi Through' [type=kernel]
    0 'Midi Through Port-0'
client 20: 'MPD218' [type=kernel,card=1]
    0 'MPD218 MIDI 1   '
    Connecting To: 129:0
client 129: 'FLUID Synth (1418)' [type=user,pid=1418]
    0 'Synth input port (1418:0)'
    Connected From: 20:0

I have not (yet) found a Python binding that will enable me to control them :-(

mgeier commented 6 years ago

OK, that's good to know!

You can simply use subprocess.run() to call aconnect, e.g.:

import subprocess
subprocess.run(['aconnect', '-d', 'MPD:0', 'FLUID:0'])

It looks like you can use either the (case-insensitive) client name (or just the first few characters thereof) or the client numbers.

Alternatively, you can try http://pp.com.mx/python/alsaseq/project.html, but I didn't test this.

mungewell commented 6 years ago

It looks like 'alsaseq' mentioned above only allows connections to be made with it's own port, thus not allowing arbitrary connections between 2 third parties. I didn't try it either ;-) https://github.com/ppaez/alsaseq/blob/master/alsaseq.c#L310

I did find a solution (at least for python2), albeit it a massively under documented solution. The 'python-pyalsa' package bundled with Ubuntu (and presumable others) is from the Alsa team themselves. It is NOT the same as many other python-alsa(ish) projects.....

Looking at the source code, there is a class which allows control in the same manner as 'aconnect'. Changes made in python are reflected in 'aconnect' and vice-versa.

Note sure whether this is the best solution for Python3, but it is at least a working reference. [edit] https://www.spinics.net/lists/alsa-devel/msg73981.html

$ python 
Python 2.7.15rc1 (default, Apr 15 2018, 21:51:34) 
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyalsa import alsaseq
>>> a = alsaseq.Sequencer()
>>> a.connection_list()
[('System', 0, [('Timer', 0, ([], [])), ('Announce', 1, ([], []))]), ('Midi Through', 14, [('Midi Through Port-0', 0, ([], []))]), ('pyalsa-2588', 128, []), ('FLUID Synth (2538)', 129, [('Synth input port (2538:0)', 0, ([], []))])]
>>> a.connect_ports((0,0),(129,0))
>>> a.connection_list()
[('System', 0, [('Timer', 0, ([(129, 0, {'queue': 0, 'exclusive': 0, 'time_update': 0, 'time_real': 0})], [])), ('Announce', 1, ([], []))]), ('Midi Through', 14, [('Midi Through Port-0', 0, ([], []))]), ('pyalsa-2588', 128, []), ('FLUID Synth (2538)', 129, [('Synth input port (2538:0)', 0, ([], [(0, 0, {'queue': 0, 'exclusive': 0, 'time_update': 0, 'time_real': 0})]))])]
>>> a.get_connect_info((0,0), (129,0))
{'queue': 0, 'exclusive': 0, 'time_update': 0, 'time_real': 0}
>>> a.disconnect_ports((0,0),(129,0))

[disclaimer: looked at this during lunch hour at work, didn't actually confirm that MIDI is routed properly]

mungewell commented 6 years ago

I should have looked at the Network chart for 'alsaseq', seems that @zelenikotao solving this problem a year ago but the code was never merged with main repo. This will allow the making/breaking/listing between 2 third party apps.

So I've issued a pull request: https://github.com/ppaez/alsaseq/pull/11

$ python3
Python 3.6.5 (default, Apr  1 2018, 05:46:30)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import alsaseq
>>> alsaseq.client("Simple", 1, 1, False)
>>> alsaseq.connect(20,0, 129,0)
0
>>> print("Midi now routed...")
Midi now routed...