(Supposedly) Same input, different results - MAC Apple Script key codes/keystroke

Hi,

I use BMT in my livesound setup. I am currently trying to automate setting up the different configurations (Window layout of UAD plugins/Tracks Live) with Apple Script. With BMT open, I have a keystroke (as key code) programmed in Apple Script which then launches a timer that is the incoming action of multiple translators (with outgoing keystrokes, mouse clicks and apple scripts) in BMT which are designated to open certain windows and position them etc.

The funny thing is: When I have apple script execute the keystroke, the translators seem to be executed incorrectly (the order is different and it seems that my global variables are also not behaving the way they should). But when I manually execute that same keystroke, everything works the way I expect it to.

Where could this issue be coming from?

 

Hi Karan,

I’ve run into something like this before. I have generally been able to handle this situation by introducing an outgoing delay on the various keystrokes as Bome MIDI Translator Pro is usually much faster in sending keystrokes than any human. The OS just may not be able to handle the input when the simulated keystrokes when they are coming too fast. It is also possible that this is what is happening with global variables. If executing multiple actions against the same incoming trigger, it is possible that the second action fires before the first action changes the value of a global variable you have changed by the first action.

So what I would do is:

  1. Put the translators into the project in the order you want them to fire
  2. Set up a delay with each translator. Each translator should have a delay longer than the one before. I would start with fairly long delays (maybe 1 second) at first and then experiment with shortening them until you find the point that they fire too fast and mess things up.

You could use a global variable for the base delay and then have rules in each translator for the amount of delay inside each one. Keep in mind, not to change the original global variable since as you have discovered, it may not change fast enough for the next translator. So say you base delay is 1000 msec and you put it in global variable “ga”

First translator you would have a delay of ga. (no rule adjust)

Second translator you would have a rule that would say something like pp=ga+500 and then delay the outgoing action with value of pp.

Third translator would have a rule that would say something like pp=ga+1000 and so on so that each outgoing action fires 500ms (1/2 second) apart.

This should also give enough time for the global variable from the first action to change before the second action reads the changed global variable.

I know this might seem to be a lot of work if you have a lot of translators but once you get the timing right initially, you should be all set.

Let me know if this helps and if you have any further questions.

Steve Caldwell
Bome Q and A Moderator and
Independent Bome Consultant/Specialist
bome@sniz.biz

 

Hi Steve,

thanks for your quick response!

I’m afraid you misunderstood my problem. I did run into the issue that you are talking about but fixed it, as you said, by timing the outgoing actions so that they don’t collide. So the sequence of translators is working fine.

My issue is that it seems to make a difference how the initating Timer (which triggers the Translator sequence) is triggered. So my first translator will have the outgoing action [500ms Timer with the name “INIT”] and the incoming action for that translator is the keystroke [Command+Ctrl+Shift+Option+I]. Now if I input that keystroke on my keyboard my translator sequence works the way I want it to. But in the interest of automating the entire process, I want to execute this keystroke using Apple Script:

tell application "System Events" to key code 34 using {command down, control down, option down, shift down}

This does trigger my first translator and the “INIT” timer is sent out. But the resulting order of translators is incorrect and thus my final result is too.

A similar issue occurs when I choose “Project is opened” as incoming action of the first translator. It triggers the timer and should have the same result – but it does not.

Any idea what this might be?

Thanks!!

 

Hi Karan,
Maybe you can post your project file so I can take a closer look?

Steve

Hi Karan,

 

You might want to look at the below excerpt from the Bome MIDI Translator Documentation and determine if this documented behavior is playing a role in your issue.

 

“Timer Initial Delay vs. Outgoing Action delay
Note that for starting a timer, you can specify an initial delay, and there is
also the possibility to specify an action delay (see Delaying Outgoing
Actions). Those two delays add up, but there is a big difference: by delaying
the outgoing action, the timer will not exist before the outgoing action delay
has passed. So during that time you cannot kill or override that timer!
Consequently, you should avoid delaying an outgoing timer action, and
rather use the timer’s (initial) delay.”

Hi Steve,

thanks for all your suggestions. I am only using Initial Delays for timers. But turns out that it is some sort of timing issue after all. I got it to work on one project by experimenting with different timings. However, it still seems a bit out of control and messy at times. I’m guessing there is no way of making one translator wait for the previous one to execute, right? This way it is always a bit of a guessing game, and it seems that when my laptop heats up and performance drops a bit, the timings are again too fast (is that possible?). Also one more question: If an outgoing action is delayed, does that mean that the processing of the rules (transforming variables etc.) is also delayed or does the rule processing start the moment the incoming trigger arrives?

Anyway, I’m 95% there. So as I said, one of my project which results in one configuration works every time. I then duplicated that project and modified a few parameters to result in a different configuration. And this setup works correctly sometimes, and doesn’t other times – regardless of how the delays are set. So I can’t really figure out the problem. I have included more Info, as well as all Apple Scripts, .bmtp files and screen recordings in the link below so you can better understand the issue. It would great if you could have a look! Thanks!!

https://drive.google.com/file/d/1pcE5Xs2hDlyiZJaH-prqs8sG-JLGTlow/view?usp=drivesdk

Hi Karan,

I’ll look at your project a bit later today but here are some answers to your questions in the meantime.

In order to have one translator to wait until another is finished, you can do this:

Translator 1 Start 2nd keystroke timer) – Set a global variable at beginning of rules to indicate it is running. Set outgoing action to fire a continuous timer “WAIT” at a given repeat delay. Timer essentially poll the global variable until it is reset.

Translator 2 Initial Keystroke – Any rules you have (that take time).Clear the global variable and give very small delay before outgoing action. Outgoing action = initial keystroke

Translator 3 Initial Keystroke wait timer – Incoming Action Timer “Wait” at repeat delay. Have it check the global variable in translator 1 and if it is still executing skip the outgoing action. Outgoing action would be the next keystroke which again would not fire until Translator 1 finishes based on the global variable set in translator 1.

Translator 4 – Kill Wait timer Incoming Action “Wait”. Check for global variable in translator 1 to be reset and outgoing actin to Kill Timer “Wait”

It’s not really pretty but I’ve tested this before and it works. Maybe I’ll play with this a bit to see if I can come up with something better. The main idea of course is to use a global variable to clear (keystroke sent) before sending the next keystroke instead of assuming a given delay is enough time. My current issue is it takes 4 translators for 2 keystrokes and if you have a lot of keystrokes, the translators could add up. Maybe I could devise a better way to do this.

As far as rules, delayed, they never are. They always execute immediately. This is why above I use a global variable to set a “wait flag” and a repeating timer to run until the wait flag is cleared.

I hope this helps. Again, will see if I can come up with something more elegant.

Steve Caldwell
Bome Q and A Moderator and
Independent Bome Consultant/Specialist
bome@sniz.biz

P.S. Also just because we wait until the last keystroke before we send the next, doesn\'t mean it might still be too fast for your computer, so in your case here maybe the above will not help anything. You still may need to introduce more delay.

 

 

 

 

Hi Steve,

thanks for the “WAIT” Timer idea, didn’t think of that but it makes sense! I won’t incorporate it into the project just now but will surely consider doing so once I get it working the way I want it to!

Here’s a third project (in addition to the two that I sent in the google link) that I am working on. Here again, I have the issue that if I start everything with apple script, it doesn’t work correctly. But as soon as my apple script has run and I hit the initiating keystroke manually, it works the way it should. Very confusing to me, since apple script is doing nothing other than I am…


Attachments:
1530191654050_BLACKOUT-PROBLEMS_V02.scpt
1530191665374_BP_V02.bmtp

Hmm, just got around to looking at your script.
It looks like INIT is firing off Each desktop in parallel, and that each desktop is doing combinations of mouse and system events (via AppleScript). I’m surprised that it works using keystrokes at all. For instance having left button click at z0,z1 on each desktop in parallel? Is this possible? It seems to me that each Desktop Timer should have different delay so that all of this happens sequentially. Am I missing something?

You say it is working if you do keystrokes manually? I would think the INIT timer would certainly mess things up.

The INIT incoming keystroke Shift(Ctrl(Command(Option(1)))) does not end up trying to initialize each desktop in parallel (resulting if mouse clicks in different desktops at the same time)? This works manually?

As far as AppleScript (I’m a WIndows user), does Key code 19 using {control down command down option down} mean keystroke Control(Command(Option(2)))?

Also, as far as I know, MT Pro will not suppress any incoming keystrokes so is it possible that both MT Pro and some other Mac application is processing the keystroke generated by AppleScript.

Sorry for my ignorance on Mac!

Steve

Hi again, Karan,

 

With some help from Florian, I managed to put the following example together. This example uses an incremental delay for a series of keystrokes.

In this example I use an incoming MIDI message as the trigger. It follows of a timer called “MIDI Trigger1”.

There are a series of translators that process the characters A, B and C in sequence with a 500ms delay between each.

First an “A” is sent with translator 1.1. Then a timer increments the delay to by the value of gk so that translator 1.3 “B” waits gk ms longer before firing. This increment increases for each character so they are 500ms apart.

This sequence continues until the last translator which decreases the delay back down as each character is transmitted resulting back in a delay of 0.

The decrease delay executes the number of times by “gi” which is increased each time a new keystroke is sent to ensure we get back to 0 delay for the next time the incoming MIDI message is received.

Maybe this will be helpful and even you might think about a way to improve upon it.

It only requires 2 translators per outgoing character with a final clean up translator at the end.

The translators need to be in the order you want keystrokes sent in order to work. Each character needs to have a “manage delay” translator between them.

Steve Caldwell
Bome Q and A Moderator and
Independent Bome Consultant/Specialist
bome@sniz.biz

P.S.

Although done with keystrokes in this example, it should work with mouse clicks or any other type of output as well. Just put the sequence of events in the right order along with the incremental delay variable based on the timing between events you want.

 

 

 

 

 

 


Attachments:
1530198938333_Managed-Keystroke-Delay-Example-2018-06-28.bmtp

I’m thinking you might only have the Desktop 4 preset enabled and then when it is done, have a translator at the end to activate the next preset. In the next a subsequent preset you fire of “DESKTOP X” upon activating and so on. At the end, all presets bill be activated.

In the Global Init preset you deactivate all presets except the first desktop. In that way, each preset can be executed in sequence.

Steve

One other thing I happened to think about.

MT Pro default settings is to “Ignore incoming keystrokes when focused”. Please Go to your settings page and make sure that is unchecked if you plan on having MT Pro focused when executing your script.

 


Attachments:
![](upload://rTjP4EXUUmmPFrGBjkj5MKksj8X.png)

Hi, I’ve played around with Steve’s project and optimized it a bit more (no need for the index variable gi). I’ve also added a second input trigger to show how it’s done. Now when pressing both inputs at once, the keys will be sent sequentially per input trigger — so keys from Input Trigger 1 will not be mixed with the keys from Input Trigger 2.


Attachments:
1530223969671_Managed-Keystroke-Delay-Example-2018-06-28_FB.bmtp

Hey Steve,

actually, the INIT is not firing off each desktop simultaneously. The way things are set up, INIT will fire the DESKTOP 4 timer. And DESKTOP 4 will fire DESKTOP 5 in the next preset, but only if the counter variable “gb” of DESKTOP 4 matches the plugin count variable “ga”. Also once gb=ga, DESKTOP 5 has an initial delay which is long enough for all ongoing actions on DESKTOP 4 to finish. And then the same process repeats with all subsequent desktops. So this way the click (for instance the z0,z1 left button) do not happen all at once.

By manually inputting the keystrokes I mean manually pressing down the actual keys for the INIT incoming keystroke as opposed to executing an apple script which key codes this.

Yes, you are right: key code 19 equals the key “2”.

I doubt that multiple apps are processing the INIT incoming keystroke since I purposely chose a very uncommon keystroke by using Shift(Ctrl(Command(Option(I)))). I am certain that no other active applications have actions assigned to this keystroke.

Thanks for your efforts even though you are not familiar with MAC, I appreciate it!!

Karan

Actually, the idea of activating subsequent presets isn’t bad at all! I will give that a try, since it is definitely safer than cascading timers.

If a preset is deactivated, will it mean that incoming actions won’t pass through the included translators at all or does it just mean that no outgoing actions will be sent from those translators? So in a deactivated preset, will Rules be bypassed as well? Because in that case it really might just help!

Didn’t know of this, will uncheck it! Thanks!

Yes, if a preset is deactivated, no translator within it will every fire.

Thanks for the clarification. Sometimes hard to read others coding.

Steve

Hey Steve,

thanks to you and Florian for putting this together for me. This is an interesting approach.

I have modified the project to match my thought process and the approach I used in my projects. Maybe I’m not thinking of an issue that arises with this approach and you might find it in this project.

So instead of cleaning up with a decrease delay after every character, I am using gi as a counter. The counter is being increased by 1 with each translator that outputs a character. All but the first character’s translator have the rule gd=gd+gk, so that their delay is incremented. And once gi reaches a certain value at which all characters have been sent out, a reset translator will reset gi and gd to 0.

This should have the same result, right? Or is there something that happens here which ruins the sequence of the characters?


Attachments:
1530230025580_Managed-Keystroke-Delay-Example-2018-06-28_V2.bmtp

Hi Karan,
In this case, I am the student and Florian is the master. I recommend you follow his sample as he pointed out some flaws in mine. We are all learning at some level.

Regards,

Steve

Hey guys,

sorry for not updating you guys any earlier!

So after quite a bit of trial and error I actually figured out the problem – it was a timing issue after all. So luckily, it was not a problem in the infrastructure of my project. Thanks still for both of your input on the issue, definitely some cool ideas that you guys had which I will keep in my for future projects! For now, I am still using an index variable to manage outgoing delays but because I also need an index for other things (mouse positions etc.) as well. So here’s why my results where inconsistent throughout projects even though the timing of the outgoing actions was identical:

When building the project, I obviously tried out the timings with only one setup (one UAD Console file). I used minimal timing gaps (as low as 10ms) between outgoing actions, so that the entire sequence of keystrokes/scripts would be execute as quick as possible. These timings delivered the right end result with that specific UAD plugin setup but as soon as I changed the setup (so a different UAD console file was loaded with a different amount of plugin windows to be opened) the workload for my CPU must have differed ever so slightly but enough to have the timings be too short. I am now using one global variable as main delay increment and just using multiples of that for the delays between outgoing actions, this way I can quickly increase or decrease the gaps between all of my actions.

On top of this came the fact that, apparently, keystrokes (key codes) from the Apple Script Editor seem to have a certain “release” time and during this time the system seems to reject any other incoming keystrokes. So when the keystroke that starts the INIT timer in BMTP was executed by apple script, the first outgoing keystroke from BMTP did not have any effect. I sorted this out by increasing the initial delay of the INIT timer to 350ms.

Now everything seems to work just fine, hope it stays that way! Sorry for causing so much confusion, it just seemed illogical for me that an essentially identical project would cause a different result, turns out I just forgot to include system workload in the equation.

Anyway, thanks so much for the great support and thanks for making a cool product!

Btw: I think it’d be cool if you showed some examples of using BMTP as a “batch commander” (without even necessarily needing MIDI) on the YT channel, there must be many people for whom this could be useful!