Two Triggers, One Macro, Sequence of Events

If I have a macro with two triggers (Trigger A and Trigger B), and the macro starts because it was triggered by Trigger A, what happens if a trigger from Trigger B comes in midway thru the macro running? At a fundamental level, I'm just trying to understand how this stuff functions in the background within KM.

  1. Does the macro continue running until it's done, and then start again because it was triggered by Trigger B, and is waiting in a cue to run a second time, once the macro is done running to completion the first time?

OR

  1. Does the macro quit where it's at immediately, and then immediately start over because it was triggered by Trigger B?

OR

  1. Does the trigger from Trigger B just get swallowed, as if it never happened, and the macro continues running until it's complete. No second run of the macro happens.

OR

  1. Is there some other way that it functions, that I haven't already mentioned?

Yes: the macro triggers again when B happens while the first instance (triggered by A) continues until its end. So you basically have the same macro running twice concurrently.

If you don't want that to happen, then you need to use a KM Semaphore action - look it up in the KM wiki.

1 Like

Ok. So Trigger B doesn't cue up the macro to run a second time consecutively, AFTER the macro is done running to completion the first time. It just fires the macro to run a second time, concurrently, regardless of whether the first macro run has completed or not.

Correct? Just making sure I understand you correctly.

I'll look into the semaphore thing. I'm aware of semaphore lock, but I haven't thought about it in this context.

Yes, correct.

If you want to queue up the second instance triggered by B so it runs after the one triggered by A, you need to use the Semaphore action. More info in the KM wiki here action:Semaphore Lock [Keyboard Maestro Wiki]

The semaphore will also let you stop the second triggering happening too, if that's what you want.

1 Like

Perfect. Thanks

So I've read about the use of semaphores and, from what I can tell, I'm not sure it will do what I want.

What I would like to be able to do is always have the latest trigger be the one that runs the macro. Because of what I'm using this for, there may be multiple triggers of this macro in a very short time period, so I want all instances of this specific macro to cancel except for the most recent one, every time a new trigger comes in.

It seems like semaphore works the opposite way. It can cancel or pause/cue subsequent instances of the macro, but not the other way around. I don't want to cancel or pause subsequent instances. I only want the last instance to run, cancelling all instances that came before it.

It's going to be difficult to give you advice without a better understanding of your actual use case. Specifically, what is the macro doing that it needs to be cancelled if it is triggered again? And if it has been triggered by A will another triggering by A result in the currently-running instance being cancelled?

It may be that there's a better way to structure your macros if you give us a fuller picture!

1 Like

This involves MIDI triggers. The macro (Macro 1) being triggered by a specific MIDI message(s) then subsequently sends a different set of MIDI update messages back out of KM to my DAW. This outgoing MIDI message tells the DAW to then send a subsequent SYSEX message (these are used for displaying characters for names) out to KM. I then use a different macro (Macro 2) in KM to translate this SYSEX message, via a look up table and shell scripts, and ultimately send it to a "Set Stream Deck Title" action, which then updates the buttons on my Stream Deck, This is all essentially happening in real time.

MIDI Trigger (Trigger A, Trigger B, etc.) > Macro 1 > MIDI Update Message > DAW > SYSEX Message > Macro 2 > Stream Deck

It's a bit circuitous. That's why I didn't mention all of this before. In addition to all of this, Macro 1 also directly enables/disables Macro 2, to act as a gatekeeper for when it can or can't accept MIDI messages. It's a bit complicated, but it DOES all work. The only issue that arises is if too many MIDI message triggers come into Macro 1 at once.

In any case, Macro 1 is what I'm concerned with. Given that multiple MIDI message triggers can come in quickly, in a very short period of time, I don't want multiple instances of Macro 1 all running at the same time because, if they are, they will cause issues with the translation going on in Macro 2, as described above.

So, is there a way to always cancel all instances of Macro 1 except for the most recent one? Basically, any time any one of the triggers for Macro 1 starts a new instance of Macro 1, I want all previous instances of Macro 1, that may be still running, to cancel. In a lot of cases, the previous instance of Macro 1 will have already completed, and it won't matter but, for those cases where one or more instances of Macro 1 are still running, I want to cancel all of them, except for the newest instance that just got triggered.

Since every new instance would cancel the previous instance, I basically just need it to cancel the previous instance because, even if 10 triggers all happened closely together in time, iinstance 2 would cancel instance 1, instance 3 would cancel instance 2, instance 4 would cancel instance 3, and so on and so forth.

I think that could be done like this:

Macro 1.kmmacros (5.2 KB)

1 Like

Won't %ExecutingInstance% identify that very same macro (the most recent one) that I want to keep?

In other words, won't this just cause the macro to cancel itself? Or is %ExecutingInstance% actually identifying the previous instance of the macro?

EDIT:

Oh, wait. I maybe get it now. Because the variable VAR_Macroinstance is set in the previous instance, but after the cancel macro action used in that previous instance, that variable is always set to the instance ID from the previous instance.

And then, when you the macro triggers again it's always cancelling the previous macro because that's what the variable is set to at that point in the action sequence. It only resets the variable to the most recent instance ID AFTER the cancel action has already taken place.

Am I understanding you correctly? If so, I think that might actually work.

@Zabobon's approach looks like it'll do what you’re asking but the ramifications of cancelling a macro somewhere in the middle of its execution are too complicated for me :wink:

it's actually no biggie to cancel Macro A in the middle. All it's doing is sending some simple MIDI messages out to my DAW. And the very first action in this macro is send a "reset" message to the DAW, before it even receives any of the subsequent messages. So it's always starting from a clean slate, regardless of where the previous instance of that macro may have quit.

Yes. The cancel action happens and then the instance is saved to a variable. So, the macro will not cancel itself as it will be a new instance and save a new value to the variable.

Great. I think that will work for what I need. I'm already having some other ideas for where else I might use this. It's simple and elegant. I like it. Thanks

So I'm trying this out, and it seems to work, with one caveat. You have to initialize the variable by disabling the "cancel" action, running the macro, and then enable the "cancel" action again.

Once you do that, it seems to work.

Any ideas on how to automate something like that? I haven't played with it yet, but I was considering just putting and if/then in there that says, if that variable is empty, assign it a value of "1". Not sure if that will work though.

Okay. A way to automate that is to use in If Then Else Action to only run the cancel action if the variable is not empty. I've updated my example to a new version in my original post to show this.