To test the "Until" action Macro (v11.0.3)

Hello.
I am trying to build a macro for executing in my MBP Music app (not the streaming but the one physically “living” in my laptop). That’s the beginning:

  • 1- Play the top song on a playlist. Play for some seconds
  • 2- Skip forward a bit and listen for some seconds 4 times
  • 3- Stop playing the song and play sound glass.
    This sequence works perfectly, but I wanted to be able to stop this after, let’s say the 2nd time, therefore I included them in an “Execute actions until conditions met”. It didn’t work, so I tried an “Execute actions while conditions met”. The same.
    The problem is that, if I press the “condition” (in this example 2 modifiers) it doesn’t stop immediately, just ignores the pressing and stops only after the 4th skip forward. (And also, I need to press continuously and eventually, after the 4th skip it works).
    One more thing: when I test the condition (while editing the macro) and press the modifiers it shows immediately "currently true".
    Am I doing something wrong or is it just that KM doesn’t like me?
    Thanks for any insights.

To test the "Until" action Macro (v11.0.3)

To test the "Until" action.kmmacros (16 KB)

The way you wrote the macro, the abort test occurs only after the end of the fourth skip. This isn't what you want, but that's what you coded.

The simplest way to fix it, which I'm not sure if you will like, is to simply "abort all macros" when you press a hotkey. That way it will stop no matter which part of the macro you are on. Here's my macro for doing that.

If you add this macro, and press the key, the macro will stop regardless of what it is doing.

There are other ways to fix this, so if you aren't happy with this solution, I can propose other solutions.

One of the other ways to solve this is worth mentioning here. (This is only part of the solution, but it's an important part worth mentioning.) If you want to be able to press a key that will abort a macro while it's "pausing for 2 seconds", you can do this:

But note the following, you have to set the timeout settings for the loop action as follows:

And of course, instead of placing this everywhere you want to pause for 2 seconds, it's probably better to put this code into its own macro, like this:

If you do that, that will probably be 95% of what you need. Or maybe I've misunderstood the problem... let me know.

Thanks for your reply Airy.
You didn't misunderstand my question, I probably "misexplained"...
I don't want to cancel the macro. This part is just the beginning of it.
What I am looking to do is: to listen to a song for some seconds and after that decide what grouping I will add it to.
Since this macro here is just the beginning I ended it with "stop the song" and "play sound glass".
If I get it to work the way I want, AFTER I finished listen to it, instead of playing glass, it will ask me which grouping it will "go" to.
If I take all the actions out of the "Until" action what I will get is the beginning of my macro, which will let me listen to 4 parts of the song and then let me decide what grouping it will belong to.
I am trying to have an option of not to have to listen 4 times to the 4 parts. Sometimes after the 1st 2 seconds I know which group it belongs to, then I want the macro not to "make me" listen 2 more times, but right away to let me choose the grouping.
I hope this time I succeeded to explain better. :sweat_smile:
Thanks for your patience!

Okay, I've read your comments several times, and I'm (hopefully) starting to understand. I think I understand.

You've written only part of the macro so far, the part that plays four pieces of the song. Then you want to have the macro let you decide which "group" (do you mean "playlist"?) to move the song into. Basically, these are two separate problems that we can tackle separately.

Let's deal with the first part first. You want a macro that will play four pieces of a song, but let you abort those four pieces if the user presses CTRL+CMD. Your code deals with the playing of the four pieces, and it works, but it doesn't let you abort that playback. I can see the problem, and the solution is almost exactly what I already suggested. The problem is that you are hardcoding pause statements and during the pause statements you aren't checking to see if the user is pressing CTRL+CMD. Well, we can fix that using the technique I proposed above, with a tiny modification. Did you see where my code said "Cancel This Macro"? All we have to do is change that to "Cancel Just This macro" and it will return to the parent macro without terminating it. So I was close. But I made a small change and I've fixed it.

Once you get this first part working, we can move to the next part.

Now personally, since you have four identical pieces of code, (to view four pieces of the song) it would be much smarter to create a loop of four occurrences than to write code four times in succession. So I've done that.

Also, there is probably a way to jump ahead in a song, without using the mouse, but it requires the use of AppleScript. I found a web page that explains how to do this, but we can still do it with the mouse. I'm not good with AppleScript, but maybe someone will advocate for it. But my method still works.

By the way, there's a much better way than aborting the routine than using CMD+CTRL. If you notice, the play bar for Apple Music is always on the same horizontal level. So if the user moves the mouse up or down, that could be the "signal" to abort playback. That's what I would do. As a compromise, my solution lets you abort EITHER by pressing CTRL+CMD or by moving the mouse up or down from the playback line by more than 10 pixels.

You will need two macros. One macro will be a subroutine to pause for two seconds, while waiting for the user to cancel with either the modifiers or the mouse, like this:

The second macro will call the above macro like this:

Notice that what the above macro does is start the song playing, then play four pieces of the song, but let the user abort either by pressing the modifier keys or by moving the mouse up or down.

This works for me. I suspect you will like it also. If you do, we can move to the second half of your problem.

P.S. Don't forget to set the timeout values of the loop as I indicate in my second post.

That's because in the Editor KM is always "looking" to see if the keys are down. In your macro, as @Airy says, it only checks at the end of the loop -- once every 10 seconds.

Even if you check for a "stop" condition before every skip in your loop you'll still have, on average, a 1 second wait -- and, as you've found, you have to keep the keys pressed until the macro un-pauses and they can be registered.

IMO the best way to do what you want is to have this macro play and skip while a global variable has a certain value plus a second macro to change that global when you want to finish with the current track.

Note that your loop shouldn't be a loop, based on your requirements -- at no time do you want to "after the fourth skip go back and double-click the top song". You might as well write it as a series of actions (although you could, as I think @Airy has, treat it as a 5x loop of a single "Move and Click" action, each loop using different coordinates).

I've left the demo as a "series" because:

  1. It's easier to how see your original actions have been put into the new "structure"
  2. Loops-in-loops can be a bit brain-bending
  3. It shows an obvious repeating flow that can be converted to a loop (consider it homework :wink: )

To test the "Until" action with a Global.kmmacros (30.9 KB)

Image

Stopper.kmmacros (1.6 KB)

Image

"To test..." is the main macro and "Stopper"... stops the skipping. "Stopper"'s hot key is currently ⌥F7, so change to your preference. If you look you'll see the "stop" response has a resolution of 1/10th of a second, which you can change to suit your needs -- remember to set the "number of loops" test so you still get 2 seconds per skip.

Hi Airy.
I must tell you that I am in awe of your commitment and the effort you’ve made, first to help me with a solution, but not less by the way you explained to me, so I can understand and LEARN (which is HUGE to me). i take my hat off to you!!!

I will try “to digest” everything, try your way and get back (warning! It may take several days but I won’t forget or leave it as it is)… :smile:

Hi Nige_S.
First let me thank you for your help. Very much appreciated!
I will repeat what I mentioned to Airy: I will try “to digest” everything, try your way and get back (warning! It may take several days but I won’t forget or leave it as it is)… :smile:

I think you just made my day. Thanks.

It's always a balancing act between "giving people a solution" and "teaching them how to solve a problem themselves." There are times when I lean too far in one direction and it doesn't work out.

1 Like

Before I start re-building a macro I re-read your reply.
What I do: I wanted to have a playlist with slow/quiet songs.
When I listened to my songs, those that were quiet/slow I opened it's info tab and in the "grouping" field I wrote "Quiet".
Than I created a playlist with a rule "Grouping>contains>Quiet".
Time passed and I added 3500 songs. Now I have 8500 songs, part of them quiet.
I created a smart playlist with a rule "Grouping>does not contain>Quiet".
I listen to all of them, one by one (here is where the macro starts, by listening to several (4) parts of the song to determine if it IS quiet or not, but sometimes I, after the first 2 secs I know it is, so I don't need to listen to the rest).
When I'll be done with this part I will go on and add an "If then else" part that will edit the info song and paste the word "Quiet" in the "grouping" field/tab.
Hope I made things clearer...

If you had mentioned that earlier I might have proposed a different solution for you. You don't have to do any of this manually. Every song in Apple Music has a field called "BPM" which means Beats per Minute. If your songs have this field populated, then you can infer that any song under a certain number is a "slow" song. If your songs do not have this field populated, you can get software that will populate the field for you. Either way you can create a Smart Playlist which is defined as "all songs under a BPM of X".

Using this method, all the work you are trying to do for 8,500 songs is done fully automatically and quickly.

The volume of a song and its BPM are different things. But you did say "slow/quiet" songs which means you recognize there is a correlation between the two.

But now we can also consider how to measure and record the volume of a song automatically, with even more precision that a subjective "quiet" flag.

What I would do is auto-populate the BPM field of every song with an autonomous utility, and then I would probably use the "Rating" field, which has a value of 1 to 5 to specify the volume of the song from 1 to 5. This would mean you would lose the ability to "rate" music, but you would gain some real benefits for smart lists.

For 8,500 songs, I would certainly use software to automate the process of determining the volume. I'm pretty sure that you could use Audio Hijack to determine the volume of a song, and by using a KM macro to control Audio Hijack, it should be possible to measure and record the volume of all 8,500 songs automatically, with no human work at all.

If you do these things, you can create a Music smart list that can filter based on both BPM and volume of a song. That could lead to some interesting smart lists.

Given your objectives, here's another approach—@Airy's method is an excellent one if you just want to quickly categorize everything (and it's the way I'd do it myself, I think). However, here's another method to consider if you actually want to listen to (parts of) all those tracks as you're categorizing them.

Have one macro that does nothing more than skips three (or however many) seconds in the currently playing track. That macro is a simple Execute AppleScript action, with this code:

tell application "Music"
	set player position to player position + 3
end tell

Put that in a group that's only active within Music, and assign it a very simple shortcut, like Control-A or whatever. Start your playback, and use Control-A as often as necessary. Create a second macro in the Music-only group; the second macro will set the grouping as you're listening to the song. It's probably a two-step macro. Step one is an AppleScript:

tell application "Music"
	set grouping of current track to "Quiet"
end tell

Step two is the Keyboard Maestro "Next Track" action, so it'll skip to the next track after you categorize the current song.

Also give this macro a simple shortcut, Control-Z or whatever. Now your process is just this:

  1. Start playback
  2. Press Control-A until you know if it's a quiet song or not.
  3. If it's a quiet song, press Control-Z.
  4. If it's not quiet, skip to next song—use your hardware keys on your keyboard, or add another macro in the group that's just the Next Track action.

With these two very simple macros, I think you could do what you're trying to do. It doesn't try to be overly complicated about skipping and stopping and starting again, which gets quite complicated. Just listen, skip as needed, and apply "Quiet" when needed.

With all that said, I'd personally take @Airy's approach, at least for a first pass at 5,000+ songs!

-rob.

Good idea, combining my automated approach as a "first pass" and then doing a manual review.

I'm sorry, my terminology again!!! (I try to make something clearer and I mess with something else)... :rofl:
What I meant is a song that is a quiet one (e.g. "Silent Night", "Hey Jude" (Beatles)) comparing to "Working On The Highway" (Bruce Springsteen).
Although I will have to reread your reply because you bring some other stuff that can answer other questions I didn't ask (BPM/volume).

In the meantime, @Nige_S I started trying your macro/stopper and so far I think it works for my needs. (Although I still need to go over it to try to learn/understand how it works because this is an "unexplored area" for me, which I will be more than happy to explore!)

Rob, thanks a lot for your input. Although I prefer to use "pure" KM because anyways I'm just scratching the surface of this wonderful program/software, but at least I know how to modify a macro, comparing to AS which is completely new to me. But, from the other hand what you suggest sounds pretty basic and simple to me, so maybe the best way will be to combine the suggestions...

Now I'll "take some days off" the forum, try to understand/implement what has been said and will be back when I'll stop scratching my head.... :rofl: :rofl: :rofl:

You'll eventually learn that you can make KM do some pretty amazing things by consider that its support for HTML custom prompts, shell scripts, Javascript, and AppleScript are still "pure" KM, because it's doing all the work for you—they're actions just like any other actions in KM, but open up a whole world of new possibilities.

Yes, it can be intimidating, which is why it's good to start slowly. And I wouldn't have offered this version if the AppleScripts weren't so simple.

However you go forward, the one part I would urge you to consider is to use AppleScript to write your "Quiet" value directly to the field. Copying and pasting, even via a KM macro, will be a real pain compared to one line of AppleScript :). And it's much more efficient to catalo the song as you're listening to it than to have to go back later.

-rob.

With just a few actions I could probably calculate both the volume and the BPM (tempo) of any song just by using Find Image and this pane in the System Preferences:

And then I would use AppleScript to save the tempo and volume in the song's settings.

The volume calculation could be done in two KM actions, and the BPM wouldn't take much more than that.

Here's a macro that calculates and displays the average volume of a song using the Sound meter:

Sound Meter Macro (v11.0.3)

Sound Meter.kmmacros (12 KB)

Calculating the BPM using this method would probably take the same number of actions, but would have a more complex calculation.

I missed this bit...

Do you actually need to listen to them? Never used it myself, but a quick google led me to an utility called sox, which seems to be able to summarise a track's volume: Audio: determining volume of music file - #2 by Axel_Schneider - General - Xojo Programming Forum

So you could make your own definition of "quiet" and "loud", then use AppleScript to get sox to analyse each of your playlist's songs in turn, check the summary against your definition, and tag the song accordingly. sox is available via Homebrew (sox — Homebrew Formulae).

"Slow" will be more difficult. If you're lucky that info is already included in the file's metadata (view the song's "Info" in Music to check). Otherwise check out aubio, also available through Homebrew (aubio — Homebrew Formulae) -- again, not a user, just a googler.