No internet connection
  1. Home
  2. How to

Creating a smarter cut and paste to FX groups?

By Owen Granich-Young @Owen_Granich_Young
    2022-01-17 18:41:12.200Z

    I work in large TV/Feature FX templates a lot. They often have multiple matching FX BUCKETS (routing folders of tracks) to keep the FX seperate and organized and/or cut for perspective.

    I've created a very simple cut and paste between FX BUCKETS which has worked great with some limitations, and I'm wondering if somebody can help me level it up?

    Currently it's fast but not intelligent. It very simply cut's what you have selected, seleects and opens a folder track and pastes the matieral into there, then scrolls it into view.

    const folderName = event.props.folderName
    //Activate Pro Tools
    sf.ui.proTools.appActivate();
    sf.ui.proTools.invalidate()
    
    //Cut Selection
    sf.ui.proTools.menuClick({
        menuPath: ["Edit", "Cut"],
    });
    
    //Open Desination Folder Track
    sf.ui.proTools.trackGetByName({ name: folderName, makeVisible: true }).track.trackSelect();
    
    //sf.ui.proTools.selectedTrack.folderTrackSetOpen();
    
    sf.ui.proTools.menuClick({
        menuPath: ["Edit", "Paste"],
    });
    
    sf.ui.proTools.trackGetByName({ name: folderName, makeVisible: true }).track.trackScrollToView();
    

    However obviously this means that the track count of the highlighted selection needs to match the desination exaclty. I'm wondering how one would go about having the script instead look at the names of the tracks and move it to those named tracks in a diffrent FX BUCKET, since the track names are consistient across Buckets.

    Similar to this script @samuel_henriques built. Copy region to .LFE track That pastes a copy to the current groups .LFE how would you get a script look at the track names and then cut and paste the material to the matching track number in a diffrent FX BUCKET

    For example : I'd like to be able to make a selection like the above picture and the script be able to Cut and Paste those into their matching tracks in the 8 FX bucket tracks 8.4 8.5 8.6 8.9 8.10 8.11

    I don't know if this will be annoyingly slow though? It may take SF too much though to process it track by track?

    Thoughts ideas?

    As always,
    Thanks so much
    Owen

    Solved in post #2, click to view
    • 42 replies

    There are 42 replies. Estimated reading time: 24 minutes

    1. samuel henriques @samuel_henriques
        2022-01-17 19:38:17.483Z2022-01-21 20:50:27.806Z

        Hello Owen,
        I think this is a good starting point. When you run the script it will show all the visible folder tracks so you can choose one, then it will paste the clips on the same track names matching the chosen folder.
        Let me know how it goes.

        function prompt(item) {
            let prompt = sf.interaction.popupSearch({
                items: item.map(x => ({ name: x.normalizedTrackName, header: x }))
            }).item
            return prompt
        };
        
        function main() {
            sf.ui.proTools.appActivateMainWindow()
            sf.ui.proTools.invalidate()
        
            const selectedTracks = sf.ui.proTools.selectedTrackNames
            const folderTracks = sf.ui.proTools.visibleTrackHeaders.filter(x => x.title.value.endsWith("Folder Track "))
            const folderToMove = prompt(folderTracks)
        
            sf.ui.proTools.appActivateMainWindow()
            folderToMove["header"].folderTrackSetOpen({ targetValue: "Enable" });
            sf.ui.proTools.invalidate()
        
        
            const destFolder = sf.ui.proTools.trackGetByName({ name: folderToMove["name"] }).track.children.whoseRole.is("AXDisclosureTriangle").whoseTitle.is("Close Folder").first
            destFolder.elementWaitFor({}, "Folder didn't open.")
        
            //Cut Selection
            sf.ui.proTools.menuClick({ menuPath: ["Edit", "Cut"] });
        
            const destTracks = selectedTracks.map(tr => folderToMove["name"].split(" ")[1] + "." + tr.split(".")[1])
            sf.ui.proTools.trackSelectByName({ names: destTracks })
        
            // Paste Selection
            sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste"] });
        
        
            // Scroll to view
            const selectedDestTracks = sf.ui.proTools.selectedTrackHeaders
            selectedDestTracks[0].trackScrollToView()
        
            const trackToScroll = selectedDestTracks[0].popupButtons.first.elementWaitFor().element
            trackToScroll.mouseClickElement({ isControl: true, isShift: true })
        
            sf.ui.proTools.trackSelectByName({ names: destTracks })
        
        };
        
        
        main()
        
        ReplySolution
        1. Wow that was fast bud!

          It seems to not work if the destinaton folder is not open. Is the script moving faster then the folder track can open at line 16?

          Otherwise it's crazy fast and snappy!

          How would I correctly add a sf.ui.proTools.selectedTrack.trackScrollToView(destTracks); at the end? I know that's not right as I tired it.

          1. samuel henriques @samuel_henriques
              2022-01-17 20:18:31.304Z

              UPDATED ABOVE.

              You have the scroll to view as well. But for me the best way is the behaviour of when you shift+ctrl click the name of the track on the track list.
              Do you keep the track list open?

              1. This works perfectly! You're a rockstar.

                As far as track list open, not always. You're saying you feel that Shift+Ctrl Click is snappier navigation for you?

                Bests,
                Owen

                1. samuel henriques @samuel_henriques
                    2022-01-17 20:59:03.355Z

                    Not snappier, but always places the track on the top of screen.

                    The way you have now, if the first destination track is visible, even if really down in the screen it won't move. And if it's really down, out of screen, all you'll see is the first track, that's the only that will be schooled. It only works well if the destination tracks are out of screen further in the top.

                    But try it for a bit, and let me know how you feel.

                    1. Ohhh I see, I have run into that problem before with other session navigation scripts I've built. For experimentation sake is it easy to put the code in the above script and ///comment it out so I can experimetn swapping between the two?

                      Thanks!
                      Owen

                      1. samuel henriques @samuel_henriques
                          2022-01-17 21:16:02.451Z

                          UPDATED ABOVE.
                          Keep the track list open for now. If this is the solution for you, I'll add the open/close track list. It changes a bit the script

                        • samuel henriques @samuel_henriques
                            2022-01-17 21:02:01.432Z

                            I have a script that uses the track list and it you want I can make it open track list if closed, scroll, and close if it was closed. That's how I use it.

                            1. Thanks man! TBH I'm only hiding track list now because soundflow has giving me the option to thin down my views quickly, for over a decade before that it was always open.

                              1. samuel henriques @samuel_henriques
                                  2022-01-17 22:30:47.088Z

                                  Cool. It's the end of day for me here. In the morning I'll add a bit to open it if closed and close it in the end.

                                  1. samuel henriques @samuel_henriques
                                      2022-01-18 11:04:27.167Z

                                      UPDATED ABOVE,

                                      Added the tracks list open/close bit.

                                      Enjoy!

                                      1. Just wanted to say I'm using the HELL out of this. In fact I've even jacked the function to help with a persepctive cut script as well!

                                        Of note, for some reason the track list aspect really wasn't working consitently on my system. Not sure if it was a folder track issue or just the sheer size of my session and the track not being visible in the track list or what? I messed around for a while to see if I could figure out exaclty why it wasn't working but it was really really inconsisitent and I had to get back to work. Which is a bummer becuase I do really like the idea of the selected track always jumping to the top of the screen not just whever it's shown.

                                        Just thinking outloud is there an easy mouse simulation to tack onto the end of the

                                        /// Scroll to view
                                            // const selectedDestTracks = sf.ui.proTools.selectedTrackHeaders
                                            // selectedDestTracks[0].trackScrollToView()
                                        

                                        Version of the script that Ctrl+Shift+Click's the track to get the same desired effect or is that too unstable?

                                        Bests,
                                        Owen

                                        1. samuel henriques @samuel_henriques
                                            2022-01-21 20:31:48.222Z

                                            Is there a chance the destination track is not visible in the track list when it's failing?

                                            1. Absolutley! The session is massive so there's no way all the tracks are visible in the track list all the time. I tired testing this being the cause by scrolling in the track list so the destination track was visiible when I triggered the script but still a little funky.

                                              1. samuel henriques @samuel_henriques
                                                  2022-01-21 20:48:34.409Z

                                                  Your idea looks good.

                                                  Just Updated the script with it. Also, in the end it will select the destination tracks.

                                                  Let me know

                                                  1. samuel henriques @samuel_henriques
                                                      2022-01-21 20:49:40.052Z

                                                      This way we don't need to use the track list. Just a minute and I'll remove it

                                                      1. samuel henriques @samuel_henriques
                                                          2022-01-21 20:50:40.011Z

                                                          UPDATED again.

                                                          1. So snappy so good! I'm gonna steal that little part of the script for general navigation too! By far my new favorite way of scrolling to view.

                                                            1. samuel henriques @samuel_henriques
                                                                2022-01-21 20:59:27.721Z

                                                                Awesome!!

                                                                1. samuel henriques @samuel_henriques
                                                                    2022-01-22 13:53:10.424Z2022-01-26 22:58:54.056Z

                                                                    Hello Owen,

                                                                    I made another version.
                                                                    This line const trackToScroll = selectedDestTracks[0].popupButtons.first.elementWaitFor().element was meant to wait for the track header to be visible an then ctrl+shift click , since I expect in same cases, the area it needs to click wont be there, because pro tools takes tame to scroll to view. Specially if you have giant sessions.
                                                                    Hence this wait. But I've tested it more and this is not a solution for this problem. The header is always there, so waiting for it doesn't do anything.

                                                                    In this version, the script will scroll the same way, but then will check if the track is in view. If it isn't it will scroll again.

                                                                    function scrollToTop() {
                                                                    
                                                                        const selectedDestTracks = sf.ui.proTools.selectedTrackHeaders
                                                                    
                                                                        if (selectedDestTracks[0]) {
                                                                            //Scroll to Top
                                                                            selectedDestTracks[0].trackScrollToView()
                                                                            selectedDestTracks[0].popupButtons.first.mouseClickElement({ isControl: true, isShift: true })
                                                                    
                                                                            // Double-ckeck if the track is in view
                                                                            const minY = sf.ui.proTools.mainWindow.buttons.whoseTitle.is("Edit Window View selector").first.frame.y
                                                                            const maxY = sf.ui.proTools.mainWindow.buttons.whoseTitle.is("Track List Show/Hide").first.frame.y
                                                                            if (selectedDestTracks[0].popupButtons.first.frame.y < minY ||
                                                                                selectedDestTracks[0].popupButtons.first.frame.y > maxY) {
                                                                    
                                                                                scrollToTop()
                                                                            }
                                                                        } else {
                                                                            log("No Track Selected to Paste. Track Names Might Not Match.")
                                                                        }
                                                                    
                                                                    
                                                                    };
                                                                    
                                                                    
                                                                    function prompt(item) {
                                                                        let prompt = sf.interaction.popupSearch({
                                                                            items: item.map(x => ({ name: x.normalizedTrackName, header: x }))
                                                                        }).item
                                                                        return prompt
                                                                    };
                                                                    
                                                                    function main() {
                                                                        sf.ui.proTools.appActivateMainWindow()
                                                                        sf.ui.proTools.invalidate()
                                                                    
                                                                        const selectedTracks = sf.ui.proTools.selectedTrackNames
                                                                        const folderTracks = sf.ui.proTools.visibleTrackHeaders.filter(x => x.title.value.endsWith("Folder Track "))
                                                                        const folderToMove = prompt(folderTracks)
                                                                    
                                                                        sf.ui.proTools.appActivateMainWindow()
                                                                        folderToMove.header.folderTrackSetOpen({ targetValue: "Enable" }, function () {
                                                                    
                                                                            // If folder size is too small, use popup menu to open folder
                                                                            const destFolderTrack = sf.ui.proTools.trackGetByName({ name: folderToMove.name }).track;
                                                                            destFolderTrack.trackScrollToView()
                                                                            destFolderTrack.popupButtons.whoseTitle.is("Track options").first.popupMenuSelect({
                                                                                menuPath: ["Open Folder"],
                                                                            });
                                                                        });
                                                                        sf.ui.proTools.invalidate()
                                                                    
                                                                        //Cut Selection
                                                                        sf.ui.proTools.menuClick({ menuPath: ["Edit", "Cut"] });
                                                                    
                                                                    
                                                                        const destTracks = selectedTracks.map(tr => folderToMove.name.split(" ")[1] + "." + tr.split(".")[1])
                                                                        sf.ui.proTools.trackSelectByName({ names: destTracks })
                                                                    
                                                                        // Paste Selection
                                                                        sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste"] });
                                                                    
                                                                        scrollToTop()
                                                                    
                                                                        sf.ui.proTools.trackSelectByName({ names: destTracks })
                                                                    
                                                                    };
                                                                    
                                                                    
                                                                    main()
                                                                    
                                                                    
                                                                    1. Very cool! Thanks bud!

                                                                      1. This script has started bugging out if the folder is closed... I've just taken to leaving all my folders open but it's weird and irksome.

                                                                        Tried both the most recent and previous same error. (Diffrent line Obviously.)

                                                                        1. samuel henriques @samuel_henriques
                                                                            2022-01-26 22:25:28.311Z

                                                                            Hello Owen,
                                                                            I'm sorry I can't recreate the error.

                                                                            Could you do a screen recording when it happens so I could find any leads for the error?

                                                                            You can send the link to my email if the session shows information you don't want to share in the forum.
                                                                            samuelhenriques@me.com

                                                                            1. Yeah will do when I have a free moment.

                                                                              I do have the folder IN a Folder - that could be the problem, the root folder is always open.

                                                                              1. samuel henriques @samuel_henriques
                                                                                  2022-01-26 22:40:16.739Z

                                                                                  ahh, is the folder size like in the picture, so the folder icon to open/close is not visible?

                                                                                  1. oh yeah, for sure... lemme try making all the folder med... I'm sure that's it.

                                                                                    1. YEP that solved it! Thanks boss!

                                                                                      'Feature not a bug' :P

                                                                                      Noted small is the smallest it should go. I can work around that.

                                                                                      1. samuel henriques @samuel_henriques
                                                                                          2022-01-26 22:59:43.975Z

                                                                                          Cool. That was it. Just updated with a fix for when the folder is too small

                                                                                          1. oh Sick!

                                                                                            1. samuel henriques @samuel_henriques
                                                                                                2022-01-26 23:02:28.973Z

                                                                                                The script needs to see the folder icon, where you click to open/close.
                                                                                                What I added is, in case it's not visible, instead of calling an error, scroll to folder and use the popup to open.

                                                                                                1. samuel henriques @samuel_henriques
                                                                                                    2022-01-26 23:04:47.071Z

                                                                                                    BTW, if you close that parent folder, the script wont work, because he can't find the destination folder. So far pro tools doesn't show the tracks inside closed folder tracks

                                                                                                    1. Good to know, never an issue in this session the bFX Parent is always open. But I have another template I've been toying with that's a bit deeper on folder tracks in folder tracks, that that would be an issue.

                                                                                                      Thanks again for everything, I use this script ALL THE TIME.

                                                                                                      1. samuel henriques @samuel_henriques
                                                                                                          2022-01-26 23:10:53.296Z

                                                                                                          Awesome. I'm sure we can figure something to make it work on that other template. When you need, let me know the workflow and I'll think about it.

                                                                                                          1. Hey @samuel_henriques I'm working on a new show with a new mixer with a different naming convention for his tracks, do you have the time to possible adapt this script to his naming convention? I still haven't really wrapped my head around the .split and filter action in the destTracks const.

                                                                                                            This mixers layout is duplicates of this in each folder group

                                                                                                            So the split at the . won't work anymore....

                                                                                                            No worries if you're too busy, but if it's an easy 'o yeah no problem'....

                                                                                                            Thanks!
                                                                                                            Owen

                                                                                                            1. samuel henriques @samuel_henriques
                                                                                                                2023-05-02 16:22:24.899Z

                                                                                                                Hey Owen, let me see if I can figure this fast.
                                                                                                                So he adds an F to each bucket of tracks?
                                                                                                                bucket one: FX F
                                                                                                                bucket two: FX FF
                                                                                                                bucket three: FX FFF

                                                                                                                And we only need to figure the destination track names, I don't remember anymore how it was all working.

                                                                                                                1. No, each group is a diffrent letter and F is mono and FF is Stereo. Here's G for example:

                                                                                                                    1. samuel henriques @samuel_henriques
                                                                                                                        2023-05-02 18:30:07.180Z2023-05-04 17:16:17.042Z

                                                                                                                        Here you go.
                                                                                                                        Try it for a bit to see if I missed something.
                                                                                                                        I made an improvement, in case there aro no destination tracks, now it wont cut and you'll get a warning.
                                                                                                                        I kept your original naming lines o you can use this script instead, just comment the "New naming" lines and uncomment the "Original Naming" line.

                                                                                                                        function scrollToTop() {
                                                                                                                        
                                                                                                                            const selectedDestTracks = sf.ui.proTools.selectedTrackHeaders
                                                                                                                        
                                                                                                                            if (selectedDestTracks[0]) {
                                                                                                                                //Scroll to Top
                                                                                                                                selectedDestTracks[0].trackScrollToView()
                                                                                                                                selectedDestTracks[0].popupButtons.first.mouseClickElement({ isControl: true, isShift: true })
                                                                                                                        
                                                                                                                                // Double-ckeck if the track is in view
                                                                                                                                const minY = sf.ui.proTools.mainWindow.buttons.whoseTitle.is("Edit Window View selector").first.frame.y
                                                                                                                                const maxY = sf.ui.proTools.mainWindow.buttons.whoseTitle.is("Track List Show/Hide").first.frame.y
                                                                                                                                if (selectedDestTracks[0].popupButtons.first.frame.y < minY ||
                                                                                                                                    selectedDestTracks[0].popupButtons.first.frame.y > maxY) {
                                                                                                                        
                                                                                                                                    scrollToTop()
                                                                                                                                };
                                                                                                                            };
                                                                                                                        };
                                                                                                                        
                                                                                                                        
                                                                                                                        
                                                                                                                        function prompt(item) {
                                                                                                                        
                                                                                                                            const formatItems = item.map(tr => ({ header: tr, name: tr.normalizedTrackName, comment: tr.textFields.first.value.value }))
                                                                                                                        
                                                                                                                            let prompt = sf.interaction.popupSearch({
                                                                                                                                items: formatItems,
                                                                                                                                title: 'Select',
                                                                                                                                columns: [
                                                                                                                                    { name: 'FX Name', key: 'name', width: 50 },
                                                                                                                                    { name: 'Comment', key: 'comment', width: 50 },
                                                                                                                                ],
                                                                                                                            }).item;
                                                                                                                        
                                                                                                                            return prompt
                                                                                                                        };
                                                                                                                        
                                                                                                                        function forceTrackViewWaveform(selectedTracks) {
                                                                                                                            // Set waveform view if not
                                                                                                                            const hasViewNotWaveform = () => selectedTracks.find(th => th.displaySelectorButton.value.invalidate().value !== "waveform") === undefined ? false : true;
                                                                                                                            while (hasViewNotWaveform()) {
                                                                                                                                sf.ui.proTools.trackVolumeToggle();
                                                                                                                            };
                                                                                                                        }
                                                                                                                        
                                                                                                                        function main() {
                                                                                                                            sf.ui.proTools.appActivateMainWindow()
                                                                                                                            sf.ui.proTools.invalidate()
                                                                                                                        
                                                                                                                            const selectedTrackHeaders = sf.ui.proTools.selectedTrackHeaders;
                                                                                                                            forceTrackViewWaveform(selectedTrackHeaders);
                                                                                                                        
                                                                                                                            
                                                                                                                            const selectedTracks = selectedTrackHeaders.map(th => th.normalizedTrackName);
                                                                                                                            const folderTracks = sf.ui.proTools.visibleTrackHeaders.filter(x => x.title.value.endsWith("Folder Track "));
                                                                                                                            const folderToMove = prompt(folderTracks)
                                                                                                                        
                                                                                                                        
                                                                                                                            sf.ui.proTools.appActivateMainWindow();
                                                                                                                            folderToMove.header.folderTrackSetOpen({ targetValue: "Enable" }, function () {
                                                                                                                        
                                                                                                                                // If folder size is too small, use popup menu to open folder
                                                                                                                                const destFolderTrack = sf.ui.proTools.trackGetByName({ name: folderToMove.name }).track;
                                                                                                                                destFolderTrack.trackScrollToView()
                                                                                                                                destFolderTrack.popupButtons.whoseTitle.is("Track options").first.popupMenuSelect({
                                                                                                                                    menuPath: ["Open Folder"],
                                                                                                                                });
                                                                                                                            });
                                                                                                                            sf.ui.proTools.invalidate()
                                                                                                                        
                                                                                                                            const trackTypeSymbol = folderToMove.name.split(" ")[1];
                                                                                                                        
                                                                                                                        
                                                                                                                            //Original Naming
                                                                                                                            //  const destTracks = selectedTracks.map(tr => folderToMove.name.split(" ")[1] + "." + tr.split(".")[1])
                                                                                                                            ///
                                                                                                                        
                                                                                                                            //New Naming
                                                                                                                            const destTracks = selectedTracks.map(tr => {
                                                                                                                        
                                                                                                                                const [fxTrack, type, n] = tr.split(" ");
                                                                                                                        
                                                                                                                                return `${fxTrack} ${type.split("").map(ch => ch.replace(ch, trackTypeSymbol)).join("")} ${n}`
                                                                                                                            });
                                                                                                                            /////
                                                                                                                        
                                                                                                                        
                                                                                                                            let tracksExist = sf.ui.proTools.visibleTrackNames.filter(trackName => destTracks.includes(trackName)).length === selectedTracks.length
                                                                                                                            if (!tracksExist) { log("No Track Found to Paste. Track Names Might Not Match."); return; }
                                                                                                                        
                                                                                                                            //Cut Selection
                                                                                                                            sf.ui.proTools.menuClick({ menuPath: ["Edit", "Cut"] });
                                                                                                                        
                                                                                                                            // Select destination tracks
                                                                                                                            sf.ui.proTools.trackSelectByName({ names: destTracks });
                                                                                                                        
                                                                                                                            // Paste Selection
                                                                                                                            sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste"] });
                                                                                                                        
                                                                                                                            scrollToTop()
                                                                                                                        
                                                                                                                            sf.ui.proTools.trackSelectByName({ names: destTracks })
                                                                                                                        
                                                                                                                        };
                                                                                                                        
                                                                                                                        
                                                                                                                        main();
                                                                                                                        
                                                                                                                        1. Sick, you're a rockstar. I'll run it through it's paces and let you know if anything gets funky.

                                                                                                                          THANKS!
                                                                                                                          Owen

                                                                                                                          1. Only a few moves so far but it's working nicely. (I just have to remember to be in waveform view not VOL sometimes)

                                                                                                                            I wanted to ask how hard it would be to implement a feature in the prompt where in addition to the names of the folder tracks it also showed a 2nd column with the comments of those folder tracks?

                                                                                                                            We often name the groups in the comments for example :

                                                                                                                            Would be a nice bonus to see the comments in a 2nd column on the prompt window.

                                                                                                                            1. samuel henriques @samuel_henriques
                                                                                                                                2023-05-04 17:17:10.288Z

                                                                                                                                UPDATED above.
                                                                                                                                Added,

                                                                                                                                1. change all selected tracks to waveform
                                                                                                                                2. added comments column
                                                                                                                                1. Daniel Perez @daniel_perez
                                                                                                                                    2023-11-21 21:57:42.217Z

                                                                                                                                    @samuel_henriques

                                                                                                                                    i want to use a part of this script for my navigation script. i'm not smart enough to decode what's going on here.

                                                                                                                                    my macro is the simple

                                                                                                                                    sf.ui.proTools.trackGetByName({ name: "DX BUS", makeVisible: true }).track.trackScrollToView();
                                                                                                                                    

                                                                                                                                    line.

                                                                                                                                    what can i add to this script, to not only scroll into view, but make the track the topmost?