No internet connection
  1. Home
  2. How to

Trying to create clips of equal length that don't start on grid values

By Jesse Field @Jesse_Field7
    2024-10-27 21:11:10.347Z

    Hey All! Im working on one that feels a little challenging for my current skill level with SF- I basically need to create a script that will help me make all drum hits the same length (looking at between 15-25ms) so I can trigger gates and samples without them staying open too long. my current plan is just:
    -Tab to Transient
    -Highlight Time Selection Box
    -Enter 25ms
    -Hit CMD+T to trim sides
    -Tab to Transient again to get past the edit

    is there something like this already floating around that I haven't found or a smarter work around?
    thank you!

    Solved in post #7, click to view
    • 8 replies
    1. B
      Brandon Jiaconia @Brandon_Jiaconia
        2024-10-28 04:14:42.576Z

        You should look into automating Strip Silence. There are a couple good threads on the forum:

        1. In reply toJesse_Field7:
          Dustin Harris @Dustin_Harris
            2024-10-28 15:24:44.835Z

            Here's something I threw together, let me know if it works well enough. There may be a faster way to trim the clips to the desired length, but I can't think of one at the moment...

            const CLIP_LENGTH_IN_MILLISECONDS = 25;
            
            
            /**@param {number} clipLengthInMs */
            function splitClipAtSelection(clipLengthInMs) {
            
                if (sf.ui.proTools.getMenuItem("Edit", "Separate Clip", "At Transients").isEnabled) {
            
                    sf.ui.proTools.menuClick({
                        menuPath: ["Edit", "Separate Clip", "At Transients"]
                    })
            
                    sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.elementWaitFor();
                    sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.textFields.first.elementSetTextFieldWithAreaValue({
                        value: String(clipLengthInMs),
                        useMouseKeyboard: true
                    })
            
                    sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.buttons.whoseTitle.is("OK").first.elementClick();
                    sf.wait({ intervalMs: 250 })
                }
            }
            
            
            /**@param {{targetTrackNames: string[], inTime: string, outTime: string, clipLengthInMs: number}} args */
            function trimClipsToLengthInMs({ targetTrackNames, inTime, outTime, clipLengthInMs }) {
            
                const clipLengthInSamples = (clipLengthInMs * sf.app.proTools.getSessionSampleRate().sampleRateNumerical) / 1000
            
                targetTrackNames.forEach(trackName => {
            
                    sf.app.proTools.selectTracksByName({
                        trackNames: [trackName]
                    })
            
                    sf.app.proTools.setTimelineSelection({
                        inTime, outTime 
                    });
            
                    
                    sf.ui.proTools.clipDoForEachSelectedClip({
                        action: _ => {
            
                            const {inTime} = sf.app.proTools.getTimelineSelection({timeScale: "Samples"});
                            const outTime = String(Number(inTime) + clipLengthInSamples);
            
                            sf.app.proTools.setTimelineSelection({
                                inTime, outTime
                            });
            
                            sf.app.proTools.trimToSelection();
            
                        }
                    })
            
                })
            }
            
            
            /**@param {{targetTrackNames: string[], inTime: string, outTime: string}} args */
            function splitAtTransients({ targetTrackNames, inTime, outTime }) {
            
                targetTrackNames.forEach(trackName => {
            
                    //select track
                    sf.app.proTools.selectTracksByName({
                        trackNames: [trackName]
                    })
            
                    //go to start of selection
                    sf.app.proTools.setTimelineSelection({
                        inTime: inTime,
                        outTime: outTime,
                    })
            
                    //mass separate clips
                    splitClipAtSelection(CLIP_LENGTH_IN_MILLISECONDS);
            
                })
            
            }
            
            
            function main() {
            
                sf.ui.proTools.appActivateMainWindow();
            
                const { inTime, outTime } = sf.app.proTools.getTimelineSelection({ timeScale: "Samples" });
                const targetTrackNames = sf.app.proTools.tracks.allItems.filter(t=>t.isSelected).map(t => t.name);
            
                splitAtTransients({ targetTrackNames, inTime, outTime })
            
                trimClipsToLengthInMs({ targetTrackNames, inTime, outTime, clipLengthInMs: CLIP_LENGTH_IN_MILLISECONDS })
            
            }
            
            main();
            
            1. JJesse Field @Jesse_Field7
                2024-10-28 19:08:16.774Z

                this is incredible thank you so much!! This works perfectly for what im trying to do. the only thing im noticing is that if I let the script split the clips at the beginning it adds a trigger pad and then misses the transient but that might be because I added sf.ui.proTools.clipDoForEachClip({action:main}) to the bottom so that it would repeat for every clip in the highlight. is there a smoother way to do that? if I precut the clips with Beat Detective it seems to work perfectly, just leaves a few stray clips but they're always silence before transients so its not a big deal. thank you so much for working on that, you just saved me so much time haha.

                1. Dustin Harris @Dustin_Harris
                    2024-10-28 19:20:36.783Z

                    I don't think you need to add anything at the bottom of the script, do for each selected clip and each selected track is already built in; just select everything you want to separate+shorten and run it... try it without your addition and see if it does what you expect? I also might need to have separate constants for the clip length and the transient pre-separate amount (maybe it should be 0?) anyway try it without your additions and let me know if it works any better, and I'll adapt it after your findings :)

                    1. JJesse Field @Jesse_Field7
                        2024-10-28 19:23:59.702Z

                        oh weird!! I must have done something goofy the first time I tried it because it only did 1 clip and stopped. its definitely doing them all now! but still has that trigger pad in the front so it looks like this:

                        1. Dustin Harris @Dustin_Harris
                            2024-10-28 19:26:49.972Z

                            ok, slightly tweaked version, let me know if this works better!

                            const CLIP_LENGTH_IN_MILLISECONDS = 25;
                            
                            
                            /**@param {number} clipLengthInMs */
                            function splitClipAtSelection(clipLengthInMs) {
                            
                                if (sf.ui.proTools.getMenuItem("Edit", "Separate Clip", "At Transients").isEnabled) {
                            
                                    sf.ui.proTools.menuClick({
                                        menuPath: ["Edit", "Separate Clip", "At Transients"]
                                    })
                            
                                    sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.elementWaitFor();
                                    sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.textFields.first.elementSetTextFieldWithAreaValue({
                                        value: "0",
                                        useMouseKeyboard: true
                                    })
                            
                                    sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.buttons.whoseTitle.is("OK").first.elementClick();
                                    sf.wait({ intervalMs: 250 })
                                }
                            }
                            
                            
                            /**@param {{targetTrackNames: string[], inTime: string, outTime: string, clipLengthInMs: number}} args */
                            function trimClipsToLengthInMs({ targetTrackNames, inTime, outTime, clipLengthInMs }) {
                            
                                const clipLengthInSamples = (clipLengthInMs * sf.app.proTools.getSessionSampleRate().sampleRateNumerical) / 1000
                            
                                targetTrackNames.forEach(trackName => {
                            
                                    sf.app.proTools.selectTracksByName({
                                        trackNames: [trackName]
                                    })
                            
                                    sf.app.proTools.setTimelineSelection({
                                        inTime, outTime 
                                    });
                            
                                    
                                    sf.ui.proTools.clipDoForEachSelectedClip({
                                        action: _ => {
                            
                                            const {inTime} = sf.app.proTools.getTimelineSelection({timeScale: "Samples"});
                                            const outTime = String(Number(inTime) + clipLengthInSamples);
                            
                                            sf.app.proTools.setTimelineSelection({
                                                inTime, outTime
                                            });
                            
                                            sf.app.proTools.trimToSelection();
                            
                                        }
                                    })
                            
                                })
                            }
                            
                            
                            /**@param {{targetTrackNames: string[], inTime: string, outTime: string}} args */
                            function splitAtTransients({ targetTrackNames, inTime, outTime }) {
                            
                                targetTrackNames.forEach(trackName => {
                            
                                    //select track
                                    sf.app.proTools.selectTracksByName({
                                        trackNames: [trackName]
                                    })
                            
                                    //go to start of selection
                                    sf.app.proTools.setTimelineSelection({
                                        inTime: inTime,
                                        outTime: outTime,
                                    })
                            
                                    //mass separate clips
                                    splitClipAtSelection(CLIP_LENGTH_IN_MILLISECONDS);
                            
                                })
                            
                            }
                            
                            
                            function main() {
                            
                                sf.ui.proTools.appActivateMainWindow();
                            
                                const { inTime, outTime } = sf.app.proTools.getTimelineSelection({ timeScale: "Samples" });
                                const targetTrackNames = sf.app.proTools.tracks.allItems.filter(t=>t.isSelected).map(t => t.name);
                            
                                splitAtTransients({ targetTrackNames, inTime, outTime })
                            
                                trimClipsToLengthInMs({ targetTrackNames, inTime, outTime, clipLengthInMs: CLIP_LENGTH_IN_MILLISECONDS })
                            
                            }
                            
                            main();
                            
                            Reply1 LikeSolution
                            1. JJesse Field @Jesse_Field7
                                2024-10-28 21:31:17.397Z

                                This is literally perfect thank you so much for doing this!!!! so excited!!!

                      • J
                        In reply toJesse_Field7:
                        Jesse Field @Jesse_Field7
                          2025-02-04 20:56:03.917Z

                          Hey Dustin! for some reason since I updated pro tools and my OS this no longer works. I tried to switch around anything I could or find a work around but i'm a bit stumped. any help would be massively appreciated since I use it a ton!