No internet connection
  1. Home
  2. Macro and Script Help

ClipBeGone (delete when clips shorter than length).

By Brenden @nednednerb
    2022-10-21 21:02:27.813Z

    Title

    ClipBeGone (delete when clips shorter than length).

    What do you expect to happen when you run the script/macro?

    This script is for clearing clips shorter than 8000 samples long, as they are created accidentally by my editing workflow and are time consuming to find manually. I expect the script to select each clip, to create a variable of selectionLength, and to do a comparison of var

    Are you seeing an error?

    What happens when you run this script?

    Everything seems to work properly regarding moving through each clip on the timeline in my track. However, the clips under 8000 samples are not deleted. These lines seem to be ignored or not valid:

    if (cliplength <= 8000) {
    sf.keyboard.press({ keys: 'delete' });
    }}

    But there is no error, and the function carries on.

    How were you running this script?

    I used a keyboard shortcut within the target app

    How important is this issue to you?

    3

    Details

    {
        "inputExpected": "This script is for clearing clips shorter than 8000 samples long, as they are created accidentally by my editing workflow and are time consuming to find manually. I expect the script to select each clip, to create a variable of selectionLength, and to do a comparison of var 
      

    Source

    
    sf.keyboard.press({
        keys: "cmd+a, alt+shift+h",
    });
    
    sf.wait({
        intervalMs: 32,
    });
    
    sf.ui.proTools.windows.whoseTitle.is("Space Clips").first.popupButtons.first.popupMenuSelect({
        menuPath: ["Samples"],
    });
    
    sf.keyboard.type({
        text: "24000",
    });
    
    sf.wait({
        intervalMs: 256,
    });
    
    sf.keyboard.press({
        keys: "return",
    });
    
    sf.wait({
        intervalMs: 32,
    });
    
    function checkClipLengths() {
    sf.ui.proTools.clipSelectNextFullClip();
    
    sf.wait({
       intervalMs: 32,
    });
    
    
    var cliplength = sf.ui.proTools.selectionGetInSamples().selectionLength;
    
    sf.wait({
       intervalMs: 32,
    });
    
    if (cliplength <= 8000) {
       sf.keyboard.press({ keys: 'delete' });
    }}
    
    sf.wait({
       intervalMs: 64,
    });
    
    sf.ui.proTools.clipDoForEachClipInTrack({
       action: clip => checkClipLengths()
    });
    

    Links

    User UID: hMEBO84NZbXqVbqYJzU5ZyTNHGN2

    Feedback Key: sffeedback:hMEBO84NZbXqVbqYJzU5ZyTNHGN2:-NEwLfatgH9yjU4yEIZ1

    Feedback ZIP

    Solved in post #3, click to view
    • 8 replies
    1. Brenden @nednednerb
        2022-10-21 21:24:06.310Z

        By the way, everything above the "function" is an attempted work around to try spacing the clips then doing the function. It seems to do the same thing with or without, and the clip does not delete.

        A fancy aspect to this, is before I created the function to make the operation repeat through EachClipInTrack, the script worked when tested and selected the NextFullClip, deleted it, and did not carry on. Making it carry on, something happened.

        I forget what else changed since that one moment!

        1. In reply tonednednerb:
          Raphael Sepulveda @raphaelsepulveda2022-10-21 21:39:13.289Z2022-10-21 22:33:07.230Z

          Hey @nednednerb,

          Give this a shot:

          sf.ui.proTools.appActivateMainWindow();
          sf.ui.proTools.mainWindow.invalidate();
          
          sf.ui.proTools.mainCounterDoWithValue({
              targetValue: "Samples",
              action: () => sf.ui.proTools.clipDoForEachClipInTrack({
                  action: () => {
                      const cliplength = sf.ui.proTools.selectionGet().selectionLength;
          
                      if (cliplength <= 8000) {
                          sf.ui.proTools.menuClick({ menuPath: ["Edit", "Clear"] });
                      }
                  }
              })
          });
          
          Reply1 LikeSolution
          1. Brenden @nednednerb
              2022-10-21 21:53:32.040Z

              Hi, that works perfectly.

              Now I am curious why mine almost worked but didn't quite delete. Even if my code was more cumbersome, I'd be highly interested in understanding where I went wrong and why your solution was foolproof. I pieced together some tutorials and I'm very much a javascript newb.

              Understanding where my script went wrong and how I could fix it, even if not optimal, would be good for learning.

              By the way, while waiting for your response, I got my script to this point:

              function checkClipLengths() {
                 sf.ui.proTools.clipSelectNextFullClip();
              
                 sf.wait({
                    intervalMs: 32,
                 });
              
              
                 var clipLength = sf.ui.proTools.selectionGetInSamples().selectionLength;
              
                 sf.wait({
                    intervalMs: 128,
                 });
              
                 if (clipLength < 8000) {
                    sf.ui.proTools.menuClick({ menuPath: ["Edit", "Clear"] });
                 } else { log("error") }
              }
              
              sf.wait({
                 intervalMs: 64,
              });
              
              sf.ui.proTools.clipDoForEachClipInTrack({
                 action: clip => checkClipLengths()
              });
              

              When I run this version, I got 3 errors. Which since I ran the macro with 3 long clips and only 1 clip 1600 samples long, It is seeming to say my variable and comparison were true once, but I did not get the delete.

              Very interesting...

              1. Yeah, no problem.

                The main thing messing with your script is sf.ui.proTools.clipSelectNextFullClip();.
                That line is not necessary since sf.ui.proTools.clipDoForEachClipInTrack() is already going through each clip for you.

                Below is your script with the things it doesn't need commented out. You were very close!

                function checkClipLengths() {
                    // sf.ui.proTools.clipSelectNextFullClip();
                
                    // sf.wait({
                    //     intervalMs: 32,
                    // });
                
                    var clipLength = sf.ui.proTools.selectionGetInSamples().selectionLength;
                
                    // sf.wait({
                    //     intervalMs: 128,
                    // });
                
                    if (clipLength < 8000) {
                        sf.ui.proTools.menuClick({ menuPath: ["Edit", "Clear"] });
                    } /* else { log("error") } */
                }
                
                // sf.wait({
                //     intervalMs: 64,
                // });
                
                sf.ui.proTools.clipDoForEachClipInTrack({
                    action: () => checkClipLengths()
                });
                

                A couple pointers for future reference:

                • Start your scripts with these two lines to avoid a myriad of bugs
                sf.ui.proTools.appActivateMainWindow();
                sf.ui.proTools.mainWindow.invalidate();
                
                • Avoid keyboard shortcuts. Use sf.ui.proTools.menuClick(); to find a menu item equivalent, when possible!
                1. Brenden @nednednerb
                    2022-10-24 22:25:42.356Z

                    Hi Raphael,

                    Thank you for your pointers. Regarding .menuClick() that makes total sense. I was having some issues with UI clicks and KeyPresses that needed Wait time and could be a bit "click or miss", Using Menu options seems to make more sense for items which exist on the menu! I can see there could still need to be Wait time for some options here, and some places where UI clicks are needed but less optimal.

                    The other pointer you make regarding appActivateMainWindow and invalidate:
                    As a guess, even when Finder might be focused on PT, maybe some Audiosuite plug-in etc is open, or some other dialog or input field is active, the first line about appActivateMainWIndow sounds like it focuses on the Edit Window.

                    However, I am less clear on mainWindow.invalidate. It sounds like invalidate on a sf.ui call means some kind of "clearing" of some other parameter.

                    If you know of a lengthier article or another thread which gets into explaining to add these two lines in more detail, please share a link and happily be lazy about responding at length here

                    : )

                    1. I can see there could still need to be Wait time for some options here, and some places where UI clicks are needed but less optimal.


                      Yes, best practices is to implement dynamic waits—using elementWaitFor()—instead of static ones—sf.wait();

                      For example, the snippet below clicks on the output button of the selected track using UI automation and waits for the output window to show up:

                      sf.ui.proTools.selectedTrack.outputPathButton.elementClick();
                      sf.ui.proTools.mainTrackOutputWindow.elementWaitFor({ waitType: "Appear" });
                      

                      Doing it this way eliminates any issues that span from wait time inconsistencies.

                      You can search the forum for elementWaitFor() to see how it's used across more situations!




                      appActivateMainWIndow sounds like it focuses on the Edit Window.


                      It makes PT the focused application by simulating a click on the top left corner of the main window. In PT this could be either the Edit or Mix window, whichever is upfront.

                      Some actions can act unexpectedly and fail if we don't make sure that PT is focused.

                      A usual situation that comes to mind is the one where you're testing out a script/macro you're working on and you trigger it by clicking on the "Run Command" button on the SoundFlow editor.
                      When you do that, SF is still the focused app as the script is starting, so things can get hairy, especially if the script starts with something like keyboard simulation lol
                      By adding sf.ui.proTools.appActivateMainWindow(); you're making sure PT will be in the ideal state to accept automation from SF.




                      I am less clear on mainWindow.invalidate. It sounds like invalidate on a sf.ui call means some kind of "clearing" of some other parameter.


                      The best thread to read about invalidation in length is this one.

                      The TLDR is, use sf.ui.proTools.mainWindow.invalidate(); to clear SF's Edit window cache and make sure it's working with current data.

                      1. Brenden @nednednerb
                          2022-10-26 07:08:37.806Z

                          Raphael,

                          Your advice and details are incredibly helpful. Taking such time between your Team members and Ambassadors to help these
                          onBoarders() {
                          thisFeat != an easy feat;
                          }
                          hah!

                          I've come back to your last post a few times to understand more each time. Thanks again for being very helpful. Good model of operations. I'm still enjoying the free trial, but SoundFlow has definitely earned me as a customer. I've actually been imagining Pro Tools automation since long before hearing about SoundFlow. It's such a natural fit for my workflows. Some parts need my attention to unique details, other parts are routines of 50 of the same steps each and every time! I can see this learning curve will always be worth its cost in saving time and many types of "energy."

                          1. Awesome to hear! Always happy to help 🤘🏼