Long "for each" loop issues

I have a long "for each" loop that executes a lot of actions on each file in the Finder's selection, including several small text actions like typing, copying, pasting, and clipboard-dependent things. It automates a process of creating instrument patches in Logic Pro. The macro starts becoming sluggish (beach balls start appearing) after maybe the 100th file (possibly sooner). Eventually, it starts missing things. With the template I am creating patches with, there are 12 "smart controls" that get renamed. Usually, it will get the text of each one, run a test (a submacro), and then replace the text it found with something short based on the results of that test. When it gets really bad, it ends up getting 1 smart control behind (that is, instead of typing the short string into the label for smart control #1, it will type it into the label for smart control #2, and everything after is offset), with unusual amounts of beachballing.

I read up on this general issue and tried inserting 1 second pauses after each cmd+C and cmd+V action, but the problem still occurs. Then I came across this When Do I Need a Pause from the wiki.

So my next idea will be to add Pause Untils for clipboard events to not proceed at a certain step until the clipboard has changed. But I want to understand the last bullet point more, since I think that is most applicable to my situation. In what way should I insert a pause at the end of the long loop? Should I just put a Pause of arbitrary length after the last action in the loop? Or is there a way to use a Pause Until to make sure all the actions of the loop have finished and it's ready to move onto the next selection in the finder?

Roughly, here's what the macro does:

  • for each Path in Finder's selection
    • count all the files that have a green-tagged parent folder to help estimate how long the whole macro will take
  • for each Path in Finder's selection
    • open the file in Kontakt, a plug-in within Logic, adjust some settings based on where the file came from, rename smart controls as mentioned above
    • save the adjusted file as a patch and move the file from its default save location to a new save location (while deleting any previous version of a patch that may already exist there)
    • display notification of how many files have been completed and an estimate of what time it will finish, based on how quickly the most recent patch has been created

Thanks for any suggestions on how to make this run reliably! Ideally, it should be able to run on hundreds of files without user input and without "falling behind."

Lets start with “beach balls start appearing”. Beachballs happen when the system or an application is so under load that it cannot process events. So this isn’t necessarily (or even probably) Keyboard Maestro becoming sluggish, it is most likely that the Mac or the target applications are being overwhelmed by the continuous sequence of tasks.

Keep in mind that applications (and the system) are not written to expect you to type and click and change applications and what have you continuously not stop for long periods of time, so it is generally not a normal or tested scenario.

In my experience across a large range of automation situations, it is good to periodically (every couple minutes maybe, it depends on the task) give the system a longer rest to allow caches to be flushed, disks to be written, network traffic to complete, etc.

So what you might try is something that basically does a long pause every say 50 iterations of your loop. If you are working with a single file (say making continuous changes to it), this would be a good time to do a Save, or even to Save & Close and Reopen the file. Sometimes you can even quit and relaunch the target application to really allow it to start afresh.

As far as how long the pause is, it is difficult (almost impossible) to detect that the system is falling behind, and equally difficult to detect when it has caught up, so it is very hard to know what to suggest as far as the length of Pause or the condition to Pause Until.

1 Like

Thanks for pointing out the heart of the issue.

I am away from the machine I'm working on this macro on, but I am trying to think of how to periodically give it a break. Here's what I'm thinking – please let me know if you have a better method. I'm going to leave off the first "for each" loop (counting files), because that is an extremely simple loop.

for each Path in Finder's selection
  set variable loopCount to text "0"
  do all the actions
  set variable loopCount to %Calculate%loopCount + 1%
  if
    loopCount < 50, do nothing. otherwise,
    give Logic a break (long pause/close & reopen/etc)

Yep, something like that. Or more completely:

  • set variable LoopCount to 0
  • for each Path in Finder's selection
    • do stuff
    • set variable LoopCount to LoopCount + 1
    • if LoopCount > 50
      • set variable LoopCount to 0
      • give Logic a break

Ah right – start at 0 outside the loop. That'll do it. Thanks!

I’m surprised nobody has used the term “pacing” in this thread. But that’s effectively what the solution is.

What do you mean? Would that just be putting longer pauses in between every action?

Potentially, yes.

@acap - as a longtime Logic user but newcomer to KM, I'd love to see that macro if you're willing to share it. I'm gathering that you're using it to deal with the issue of unusably (unviewably) long labels on the Smart Controls for various Kontakt instruments, yes?

That's part of what I'm using it for! I created that macro (which works flawlessly now, by the way, thanks to @peternlewis and @MartinPacker) for a composer I no longer work for, so I don't have access to the macro anymore, sorry! However I'll try to push you in the right direction...

  • You need the Smart Controls "info" window open.
  • Loading from Kontakt is simple – use KM to "click at center of found image" to select the floppy disk icon
  • Use the "Path" of the current file combined with Finder's "Go to..." shortcut.
  • One big hurdle is click location...
    • I have KM click the text above each smart control knob to select it so as to not inadvertently change the knob's value while the macro runs.
    • After that, selecting the knob's text in the info window and then changing it (more on this later) or deleting the knob if it's unused is pretty straightforward
    • Unfortunately, the Smart Controls are not fixed relative to either the bottom left or bottom right corner of the window. Hopefully you'll always run this macro on the same system so it'll stay reliable, but for modularity and just in case your Logic window isn't always the same size, I recommend saving the mouse position of the 1st smart control to a variable and then adding to those x & y coordinates to reach all your other smart controls.
  • As far as renaming the controls goes, you're basically copying the name to the clipboard, looking at the clipboard, changing the clipboard text based on a bunch of rules you determine based on how you want your controls renamed, and then pasting back in the newly modified clipboard text. You can use variables here instead if you want.
    • Learn Regular Expressions! This is invaluable when creating your renaming rules. Then use search and replace using regular expressions.
    • A "Switch" is cleaner to use when creating your rules than using a bunch of if/then actions. If you like, you can further nest switches, or nest if/then actions inside the switch.
  • I use CLIPBOARDSEED when copying to the clipboard to make sure the computer doesn't get ahead of itself.
  • Be sure to leave sufficient pause time for any click actions or events that are accompanied by an animation.

That should get you started!

Awesome, thanks so much! Tons of excellent tips that will help me with many other ideas I've had.

It might be a minute before I get a chance to give this particular macro a go, so don't wait up. :wink: But I greatly appreciate your response!

As I suspected, I couldn't help myself and started working on replicating this, this morning. It's a productive way to start learning KM. I just have to limit myself to 30 minutes per session so that I don't get so "in the zone" that I neglect paid work! :slight_smile:

Yes, creating a macro for a need you already have is a great way to learn KM, as you'll figure out different ways to accomplish your goal and figure out solutions to Macro issues as you troubleshoot along the way.

I have the same problem! And when I revisit a macro a year later, I see obvious things I could have done to improve it, but often need to resist the urge to tweak it, otherwise I'd never finish it!