Help me build a keyboard macro.

Bolle
Bolle Member Posts: 349 Pro
edited July 2022 in Building With Reaktor

Hi everyone.

This one's another little experiment / project for upload to the User Library and of course personal use. A keyboard Macro for everyone to download, adapt and use in their projects.

There are a bunch of different methods on the User Library already, but none of them work really well imo. Lots of them devide the keyboard into the amount of voices of the instrument. That works, but it's not how a real keyboard reacts to multiple keys being pressed. Even if an instrument only has 4 voices, at least 12 keys can be pressed simultaneously (12 fingers, innit).

An earlier version i built needed a voice count equal to the amount of keys, in order to not have sticky keys.

Anyway. This is where i'm at right now, and i have questions.

I gave every key its own Macro, with a monophonic Selective Note Gate module and Mouse Areas that are placed on top of the key graphics. No sticky keys, even with only two voices and multiple keys pressed. Like so:

My initial plan was to not have the keys be playable with mouse button clicks, but then why not? This should be doable.

As far as i can tell, the keyboard graphics move and react flawlessly now, even with low voice counts.

What i'm trying to do now is get the mouse area events fed into the oscillator and combining the Midi Keyboard events with the Mouse Area events, using either a Merger or an Add module. This does not work, even though Mouse Area events send the note number of the key in question to the oscillator.

If i can get this to work, i'll probably make the graphics perfectly rectangular and i a few different sizes so people can choose which size fits their project.

You are most welcome and free to help me throw around a few methods and ideas to achieve this.

Greets,

Bolle

«13

Comments

  • Quietschboy
    Quietschboy Member Posts: 45 Helper

    Uh, not an easy task!

    What you´re doing in the ens above is adding mouse area pitch values to previously received MIDI pitch values on ALL voices (or vive versa). Gate events from the mouse keyboard are still missing. I guess, depending on the actually pressed notes on the MIDI Keyboard, simultaneously sent Mouse notes just raise the pitch of the played MIDI notes?! Or after playing with mouse, all MIDI input notes are raised?!

    I am sure there are a lot of discussions and solutions in the UL and old Forum depending voice and note handling which might adress your problem. I can´t give you a simple solution but some thoughts:

    • You want to merge two note sources into one output, whereas each input potentially impacts the other input´s state (i.e. pressing note 36 on MIDI, after that on Mouse, then releasing Mouse before MIDI; what should happen?) --> MIDI Merging
    • You need some voice handling. Voices rotate in some strange way in Reaktor. It is not raising from 1 to n, but in a fixed scrambled order, somehow depending on the number of voices. There where solutions in the past to order the used voice from 1 to n. However, if reordering is needed or not, it is definitely important to know if a voice is actually used or free and which is the next one. I.e.: For new pitch value, you need the next free voice, for a already playing pitch you possibly need to cancel this with a incoming note off on the other input source. This includes the need to discard the note off for the same pitch on the first input, when it arrives.
    • All in all, this goes into Array handling, maybe search algorythms and so on.

    Maybe a simple solution would be using the Reaktor internal MIDI connections and leaving the MIDI-Merging up to Reaktor...? Maybe you have to place the Mouse Keyboard into another instrument than the Synth to make internal MIDI work?

    I hope this gives some help, but i am sure some well known collegues will drop in here, getting more precisely 😉

  • colB
    colB Member Posts: 761 Guru

    Look inside the Factory Note In Block. Inside the 'Note filt&prio' macro, there is a 'Note priority' macro. That uses a Primary iterator to drive a process that keeps track of all midi note activity. That way when the currently active note is released, if there are any other active keys, the appropriate one can be chosen as the new active note.

    It's a brute force approach, but seems to work ok. It's possible to implement the same idea, but using a linked list / stack hybrid, then you dont need to search through all the notes each time, but that's not essential.

    I think what you are trying to do is similar but for a poly situation... so that with limited note count, if an active note is released, then some currently held key that was not active can become activated?

    If so, you should be able to use a similar approach, although it might need to be a separate instrument to ensure that the midi handling can be generalised... and then anyone using it will have to set up their instrument to ignore midi inputs except the one from your fancy keyboard widget...

    I'm not sure that it would work well, though - some notes suddenly activating within a chord will be audible, so there would need to be some sort of extra fade envelope, and then you are getting to the point where this uses extra cpu resources, and it's not a widget that can just be plugged into an existing project, but one that must be carefully integrated in order to work properly... not sure it's really worth the hassle.

    I don't remember hearing any complaints about the existing system?

  • Studiowaves
    Studiowaves Member Posts: 451 Advisor

    I guess it's a project but there's nothing like a real weighted action keyboard. You get to play in real time and have a lot of fun.

  • colB
    colB Member Posts: 761 Guru

    I think the main point here is not the graphics, rather the functionality, which would still be relevant even without a fancy skeuomorphic keyboard monopolising screen real estate. Assuming it works as imagined, it might improve the experience of someone using a real weighted action keyboard - or any other kind of hardware control surface.

  • Bolle
    Bolle Member Posts: 349 Pro
    edited July 2022

    Thanks all!!

    I'll have to wait until next weekend to find some time to work on this and try out your suggestions. I knew this wouldn't be easy, but let's try it anyway.

    My latest attempt is very simple and it goes like this:

    61 keys. Each with it's own Multi Picture and Selective Note Gate module. This way all keys work flawlessly, independent of the Instrument voice count. No sticky keys and almost no CPU usage. The Sel. Note Gates don't go anywhere other than the Multi Picture modules.

    So, now everything moves like it should while playing the Midi keyboard.

    The next step (for this tryout version) is to attempt to add mouse button play. It's not strictly necessary (imo) but i know it can come in handy for people. A mouse button can only play one note at a time, so only one event needs to be sent out at any time.

    In the previous version it was obvious that, though everything worked and moved the way it should, all voices were engaged simultaneously when clicking a key and sent to the oscillator. Resulting in a flanged sound. This was due to the Multi Pictures serving as both a display and a control element and creating (i think) feedback loops.

    In this version, mouse button events will come from a separate Mouse Area module (devided into regions by use of a quantizer and A/B comparisons), creating a black box that spits out note values and is totally seperate from the keyboard macro and its 61 Sel. Note Gates. Also sending out just one note at a time. Note values will be fed back into the Multi Picture modules (but not out again) for graphics control.

    This is all a bit labour intensive, but i'll see how far i can get next weekend.

    Thanks all!!

    Greets,

    Bolle

  • colB
    colB Member Posts: 761 Guru

    Are you just trying to get the graphical keyboard to echo the real one independently from the audio functionality?

  • Bolle
    Bolle Member Posts: 349 Pro
    edited August 2022

    No, but i do want to find a way to completely separate the keyboard graphics control from a Mouse Area module that goes on top of the graphical elements, and which serves as the module that takes care of mouse button play and note value output. So the graphical elements, the Multi Picture modules, have no control function and no output.

    My previous attempt had issues with all voices firing at once when a key was played with a mouse click. This way, i am hoping to find a way to solve this issue.

    Greets,

    Bolle.

  • colB
    colB Member Posts: 761 Guru

    Multi display would do that. As long as your key animation frames are all the same size, you can use a single multi display the same dimensions as the mouse area with each key as an object. Just need to do some arithmetic to calculate which key has been clicked based on xy coordinates

  • Studiowaves
    Studiowaves Member Posts: 451 Advisor

    A simple bar graph displaying individual key velocities would be nice. Just a series of meters, one for each key; That way you can visually keep an eye on your velocities. Combine sight and sound offers more feedback. Not sure of the musicians aspect but for the engineer it may be apparent the musician needs more of less volume of his own instrument fed back to his monitor. Like you might notice most velocities are too hard if the musician can't hear himself in the studio. Stuff like that comes in handy.

  • Studiowaves
    Studiowaves Member Posts: 451 Advisor

    Maybe Kontakt would be better suited for this. just a thought.

  • Bolle
    Bolle Member Posts: 349 Pro
    edited August 2022

    Not much progress made (yet), but i think i have a good idea about how to add mouse button control of the keyboard.

    To reiterate: The events that are sent to the oscillator are straight from the MIDI Note Pitch and Gate modules.

    Graphics control (moving keys) is done by a Selective Note Gate for every key individually. None of this goes to the oscillator.

    Mouse button control will feed into both of these levels with a Mouse Area module. X/Y position goes to a macro with Compare / Equal modules, of which the output is a note number. These note numbers have to go through a lot of comparisons again (in order to only send forth 1 note number) and somehow this has to be fed into the note events signal, in parallel with the Note Midi In events. MB (left mouse button) events should go in parallel with Gate events and should also feed into the graphics control.

    This also has to be taken into account: when two adjacent keys are pressed, one does not throw a shadow on the other. Because they're level with each other. This should also be doable with 3 frame animation and Compare/Equal modules.

    That's a whole lot of typing numbers for Compare/Equal modules, for a 61 key keyboard.

    Greets,

    Bolle

  • colB
    colB Member Posts: 761 Guru

    Graphics control (moving keys) is done by a Selective Note Gate for every key individually

    Different to how I would have done it, but probably just as good. Can never tell without testing.


    My first thought would be to use a single MIDI 'channel message' module, and then listen for note-on and note-off messages.

    Use a single multi-display module for the graphics, with an object per key, and whenever there is a note-on or note-off, you just update the animation frame id for that particular 'object'. I imagine some arithmetic will be required to derive the correct key graphic from the midi note number

    One gotcha is that you might need an iterator for initialisation that will set all the keys to their default position. Not sure. Not difficult though.

    The thing with the shadows complicates it a tad. for that you would need to populate an array... so each time you update the graphic id, you also update an array entry... 0 for key off and 1 for key on (one array entry per note). Then you need logic to check neighbouring keys and use a shadow or not on note-ons... and also update the shadow status neighbouring keys on note-offs... still pretty simple though.

  • Bolle
    Bolle Member Posts: 349 Pro

    Thanks for the tips, Colin! I'll check out using the Channel Message module and see what it comes up with. I'm piling so many little things into this build, it will come in handy to see if it works beforehand.

    I'm not very familiar with using Multi Display modules, so i chose a Mouse Area module instead. This way i can take into account that not all keys are the same width (they should be but they're not) and i can merge two regions for keys that have a cut-out in them where a black key is. As far as i can tell, it works really well.

    I did a few tests with simple math solutions for the three frame animations that will make it possible to have no shadows on adjacent keys that are both pressed, and i think i've got it. But it's a lot of work and a lot of extra macros in the build.

    Still a lot of work to do.

    Greets,

    Bolle

  • Bolle
    Bolle Member Posts: 349 Pro

    Sorry for the double post, but does anyone know why a Mouse Area module ignores half the LMB clicks if they come in rapid succession? Like, less than half a second apart? This is very annoying. I'm still trying to build this keyboard macro that is playable with both a MIDI keyboard and LMB clicks.

    I think, as far as building is concerned, i've got this working pretty good. Just that the Mouse Area doesn't do its job properly.

    Greets,

    Bolle

Back To Top