Hi all - I’ve been away from electronic music stuff for a while, but am back now.
I’ve reviewed all the discussion about amidiminder and looked back over my notes and come up with the following list of projects to enhance it. I’d appreciate your input and thoughts on which of these are important, and how to make it work for you.
saving state
Right now, if you reboot, any connections made outside of the amidiminder rules file aren’t restored. This would change that so that amidiminder is always writing the connections to a live file. If there’s a reboot, the rules file & the live file would both be restored, so you should end up in exactly the same connection state once all the MIDI devices return.
aconnect functionality
The aconnect command uses a different syntax for making connections, and has a somewhat verbose and hard to read output for listing. I propose to add connecting (and disconnecting) connections as command line options to amidiminder and a list option which produces easier to read (and use) output.
maturity
There are a number of things to make the project polished:
a man page.
default location of the rules file so it doesn’t need to be specified (this has tripped many folks up)
explicit daemon mode command flag
ensuring that the service is always set up in Patchbox OS.
debian packages for all architectures that folks here use
connection sets
The idea here being that when you get everything set up as you like for a particular piece for performance, you can use amidiminder to save that as a named rule set. Then you can use amidiminder to completely swap rule sets live to reconfigure your set up as needed.
For the Debian packaging part - having packaged up so much software for Patchbox OS, we’ve already got the amidiminder package debianized using debhelper scripts here: https://github.com/BlokasLabs/amidiminder. Using the command dpkg-buildpackage -b it will produce a build for the current host architecture (devscripts APT package must be installed). I have set up two build nodes here for building arm64 and armhf .deb packages. Cross compilation is possible too, but as long as there’s a limited number of target architectures, building on targets themselves should be most foolproof.
We’ve also made the /etc/amidiminder.rules to actually be a symbolic link to /etc/default/amidiminder.rules - this way it’s easier to have patchbox override the amidiminder configurations for activating different modules for which you might want to have different sets of amidminder rules. Use case - you activate, say, Pure Data module, it automatically changes the symbolic link to something else, edit the /etc/amidiminder.rules, and your changes are associated with Pure Data. When you activate ORAC, it could link its own copy of rules, which might be different. When all modules are deactivated, it would link it back to /etc/default/amidiminder.rules.
This is very similar to the connection sets idea. Let us know if you’d like this logic modified, we could switch to adopting connection sets.
We could send you a pull request with the changes thus far.
This would be great! It should also be defined that the rules in /etc/amidiminder.rules are the base rules, and that live rules, set up through live changes using any utilities modifying the ALSA sequencer subscription, will override those rules. One caveat I see - it can be difficult for amidiminder to know when a live rule should be ‘forgotten’ - for example, when you manually add a connection, and then remove it, should amidiminder remember that the devices should not ever be connected anymore, or should it delete the live rule in case the latest action matches what would happen by base rules?
Btw, the ‘live rules’ term could be something else, something that would immediately mean that they persist reboots.
A CLI for modifying amidiminder’s rules would be useful, but it should still try and keep track of live changes from other sources. Having its own CLI could allow users to be more explicit about what they mean - like I mentioned above, disconnecting devices using aconnect might be understood as adding a rule to ensure they’re not connected, or that the rule to connect them should be deleted. If a dedicated CLI is available, the user can be specific.
Another useful command would be to move the ‘live’ rules into the base rule file, so when clearing the live rules, you return to your currently desired base state.
A man page would be great. It would also allow the default rules file to be much slimmer with most of the comments moved to the man page. (p.s. the debhelper scripts help with automatically installing the .1 file to the right location, PM me in case of any questions of how to package these things properly)
It would be great if amidiminder could run in daemon mode and have some means of communication with its utilities (unix socket?) to communicate things like rules modifications, a request to live-reload the base rules file, but simply restarting on file changes could work as well (I think systemd is capable of restarting a service whenever it detects a certain file’s contents has changed, but it would be great to retain the old valid set of rules, in case the new contents have syntax errors)
amidiminder, when run in “minder mode” (as a system service) maintains two files:
profile.rules - a list of rules to apply as devices and ports come on-line
observed.rules - a list of observed connections (and disconnections that override connections made by rules)
These files will be in /var/lib/amidiminder and survive both service restarts and system reboots. This makes your MIDI connections act just like they were physical connections.
amidiminder can also be run as a command line tool, which lets you manipulate the rules:
amidiminder check <user-rules-file> - runs syntax check on a rules file
amidiminder load <user-rules-file> - if it is a valid rules file, removes all connections, clears the observed, resets the profile.rules file to a copy of the user rules, makes connections as per these new rules.
amidiminder save <user-rules-file> - combines the current profile and observed rules into a rule set and writes it to the user file
amidiminder reset - removes all connections, clears the observed file, makes connections as per the existing profile.
Edit: Changed to match the final terminology: ‘profile’ and ‘observed’.
What if the disconnection is not intentional? (like device intermittent disconnect) - will amidiminder be able to differentiate whether it’s a user action (like aconnect -d)? (I’m not sure what events ALSA sequencer produces in device disconnection case, does it produce the SND_SEQ_EVENT_PORT_UNSUBSCRIBED events regardless of the circumstances, or in case the devices is disconnected, it may be producing only SND_SEQ_EVENT_PORT_EXIT)
Do the CLI commands communicate with the daemon running in the background to carry out the save, load & reset commands?
amidiminder already distinguishes between connections lost because the port was removed (for example on power off, or cable disconnect) from connections that were an intentional disconnect by the user (or the user’s software).
Technically, on a port going away, ALSA produces a SND_SEQ_EVENT_PORT_EXIT and simply removes any connections that port participated in without sending SND_SEQ_EVENT_PORT_UNSUBSCRIBED events.
The CLI commands will indeed communicate to the daemon for the save, load, & reset commands. I’m planning on using a unix domain socket which will be located in /run/amidiminder (using the normal systemd support for changing that location)
Launchpad # by default
Launchpad:1 # by number
Launchpad:Standalone # by name
Launchpad:* # by wildcard
by default: Uses the first port on the device that can is in or out as needed. As most devices have just one port, this does what you want most of the time. For software, like PureData or SuperCollider that separate in and out ports, it will use the first in each direction, again, usually what you want.
by number: Identifies the port by the ALSA port number, which start from 0, and is in the order the device or software adds them. Succinct, but opaque.
by name: Matches ports by name. Without quotes (spaces allowed), this name is found anywhere in the full port name (case insensitive), then it matches. With quotes, only exact match to the port name matches.
by wildcard: Uses all ports from the device that are in or out as needed. Generally, this is only useful in disallow rules.
The by number and by name forms haven’t changed at all.
The by default and by wildcard forms replace the current :* wildcard, which acts almost like the by default in connection rules, and like the by wildcard form in disallow rules. The semantics were muddy and hard to understand.
I realize that amidiminder is a mouthful, and long to type. And because amidi is an exisiting command, you have type a fair bit before command completion works.
If there is interest in changing the name - this is it. Once we get it into debian, the name will be pretty much fixed. I don’t feel strongly either way, but thought I’d throw out these alternatives:
The port names seem to make sense, I don’t see anything wrong with that.
In my experience, the snd_seq_parse_address doesn’t take care of resolving the port index from the port name (it simply does atoi on the part after the : (or .)), do you plan to use your own extended variation of this API?
As for the name, amidiminder seems ok in my opinion (‘minder’ has a suitable meaning too). Some similar shorter versions could be amidimind, aminder or amind
It might be useful for 3rd party software to reuse the name matching logic (resolving a string into a client_id:port_id) - that could be in libamidiminder as a collection of useful APIs (or maybe it could even have APIs to control the amidiminder daemon). But this is a nice to have thought.
Pre-release .deb files are here! Try this one out, folks!
The packages have been tested on Patchbox OS, both the current (armhf, based on bullseye) and beta (arm64, based on bookworm) - all on RaspberryPis.
In summary:
The daemon is run by systemd, and should just be happy as a clam in the background. It persists all state, so even hard rebooting your system will bring all your devices connected back up.
There is no longer a config file in /etc. Instead - write your on rules files in your own directory, and run:
amidiminder load my-rules-file.rules
You can have different files, and load them as needed. Loading will tear down all connections and re-make them as per the profile. (Different modules in Patchbox OS could now have their own rules files and can load them when the user switches modules.)
Connections you make or break with aconnect or other tools will be observed and remembered, and kept as part of the configuration.
At anytime, you can see the current rules in force:
amidiminder save -
You can check things are running and set up correctly with this:
amidiminder status
We put a lot of attention into the log messages to try to make things clear. You can follow them with:
journalctl -f -u amidiminder.service
Finally
See the man pages (after you install, or in the links in the prior message, they’ve been updated), for all the details.
Please please please let me know how it goes… report bugs here or in the github repo.
And yes, we have a few more surprised up our sleeve for 1.0 release, which should happen by end of year…
This will connect a port from the Midihub to the MicroMonsta. But which port?
I think most users would expect, after seeing the listing above, for it to be the second port, that is [36:1]. I am making both amidiminder and amidiview interpret Midihub:2 this way - as a partial match against the port name.
The old amidiminder treats ‘:2’ as a match on the ALSA id, so [36:2], which is the third Midihub port. I’m adding a syntax to explicitly mean match by ALSA number: Midihub:=2 - but I can’t imagine it is all that useful.
Since this is a breaking change (should your rules use port numbers) - I’m looking for opinions.
Current project status: I split the functionality into two commands, amidiminder for all things dealing with profiles and the service. and amidiview for the new interactive view command, and replacement for aconnect (listing, connecting and disconnecting). We are really close to a 1.0 release. I’ll do a 0.90 release tomorrow so folks can install and try it if they wish.
Good stuff, @mzero ! These tools will be essential for MIDI on Linux.
Btw, for me it seems counter-intuitive for a command called amidiview to be able to make changes to the graph, as ‘view’ seems to imply read-only interactions. An alternative name I could suggest is amidigraph - it should fit both the display and the editing nicely.
The rest makes sense, including partial string matching for port name ID.
Theoretically it could be useful if you want to tie to a particular index, as Midihub allows overriding the USB Port names, they may get changed between reconnects of Midihub if the user has edited them. A rare, but possibly legit use case for supporting the index based port selection.
I didn’t come across the ‘wala’ word suffix before (first thing to come in mind was voilà due to similar sound), but it might make sense. I think the ‘a’ prefix indicates that it’s related to ALSA world, but in the end, it is your choice how to name it.
The executables, package, service and even the service-user have all switched to the final names:
midiminder - the service, the command for interacting with the service, and user name the service runs under
midiwala - the Swiss army knife of ALSA MIDI ports and connections
The package will correctly stop & disable the service under the older name, and will prompt you to remove the older packages. You can do so before or after installation of this version:
sudo apt remove amidiminder # or purge instead of remove if you prefer
sudp apt remove amidiauto # if you have this older pagkage
If you had custom rules loaded into amidiminder you can load them into midiminder:
midiminder load /etc/amidiminder.rules
You only need to do that once… the loaded rules are persistent, until you load other rules.