probonopd / MiniDexed

Dexed FM synthesizer similar to 8x DX7 (TX816/TX802) running on a bare metal Raspberry Pi (without a Linux kernel or operating system)
https://github.com/probonopd/MiniDexed/wiki
1.13k stars 81 forks source link

Initial implementation of system-level, i.e. all TG, MIDI control maps #704

Closed diyelectromusic closed 1 month ago

diyelectromusic commented 3 months ago

As per discussion here: https://github.com/probonopd/MiniDexed/discussions/702#discussioncomment-10409687

Defines the following "CC maps" for use in controlling each individual tone generator over the same MIDI channel: 0 = disabled 1 = CC 16-19, 80-83 - the General Purpose Controllers 1-8 2 = CC 20-27 3 = CC 52-59 4 = CC 102-109 5 = CC 110-117 6 = CC 3, 9, 14-15, 38-31 7 = CC 35, 41, 46-47, 60-63

Note: maps 2-7 utilise various sets of undefined in the MIDI spec MIDI CC numbers.

These can be configured in minidexed.ini for any of the following MIDISystemCCVol= MIDISystemCCPan= MIDISystemCCDetune=

It has only had very, very basic testing but as a concept I think it could work.

This PR is to let people try out the concept and see if it has any merit.

Kevin

github-actions[bot] commented 3 months ago

Build for testing: MiniDexed_2024-08-21-3ec467f Use at your own risk.

diyelectromusic commented 3 months ago

The question now is what MIDI channel should this be tied to?

At the moment it will respond to any MIDI channel configured for any tone generator (in fact, I ought to ensure it only gets processed once - if all 8 TGs are on the same channel, then this will currently be processed 8 times!).

But we could say it should only be on the PCCH channel. Or it could only be on the TG 1 MIDI channel. Or we could keep it as any listening MIDI channel, but I'll just ensure it is processed once.

This last option would mean that if each TG had its own MIDI channel any of them could still be used to set the parameters for all TGs, so maybe that is the best option?

Thoughts? Kevin

github-actions[bot] commented 3 months ago

Build for testing: MiniDexed_2024-08-21-d94d3f5 Use at your own risk.

iluvsa commented 3 months ago

Ok this works as expected for me! It’s really cool! Especially if you have a controller that allows multiple configs to be saved (e.g. Arturia Minilabs, MidiTwister, etc.). You can have one config to adjust all your voices’ volumes and pans or tuning simultaneously, then switch back to your main config to have control over Reverb, Filter, Bank Select. It makes the Minidexed really easy to adjust on the fly!

And yes, we need one instance of it processed, because I do notice hiccups here and there when making volume and pan changes, on a Pi 4, but I bet it’s because they are all on one channel.

Lastly - there’s no way for the screen to track changes as you make them, right?! It’s great to have all this control I just wish it could flip to the parameter being adjusted while receiving MIDI CC for that parameter!

Regardless, amazing work!

diyelectromusic commented 3 months ago

Are you using the first build or the second? The second shouldn't be doing multiples now so I'd hope the performance of that wouldn't be too bad.

It's hard to test things like that, but I'll add in some instrumented code (pun intended) and see if I can work out the performance impact, but I don't have a set up to test this easily at the moment - although I could probably rig something together!

I am thinking about screen updates - again it is something lots of people ask for, but that will have to be its own change I think.

Kevin

diyelectromusic commented 3 months ago

Ok, I suspect there is a significant performance hit if the system receives an unsupported CC message as there is a lot of checking required to get to the point of realising it is unsuppported.

I see what I can do - there must be a quicker way to reject unrecognised CCs :)

Kevin

diyelectromusic commented 3 months ago

I think that will slimline the processing a little - try this latest build and see how that behaves.

Kevin

github-actions[bot] commented 3 months ago

Build for testing: MiniDexed_2024-08-22-b94961a Use at your own risk.

iluvsa commented 3 months ago

The last code works much nicer, nearly immediate volume and pan control for each TG! The setup pictured is so great - individual volume, pan, and detune across all 8 TGs! Stay tuned I think I am gonna stuff it all into the controller and create some vinyl graphics to create a proper DX-56!! Thanks again for the work on this! IMG_5534

probonopd commented 3 months ago

This is way over my head. Could someone please write a concise description of what this does, and why one would need this. So that we can put it in the wiki.

This feature seems rather esoteric to me, but I might be mistaken. Do commercial instruments have something like this? Is it worth complicating the code for this? Could the same effect be achieved in another way (e.g., by sending multiple or different MIDI messages to MiniDexed)?

diyelectromusic commented 3 months ago

You can see for yourself how complicated the code is - i.e. not much.

And almost any multi-timbre, multi-instrument out there will give you ways to control the parameters of each individual instrument over MIDI, so I'd say it fits really well with the idea of the MiniDexed as 8 DX7s playing together.

If it helps, think of each TG as an oscillator then one of the most natural things in the world to do is to change the amplitude of each oscillator with respect to each other and to offset the frequency of each oscillator with respect to the core playing frequency. It is just that in this case a single oscillator is an entire 6-op DX7 synth voice.

And when using it as a "performance" instrument when all TGs are on the same channel there is no way for individual control until now, so I think it works really well with performances too.

So maybe the simplest way to think about it is MIDI control for volume, pan and detune for each individual TG in a performance voice.

I looked quite hard at the DX7/DX7II MIDI support for alternative ways to do this (full analysis here: https://github.com/probonopd/MiniDexed/discussions/702#discussioncomment-10388388) but I couldn't find any. I think this is actually now quite neat.

As I say, it is really quite a relatively simple addition compared to some we've had to massage in (cough MIDIAutoVoiceDumpOnPC cough).

Anyway, like all the changes I submit, I'll update the wiki once its complete.

I could do with some people testing their normal configurations with it to ensure no side effects (there shouldn't, but I've been known to miss things in the past :))

Kevin

iluvsa commented 3 months ago

Yes, to re-iterate the comments above, and given as I was the one originally wondering about it - I think the two main uses for 8 instances of a DX-7 would be to have various instances on different MIDI channels, allowing for multiple DX-7's to be doing different things, or the second (and I think more common scenario given the "Performances" that are provided in the code?), which would be to allow just a big, fat, multi-voice patch to be controlled by a single MIDI channel. In the latter case, the only way to previously adjust the volumes, pans, or de-tunes of individual TGs was to go in to the menu (of course, recalling which voice was assigned to each TG) and adjusting them one by one and listening for changes in the performance - cumbersome in the studio, and fairly impossible (oxymoron alert!) during an actual performance.

I think on commercial synths, this kind of control would be achieved to some degree with a "Mix" knob, but of course, with most commercial synths, you'd only be dealing with two (or three) individual synth engines - here we essentially have 8!

And, for me, none of these things showed up in the miniDexed.ini file unless you add them, so it's there if you need it, but out of sight if you don't!

miotislucifugis commented 3 months ago

Rather than add another layer of midi control that needs to specify individual settings, perhaps a more versitile and "playable" approach (albeit prob more difficult) would be to to have mididexed be able to link link a stack of TGs, anywhere between 2 and 8 TGs, with the top one being the leader and all the other TG layers following all of the "leaders" parameter changes...using the leader's midi channel AND/OR minidexed menu settings*. For example, if one wanted to create a 4 layer patch using TG 1-4, TG1 would be the leader and TGs2-4 would mirror all of TG1's parameter settings. If a change was made to one of TG1's parameters, volume for example, the change would be reflected on all of the follower TGs. ideally one could go to each layer's individual settings and override the master's default, for example detune and pan, creating a custom setting on each TG, that would unlink them from the master. Changing Detune and pan setting for TG1 then would then have no effect on the other TGs whose detune and pan setting have been "unlinked"... but channel, reverb, volume,... any paramater that has not been altered would still follow TG's lead. Make sense?

extra ideally, there could be multiple groups - 2x 4 TG layers or 4x 2 TG layers... or a 4 layer stack + a 2 layer stack + 2 individual independent TG voices... etc.

extra extra ideally, would be an option to play all the voice in the stack simultaneously where all are played at the same time or sequentially, where each note played triggers the next TG in the stack, round robin style, like how most polyphonic synths operate.

*i guess midi cc commands would apply by default to all TGs on the same midi channel... and this presents a challenge to how they are applied to the "unlinked" parameters. Maybe the custom setting values could be applied as an offset to the incoming CC messages... the levels would change relative to the original settings. another example: unlinked parameter settings of 10, 20, 30 (on different TGs) would become 60, 70, and 80 respectively with an incoming CC message with the value of 50.

probonopd commented 3 months ago

I guess what I am not understanding is why don't we send MIDI messages to OMNI if we want to steer all TGs. Is it because some controllers can't send to OMNI? Wouldn't it be conceptually easier then to have an option to say "Interpret channel 1 as OMNI" or something like that?

miotislucifugis commented 3 months ago

Well, yes some controllers do not send omni...(also many commercial synths do not offer to receive omni) but even so, omni is not ideal because it responds to ALL incoming midi messages. Maybe not a issue if your set up is just minidexed and a controller, but if you want to use a multitrack sequencer and other midi instruments, it quickly becomes problematic. you dont want the lead droning away because it also responding to all the drum, bass, and pad parts.

diyelectromusic commented 2 months ago

I guess what I am not understanding is why don't we send MIDI messages to OMNI if we want to steer all TGs. Is it because some controllers can't send to OMNI? Wouldn't it be conceptually easier then to have an option to say "Interpret channel 1 as OMNI" or something like that?

No controllers can "send to OMNI" - that isn't a thing in MIDI. If they say they are doing it, they are sending to each channel 1 to 16 in turn rather than an actual "omni broadcast".

The OMNI concept is really just a MIDI way of saying "whatever channel is used in the message, ignore it and respond as if it was sent to you" in a receiver.

The key issue is that either all TGs are treated as separate instruments for both control AND notes (by being on different channels) or they are treated as the same instruments for both control AND notes (by being on the same channel).

This change is about letting them be the same instrument by being on the same channel, but still allowing some individual control.

Any talk of changing all TG parameters at the same time, or stacking specific numbers of TGs, whilst a valid request is different to the aim here and there are other issues/discussions relating to that elsewhere.

To be honest, given the cost of Pi Zero 2 or Pi 3A+, on the issue of stacking/layering/splitting TGs I'd be tempted to say just make several MiniDexeds and use each as its own multi-TG single instrument :)

Kevin

diyelectromusic commented 1 month ago

Is this something we can merge in now? Any objections from anywhere?

Kevin

probonopd commented 1 month ago

The main issue is that I still don't fully understand this. It seems rather complicated to me, and it doesn't seem to have an eqivalent in the DX/TX... series of instruments.

Wouldn't this kind of functionality be better solved in a separate external box that could do all kinds of user-defined MIDI translations?

diyelectromusic commented 1 month ago

The main issue is that I still don't fully understand this. It seems rather complicated to me, and it doesn't seem to have an eqivalent in the DX/TX... series of instruments.

With our performance system, we deviated from the original DX/TX series a long time ago...

Wouldn't this kind of functionality be better solved in a separate external box that could do all kinds of user-defined MIDI translations?

The problem is that at the moment this is /impossible/ to do over MIDI at all. This change exposes the parameters to MIDI to allow exactly what you suggest. In theory a complex, magic MIDI box could redirect on an individual message basis, but only when all TGs are on their own MIDI channel which completely breaks all the performances and makes playing them all at the same time very problematic.

As we've discussed several times before, MiniDexed is one of two things depending on the viewpoint (and thus configuration) of the user.

It is either 8 DX7s or a single multi-TG instrument.

When 8 DX7s it will typically have TGs on different MIDI channels, will allow full individual control of TGs over MIDI and be in a world of banks and voices. BUT it is not possible to play all TGs at the same time unless notes are sent to all MIDI channels, which is very inefficient in MIDI terms (and essentially not usable for serial MIDI).

As Synth_Dexed is fundamentally a DX7 emulator, not a DX7II or anything else, the "multi-DX7" view originally made the most sense and was (arguably) the original purpose of MiniDexed, but nothing stands still, and then performances came along.

When used as a single-multi-TG instrument, this brings in the world of performances. In this world, banks/voices are irrelevant unless you are making your own performances (and even then are ignored once saved); TGs typically all have the same MIDI channel (all our performances use channel 1); and all TGs respond together to notes and MIDI messages as if it was one large instrument.

However, there is NO means of individual control of the TGs when used like this. There are some bespoke SysEx ways to do it for a DX7II based instrument, but not ours (I looked quite hard - see https://github.com/probonopd/MiniDexed/discussions/702#discussioncomment-10388388).

If someone bought a commercial instrument with 8 individual sound sources, intended to be played together but had no means (over MIDI) to control the mixing parameters between them (volume, pan, tuning) we'd all agree that was a bug and a missing feature that limits its use.

This relatively simple change adds that control.

The alternative is either a full DX7II style implementation of the bespoke SysEx messages (which might come at some point, but needs to basically upgrade Synth_Dexed to a DX7II), or exposing our menu system to MIDI (e.g. something like this proposal for using NRPNs: https://github.com/probonopd/MiniDexed/pull/604) or my original proposal to expose TG parameters directly over MIDI which you weren't keen on as I'd used to allow several MiniDexeds to share the same UI (https://github.com/probonopd/MiniDexed/pull/557#issuecomment-1791590308).

Considering what functionality this change enables, for very little additional complications in the code, and considering how it fits a lot more with how people are coming to see MiniDexed (as a single-8-TG-instrument), I see no reason not to do it.

Kevin

probonopd commented 1 month ago

Thanks for your explanation. Now I begin to understand the necessity for this, but I am still wondering whether the intended result could be achieved in a much more straightforward way.

Wouldn't a simple solution be to a) have each TG use its own MIDI channel in a performance, and e.g., define one of our MIDI channels as "send to all TGs"? So, if you want to make a change that affects all TGs in the performance, you use that special MIDI channel. Otherwise, you use the respective TG's MIDI channel.

In other words, since there is no "OMNI channel" in MIDI, what prevents us from using one of the regular MIDI channels in such a way that messages sent to it are sent to all TGs?

diyelectromusic commented 1 month ago

So you'd rather us not implement a common MIDI idea (multiple controllers for different sound sources) but instead re-invent the mental model about how MIDI itself works by redefining what a channel actually means, going against the MIDI spec (and 40+ years of established behaviour in other devices)?

And while we're at it rewrite each and every performance file we have to a hard-coded MIDI scheme...?

:)

I tend to assess these things by "principle of least surprise". What is the least surprising to someone using the system:

As I said above, MiniDexed is fundamentally two mental-models built into one system. Your suggestion (to me) conflates the two and I think would just cause major confusion, whereas this change is working well within both mental models, and is also a common pattern for MIDI control when compared to other devices.

Kevin

probonopd commented 1 month ago

Well, I think rewriting the performances sounds worse than it is, because we could automate it.

outside of the MIDI spec

OK, we should of course not do something that is outside of the MIDI spec. If I understand you correctly, you are saying that what this PR is doing is what other off-the-shelf instruments are doing in a similar way. Then we should go with it.

But please add extensive documentation to the wiki, including an example ("explain this to a five year old"). Thanks!

diyelectromusic commented 1 month ago

Wiki updated.

Remember this is disabled by default, so doesn't have to be used by anyone not wanting it. And the best way to realise the usefulness is to give it a try. Detune is particularly splendid to try...

Kevin