giada icon indicating copy to clipboard operation
giada copied to clipboard

Support for multiple MIDI devices

Open tblrchstr opened this issue 6 years ago • 11 comments

Giada should be able to support more than one MIDI device at once. The problem arises when using MIDI devices over USB, where the concept of MIDI-through doesn't apply.

tblrchstr avatar Sep 09 '18 09:09 tblrchstr

On Linux and macOS the audio/MIDI framework of the OS (ALSA/JACK resp. CoreMIDI) already provides that for you. On Windows you can use "virtual MIDI cables" like MIDI Yoke or loopMIDI.

SpotlightKid avatar Nov 26 '18 14:11 SpotlightKid

I'd love this ehancement too.

I don't understand how to use the single MIDI port with multiple devices : is there another solution than configuring different MIDI channels and hope there is no conflict between not-configurable devices?

KjoHansiGlaz avatar Aug 09 '19 21:08 KjoHansiGlaz

Not a MIDI expert here (ping @tblrchstr), this feature has been planned in order to fix the annoyance you @KjoHansiGlaz mentioned. I didn't experiment with the solutions provided by SpotlightKid yet...

monocasual avatar Aug 15 '19 07:08 monocasual

I did use Giada with Jack, so I could connect all MIDI controllers to Giada easily. However I understand that the idea is to use Giada with multiple controllers and without any additional software.

I think that the solution ought to be well discussed and a well defined solution must be picked in order to avoid unnecessary work.

The problems I see right now are:

  • Only one MIDI controller without external software
  • MIDI controllers tend to operate on Channel 1 by default
  • Grid controllers like Launchpad tend to use Note On / Off for its buttons

These could be addressed as such:

  • More MIDI inputs in Giada settings :) I'm not sure about this, but I think that under the hood that would still be one MIDI socket, just binded to more than one device. This is how ALSA MIDI does it, at least.
  • Built-in MIDI channel translator for selected devices. For me it's completely unnecessary, just a loose idea.
  • Separate MIDI inputs for grid control (playback, arming, muting etc) and note control (actual musical content in Giada MIDI channels). Sure, this also can be addressed by manipulating controller's midi channels, but that's not so hard to do, and might clean up the code a little bit. And what's moire annoying than recording Launchpad's key presses by accident.

tomek-szczesny avatar Aug 15 '19 10:08 tomek-szczesny

@tomek-szczesny I have a (hopefully) simple and straight solution for the near future: just allow more inputs simultaneously. Yes, it's basically what you are suggesting in point 1. :+1:

RtMidi, the library our MIDI layer is based upon, already allows this. Quoting their docs:

Create multiple instances of this class [RtMidiIn] to connect to more than one MIDI device at the same time.

In "user land" this would mean to have a selectable list of checkboxes for each MIDI input port/device available. Want multiple inputs? Selects more checkboxes and you are done.

MIDI controllers tend to operate on Channel 1 by default

Could this be a problem when you have multiple devices connected, all of them operating on Channel 1?

Grid controllers like Launchpad tend to use Note On / Off for its buttons

Genuine question: In the wake of #251, could you show me a scenario where a Note On/Off triggered by the Launchpad would conflict with other things in Giada?

monocasual avatar Aug 19 '19 15:08 monocasual

RtMidi, the library our MIDI layer is based upon, already allows this. Quoting their docs:

Create multiple instances of this class [RtMidiIn] to connect to more than one MIDI device at the same time.

In "user land" this would mean to have a selectable list of checkboxes for each MIDI input port/device available. Want multiple inputs? Selects more checkboxes and you are done.

It's been a while since I tinkered with MIDI support in Giada and I'm not really handy with Cpp, but I think that this is going to be more complicated than this. It calls for handling unspecified number of instances of classes, huh.. It's beyond my Cpp skills for now, but surely it's possible!

MIDI controllers tend to operate on Channel 1 by default

Could this be a problem when you have multiple devices connected, all of them operating on Channel 1?

It is not a problem right now because Giada seems to zero the MIDI channel information from incoming MIDI messages. place in repo However, if this is planned to use multiple MIDI controllers, I think Giada must start respecting MIDI channels 1-16, and be able to repeat them faithfully. That's basically the point of using multiple MIDI controllers. As far as I understand, right now Giada records the MIDI messages (by default from all MIDI channels), zeroes the channel info, then plays the notes back with a user-selected MIDI channel info, per Giada channel. I think this must be a royal pain in the back in the live setting. You create a channel, tap in a drum beat, and by default it plays back the beat on channel 1, not channel 10, the default channel for drums.

What I suggest is:

  • to let Giada actually handle MIDI channel info from incoming messages, and play them as they came.
  • To get rid of this option, to select output MIDI channel, because this has been determined by the controller.
  • to introduce, in place of the removed option, a "Midi channel translation" feature, that would disregard recorded MIDI channel info and play the content with user-selected channel.

I think this would allow for more advanced use of Giada with multiple MIDI controllers without losing any bit of original functionality. Actually, this solution should be completely backward - compatible.

Grid controllers like Launchpad tend to use Note On / Off for its buttons

Genuine question: In the wake of #251, could you show me a scenario where a Note On/Off triggered by the Launchpad would conflict with other things in Giada?

Sure. While you record something off your midi keyboard and at the same time press some buttons on a Launchpad, Giada will record it all, and play back both keyboard and Launchpad key presses. I'm pretty sure this happened to me at least once.

Now imagine going through "Setup MIDI Input" on all Giada MIDI channels just to filter out the grid controller...

The separate MIDI input for grid controller isn't a perfect solution. For example AKAI APC KEY 25 combines grid controller, knobs and keyboard, and it's still seen as a single device. The perfect solution would be to discard notes while recording, that were identified by Giada as any sort of function keys. However I'm not smart enough to estimate the viability of these solutions. I could TRY doing it...

tomek-szczesny avatar Aug 19 '19 18:08 tomek-szczesny

@tomek-szczesny first of all thank you for your detailed feedback, this is really helpful.

[...] I think Giada must start respecting MIDI channels 1-16, and be able to repeat them faithfully. That's basically the point of using multiple MIDI controllers. As far as I understand, right now Giada records the MIDI messages (by default from all MIDI channels), zeroes the channel info, then plays the notes back with a user-selected MIDI channel info, per Giada channel.

This is correct. Giada strips the channel information away from incoming MIDI Messages. It's a naive trick that simplifies the internal messaging system. What if, according to your suggestion number 1, we simply keep (and store) the channel information during a recording session, so that it can be sent back again when needed, untouched? Giada would of course need to filter it out during its internal computations, but it shouldn't be much of a problem. This way the live mode experience is preserved. Does it make sense?

Sure. While you record something off your midi keyboard and at the same time press some buttons on a Launchpad, Giada will record it all, and play back both keyboard and Launchpad key presses. I'm pretty sure this happened to me at least once. Now imagine going through "Setup MIDI Input" on all Giada MIDI channels just to filter out the grid controller...

Great, I see now. Just off the top of my head: given the multiple-MIDI-device-support for granted, why not adding some kind of flag that marks the device as "functional", i.e. a device whose MIDI messages should be interpreted as function keys instead of note keys? EDIT - nope, on a second thought I fear this solution would leave out complex devices such as the AKAI APC KEY 25 ...

monocasual avatar Aug 20 '19 16:08 monocasual

@monocasual I hope I will prove myself more helpful with actual coding and testing. :)

What if, according to your suggestion number 1, we simply keep (and store) the channel information during a recording session, so that it can be sent back again when needed, untouched? Giada would of course need to filter it out during its internal computations, but it shouldn't be much of a problem. This way the live mode experience is preserved. Does it make sense?

Yes, I think this is exactly what I meant. I'm not sure how complex is this task and why abandoning this chunk of data simplified anything in the first place, but hopefully this can be done. I think that sending back MIDI notes with original channel info should be the default behavior. An option of translating notes to some other channel (in Setup MIDI Output per Giada Channel) should ensure full compatibility with current functionality, for those who have less controllers or more synths in their setup.

Some problems I foresee include:

  • Compatibility with old savefiles The problem arises only if someone created Giada MIDI Channel, filled it up with data, and then left the "Enable MIDI Output" checkbox unchecked. No idea why on earth would anyone do this, but if we followed my idea of converting this function into "Translate into MIDI Channel", this case won't work properly. But, then again, I can't see the point of the option to disable MIDI output in Giada MIDI channel.
  • Upgraded piano roll for multi-channel MIDI support. I think that for the completeness of this solution, Giada MIDI channels should be ready to record inputs from all 16 MIDI channels and keep channel information. Then, it's gonna be a challenge to represent those notes in GUI. My idea is to introduce a drop-down menu for selecting MIDI Channel, that would work a bit like layer selector in graphics tools. The notes from user-selected MIDI channel should have a solid color like they have right now, and all the rest should have dimmed color and blend into background. The user will be able to manipulate notes from currently selected channel only. The default usage of piano roll in general is to stay within the scope of just one MIDI channel. This is why the widget would automatically pick the correct MIDI Channel setting upon loading the widget, and while recording new content. This way, again, less experienced users won't notice any change. Why is this important? Because without that we're letting users record MIDI content they can't fully control afterwards. There is no mechanism of MIDI Channel manipulation in Piano Roll, and I think the one I'm suggesting is the best trade-off between development effort and user experience.

Just off the top of my head: given the multiple-MIDI-device-support for granted, why not adding some kind of flag that marks the device as "functional", i.e. a device whose MIDI messages should be interpreted as function keys instead of note keys? EDIT - nope, on a second thought I fear this solution would leave out complex devices such as the AKAI APC KEY 25 ...

That's just another take on my idea of separate MIDI input for "functional" devices. ;) Except that my idea still leaves the possibility to use APC KEY 25 as both grid and note controller - just connect it to both MIDI inputs. I'd seriously consider more user friendly solution - that once the received MIDI message is considered "functional", it is simply ignored by MIDI recorder. I just fear it might be a complex dev task.

Like I said before, when we agree on a functionality, I'll try implementing at least some of it.


EDIT:

I'd seriously consider more user friendly solution - that once the received MIDI message is considered "functional", it is simply ignored by MIDI recorder. I just fear it might be a complex dev task.

I think this one is easy after all - in midiDispatcher.cpp, all I need to do is to block processChannels_ if processMaster_ was successful in any way. Also, in processChannels_ the "for" loop should be broken into two. The first one would process "functional" actions per channels, while the second one would forward MIDI message to VST plugins and channels only if, again, the MIDI message still wasn't processed by the former loop. Does it sound right?

I also skimmed through pianoRoll.cpp and it seems pretty straightforward, I think I can handle the multi-MIDI-channel support that I suggested.

tomek-szczesny avatar Aug 20 '19 18:08 tomek-szczesny

Some problems I foresee include:

  • Compatibility with old savefiles [...]

That's not a huge problem actually. We are still in a "beta" stage of development, breaking things is allowed :grinning: If backward compatibility becomes a nightmare we could hack a quick script that converts old patches into new ones.

  • Upgraded piano roll for multi-channel MIDI support. [...]

Agreed. We need to find a way to "paint" notes in the MIDI Action Editor given a MIDI channel. Your solution looks pretty good.

I think this one is easy after all - in midiDispatcher.cpp, all I need to do is to block processChannels_ if processMaster_ was successful in any way. Also, in processChannels_ the "for" loop should be broken into two. The first one would process "functional" actions per channels, while the second one would forward MIDI message to VST plugins and channels only if, again, the MIDI message still wasn't processed by the former loop. Does it sound right?

Sounds right indeed. Just one question: how would you identify a MIDI message as functional, once received? Maybe during MIDI learning?

I also skimmed through pianoRoll.cpp and it seems pretty straightforward, I think I can handle the multi-MIDI-channel support that I suggested.

That would be great! However I strongly suggest you to wait until we merge the solid-arch branch into master, which will be a kind of game changer for the internal architecture. It should be done around September/October hopefully...

monocasual avatar Aug 24 '19 09:08 monocasual

Sounds right indeed. Just one question: how would you identify a MIDI message as functional, once received? Maybe during MIDI learning?

The solution I propose doesn't care. ;) If the MIDI message did some action in processMaster_, don't call processChannels_. If within processChannels the MIDI message does anything functional in any channel, skip the separated loop that sends MIDI message to all Giada channels and VSTs.

That would be great! However I strongly suggest you to wait until we merge the solid-arch branch into master, which will be a kind of game changer for the internal architecture. It should be done around September/October hopefully...

That's fine, I'm busy too :) Feel free to assign me the tasks that we were discussing so you won't forget who promised some help. Any plans for tinkering with piano roll? I could at least start figuring out the editor part.

tomek-szczesny avatar Aug 24 '19 19:08 tomek-szczesny

The solution I propose doesn't care. ;) If the MIDI message did some action in processMaster_, don't call processChannels_. If within processChannels the MIDI message does anything functional in any channel, skip the separated loop that sends MIDI message to all Giada channels and VSTs.

Sounds good to me!

Any plans for tinkering with piano roll? I could at least start figuring out the editor part.

If you wish you can take a look a the source code in the solid-arch branch, the UI part has already been ported to the new architecture. I've opened a new issue #252 that adresses both the core logic and the interface. I've put some useful information in there, such as which classes are responsible for the whole piano roll thing. Thanks!

monocasual avatar Aug 27 '19 15:08 monocasual