No internet connection
  1. Home
  2. How to

Trim Fader Across Highlighted Session

By Andy Daddario @Andy_Daddario
    2020-11-05 00:56:46.034Z2020-11-05 05:12:25.643Z

    Hi All,

    Been searching the Forum, experimented a lot, and not really coming up with a lot of solutions how to automate this one. For Broadcast mixing with have to hit LKFS numbers all day long. Typically we get a number after our first playback, and trim our masters up or down (usually down) to get us closer.

    This would be across a Master Fader to pull the overall level down. Kinda happens like this.

    First I'd highlight the width of the session I'd like to pull down (usually a 45 minute section of the session). Manually, not automated.

    Soundflow would take it from here.
    1.) Show Trackview
    2.) Show Volume Trim line
    3.) Here I'd love for a box to open to ask how far to trim Up or Down. (enter as a +3 for db would be fine)
    4.) Pull the Volume Trim line across the Selection. (up or down depending on level amount I input on Line 3 above)
    5.) Shut off Volume Trim line (so it just looks like a normal volume automation line again)

    I'd do this across all my Stems ultimately. Dialogue, Music, Group, Vocals, Narration.

    Any thoughts on directions to take?

    In advance....Thanks!

    ...Andy D.

    • 42 replies

    There are 42 replies. Estimated reading time: 31 minutes

    1. A
      Andy Daddario @Andy_Daddario
        2020-11-05 05:04:54.037Z

        (up or down depending on the input level of line 3) is what that should have said on item #4.

        Thanks!

        1. Would it work for you, if we used Automation Preview as a way to write the trim automation to the selection (and then I'm assuming you have PT set to coalesce the trim auto to volume auto when exiting trim auto mode?)

          We can't reliably automate dragging on the actual lines, but we could automate setting the trim value of the selection to a set value (supplied by the user).

          1. AAndy Daddario @Andy_Daddario
              2020-11-06 21:07:21.111Z

              Hey Christian, yes that would work just fine.

              1. Christian Scheuer @chrscheuer2020-11-07 14:18:09.687Z2020-11-07 17:14:01.153Z

                So... this turned out to be fairly complex, because there's a lot of setup that needs to be made correctly.
                The script needs to set up:

                • Ensure automation window is open
                • Enable preview
                • Enable volume automation
                • Set the track to "touch trim" mode
                • Ensure track output window is open

                Before actually making the change and then writing the automation, and then restoring any settings that it temporarily changed.

                The current script also assumes that you have automation warning dialogs ON - as this is the recommended setting when working in SF (since SF then monitors and ensures that you don't accidentally overwrite the whole session).

                Here it goes:

                
                /**@param {{
                     track: AxPtTrackHeader,
                     automationMode?: string,
                     automationTrim?: boolean,
                     enableVolumeAuto?: boolean,
                     enablePreview?: boolean,
                     action: () => void,
                }} args */
                const withAutomationMode = (args) => {
                    const {
                     track, automationMode, automationTrim, enableVolumeAuto, enablePreview, action,
                } = args;
                
                    if (!track || !track.exists) throw `Track is required`;
                
                    //Define reusable funcs to query the state before/after
                    const isAutoWindowOpen = () => sf.ui.proTools.automationWindow.invalidate().exists;
                    const isAutoVolumeEnabled = () => sf.ui.proTools.automationWindow.enableVolumeAutoButton.value.invalidate().value === "Selected";
                    const isAutoPreviewEnabled = () => (sf.ui.proTools.automationWindow.previewButton.value.invalidate().value === "Selected");
                    const getTrackAutomationMode = () => track.automationModeButton.value.invalidate().value.replace(/trim/g, '').trim();
                    const isTrackAutomationTrim = () => (track.automationModeButton.value.invalidate().value + '').includes('trim');
                
                    let initialState = {
                        automationMode: undefined,
                        automationTrim: undefined,
                        autoWindowOpen: undefined,
                        autoVolumeEnabled: undefined,
                        autoPreviewEnabled: undefined,
                    };
                
                    try {
                        //Grab initial state
                        initialState.automationMode = getTrackAutomationMode();
                        initialState.automationTrim = isTrackAutomationTrim();
                        initialState.autoWindowOpen = isAutoWindowOpen();
                
                        //Ensure automation window is open
                        if (!initialState.autoWindowOpen)
                            sf.ui.proTools.automationWindowRequireOpenAutomationWindow({}, `Couldn't open automation window`);
                
                        //Complete the initialState, now that the automation window is ensured to be open
                        initialState.autoVolumeEnabled = isAutoVolumeEnabled();
                        initialState.autoPreviewEnabled = isAutoPreviewEnabled();
                
                        //Select the track - TODO: This state change is currently not restored
                        track.trackSelect({}, `Couldn't select track ${track.normalizedTrackName}`);
                
                        //Ensure track is in the proper automation mode
                        track.automationModeSet({ automationModeName: automationMode, trackTargetMode: 'SelectedTracks' }, `Couldn't select automation mode "${automationMode}" for track`);
                        if (automationTrim !== undefined) {
                            if (initialState.automationTrim !== automationTrim)
                                track.automationModeSet({ automationModeName: 'trim', trackTargetMode: 'SelectedTracks' }, `Couldn't select automation mode "trim" for track`);
                        }
                
                        //Enable/disable volume auto
                        if (enableVolumeAuto !== undefined && initialState.autoVolumeEnabled !== enableVolumeAuto)
                            sf.ui.proTools.automationWindow.enableVolumeAutoButton.elementClick();
                
                        //Enable/disable preview
                        if (enablePreview !== undefined)
                            sf.ui.proTools.automationPreview({ targetValue: enablePreview ? 'Enable' : 'Disable' });
                
                        //Perform whatever it is you want to happen
                        try {
                
                            action();
                
                        } catch (err) {
                            throw { inner: err };
                        }
                
                    } catch (err) {
                
                        //Errors happening inside the action shouldn't be wrapped by us, so re-throw them directly
                        if (err.inner) throw err.inner;
                
                        throw `Error setting up automation.\n${err}`;
                
                    } finally {
                
                        //Restore initial state, ignoring potential errors
                
                        if (initialState.automationMode !== undefined && initialState.automationMode !== getTrackAutomationMode())
                            track.automationModeSet({ automationModeName: initialState.automationMode, onError: 'Continue' });
                
                        if (initialState.automationTrim !== undefined && initialState.automationTrim !== isTrackAutomationTrim())
                            track.automationModeSet({ automationModeName: 'trim', trackTargetMode: 'SelectedTracks', onError: 'Continue' });
                
                        if (initialState.autoPreviewEnabled !== undefined && initialState.autoPreviewEnabled !== isAutoPreviewEnabled())
                            sf.ui.proTools.automationPreview({ targetValue: 'Toggle', onError: 'Continue' });
                
                        if (initialState.autoVolumeEnabled !== undefined && initialState.autoVolumeEnabled !== isAutoVolumeEnabled())
                            sf.ui.proTools.automationWindow.enableVolumeAutoButton.elementClick({ onError: 'Continue' });
                
                        if (initialState.autoWindowOpen === false)
                            sf.ui.proTools.automationWindow.windowClose({ onError: 'Continue' });
                    }
                }
                
                /**@param {{
                    track: AxPtTrackHeader,
                    action: (AxWindow) => void,
                }} args */
                function withTrackOutput(args) {
                    const { track, action } = args;
                
                    //Define reusable state funcs
                    function getOutputWin() {
                        return sf.ui.proTools.floatingWindows.whoseTitle.is('').filter(w => {
                            let trackSel = w.children.whoseTitle.startsWith('Track selector').first;
                            if (!trackSel.exists) return false;
                            return trackSel.value.value === track.normalizedTrackName;
                        })[0];
                    }
                
                    let initialState = {
                        outputOpen: undefined,
                    };
                
                    try {
                        let outputWin = getOutputWin();
                        initialState.outputOpen = !!outputWin;
                
                        if (!initialState.outputOpen) {
                            track.trackOutputToggleShow({}, `Couldn't open track output window.\nMake sure you're displaying track I/O`);
                            sf.waitFor({
                                callback: () => {
                                    outputWin = getOutputWin();
                                    return !!outputWin;
                                },
                                timeout: 2000,
                            }, `Track output window didn't open`);
                        }
                
                        try {
                            action(outputWin);
                        } catch (err) {
                            throw { inner: err };
                        }
                
                    } catch (err) {
                
                        //Errors happening inside the action shouldn't be wrapped by us, so re-throw them directly
                        if (err.inner) throw err.inner;
                
                        throw `${err}`;
                
                    } finally {
                
                        //Restore initial state, ignoring potential errors
                
                        if (initialState.outputOpen === false)
                            track.trackOutputToggleShow({ onError: 'Continue' });
                
                    }
                
                }
                
                /**@param {{
                    track: AxPtTrackHeader,
                    amount: number,
                    autoConfirmation: boolean
                }} args
                */
                function trimVolume(args) {
                    const { track, amount, autoConfirmation } = args;
                
                    if (!track) throw `Track is required`;
                    if (isNaN(Number(amount))) throw `Amount must be a number`;
                
                    /**@param {AxWindow} trackOutputWin */
                    function main(trackOutputWin) {
                        try {
                            let volumeField = trackOutputWin.textFields.whoseTitle.is('Volume Numerical').first;
                            if (!volumeField.exists) throw `Couldn't find volume field`;
                
                            volumeField.elementClick({}, `Couldn't focus volume text field`);
                
                            sf.keyboard.type({ text: String(amount) }, `Couldn't type trim amount`);
                
                            sf.keyboard.press({ keys: 'enter' }, `Couln't press enter`);
                
                            sf.wait({ intervalMs: 50 });
                
                            sf.keyboard.press({ keys: 'left' }, `Couldn't update Pro Tools state`); //to update things...
                
                            sf.ui.proTools.automationWindow.writeAutoToSelectionButton.proToolsAutomationClickButton({
                                autoConfirmation: autoConfirmation,
                            }, `Couldn't write automation to selection.\nEnsure your automation warning dialogs are ${autoConfirmation ? "on" : "off"}`);
                
                        } catch (err) {
                            throw `Couldn't trim volume.\n${err}`;
                        }
                    }
                
                    withAutomationMode({
                        track,
                        automationMode: 'touch',
                        automationTrim: true,
                        enableVolumeAuto: true,
                        enablePreview: true,
                        action: () => {
                            withTrackOutput({
                                track,
                                action: main,
                            });
                        }
                    });
                }
                
                function main() {
                    let amountStr = prompt(`How much do you want to raise/lower the dB of the selected region?`);
                    if (amountStr === undefined || amountStr === '' || String(amountStr).trim() === '') throw 0;
                
                    //To make it easier in countries that use ',' as decimal point
                    amountStr = amountStr.replace(/,/g, '.');
                
                    let amount = Number(amountStr);
                    if (isNaN(amount)) throw `The amount needs to be a number, for example "-0.5"`;
                
                    trimVolume({
                        track: sf.ui.proTools.invalidate().selectedTrack,
                        amount,
                        autoConfirmation: true,
                    });
                }
                
                main();
                
                
                1. cc @Kitch, @Andrew_Scheps, @Dustin_Harris - see here for a good way to abstract away complex initial setup and cleanup, to keep the actual code more simple.

                  1. Dustin Harris @Dustin_Harris
                      2020-11-07 14:37:25.094Z

                      Oh wow, this is beautiful. I have a lot of studying to do here. Thanks!

                      1. Yay :) Just edited the script and refactored some things to make for even better "best practices" for complex initial state / state restoration and error handling.

                        1. Dustin Harris @Dustin_Harris
                            2020-11-07 16:38:20.530Z

                            If I'm reading the script right, this might be a worthwhile check too (or is it already handled as well?)

                                if (sf.ui.proTools.getMenuItem('Window', 'Hide All Floating Windows').isMenuChecked == true) {
                            
                                    sf.ui.proTools.menuClick({
                                        menuPath: ["Window", "Hide All Floating Windows"],
                                    });
                            
                            
                            1. This could break other potential floating windows you have open. The script should already handle closing any windows that it opens.

                              1. Dustin Harris @Dustin_Harris
                                  2020-11-07 17:03:38.606Z

                                  You're right, I just tested it; I was thinking that if that menu item was checked, new floating windows would NOT appear, but they do, so disregard that statement. (I use that in scripts to temporarily hide windows to ensure the Start / End / Length fields in the main counter aren't obscured)

                              2. In reply tochrscheuer:
                                Dustin Harris @Dustin_Harris
                                  2020-11-07 16:43:35.448Z

                                  I'm going to have to study that script a lot. There is so much syntax here I'm unfamiliar with 😅

                                  1. In reply tochrscheuer:

                                    I've now added this as a template to the "Pro Tools Utilities" package as: "Trim Volume Automation in Selection" :)

                                    1. Josh Cruz @spacebearaudio
                                        2021-05-31 12:26:50.772Z

                                        I was forwarded to this thread from a similar question I had. Think this script will do pretty much what I need, but whenever I try to run it from the utilities package or the one above, it keeps giving me an error saying it can't open up the automation window. Any ideas?

                                        1. Are you on PT Ultimate?

                                          1. Josh Cruz @spacebearaudio
                                              2021-05-31 12:35:10.715Z

                                              I am not. Is that required? I must have missed that.

                                              If that is the case, is there any way to make it available with standard?

                                              1. Hi Josh,

                                                The version I built relies heavily on Ultimate features (automation preview in particular), so I think it would have to be started from scratch to make it work in the vanilla version.

                                                I have to be honest and say that I don't know if it would be possible, and due to my work on the SF app itself I probably won't have time to look at this in the near future - but maybe if somebody (or you) could write up the steps required to do this manually on vanilla PT, that would be a great first step for trying to automate it there.
                                                Please start that as a new thread linking to this though, just to keep things a bit more easy to organize :)

                                    2. In reply tochrscheuer:
                                      Kitch Membery @Kitch2020-11-07 17:43:42.451Z

                                      Thanks Christian! This is great.

                                    3. In reply tochrscheuer:
                                      AAndy Daddario @Andy_Daddario
                                        2020-11-09 03:42:41.273Z

                                        WOW Christian, holy cow! Yeah, I can now see why I couldn't get anywhere....(huge LOL). I can't wait to get back in the studio and give this a try.

                                        So new question....how do I move to the next level of complexity? I've done ok writing basic Macros, turning them into Scripts, making some small modifications and called it "close enough". I've struggled with I think you call them "child" menus that open, (a sub-menu of a menu) and still really not getting I guess. (at least consistently)

                                        I've made some small progress, and maybe that's all I can expect and just takes hours of trial and error (as @Andrew_Scheps mentioned on his seminar). I'm not looking for short cuts, I want to learn, but not even sure where to begin on some ideas I want to try (like this one).

                                        I've seen the page you've been pointing us to recently (I'm sorry I don't have it right in front of me) with all the Java commands. What I need I guess is how to put all that together? Or, is it just years of working in Java?

                                        Very impressive Christian, there's a lot of logic going in that script that will take me quite awhile to wrap my head around.

                                        Thanks for taking all that time, I'm sure it was quite the challenge.

                                        Thanks!........Andy D.

                                        1. Hi Andy :)

                                          Happy to help!

                                          For how to best learn... I guess you may actually get a better answer from the likes of @Dustin_Harris, @Kitch and @Andrew_Scheps - who all mostly learned by themselves and by using the forum. How did you guys get started making more advanced scripts?

                                          1. Andrew Scheps @Andrew_Scheps
                                              2020-11-09 12:49:15.846Z

                                              Searching the forum was by far the best way. Dissecting scripts that Christian had posted and reading tons of other posts.

                                              Another thing that helped a lot was taking the scripts from the forum and modifying them just to see what everything did. I also spent a bunch of time trying to answer other people's How To questions, even if it was nothing I would ever need myself.

                                              And lastly, I haven't slept in 6 months...

                                              1. Andrew Scheps @Andrew_Scheps
                                                  2020-11-09 13:01:33.833Z

                                                  I would also say that this script has a very advanced structure. Don't get thrown off by the second function call main inside the trimVolume function. It is completely separate from the main script at the bottom that gets everything going. (@chrscheuer by the way, what's the thinking behind calling that one main too?)

                                                  Also, within the trimVolume function, the object being sent to withAutomationMode sends that second main function as a variable called action within an object that's sent to withTrackOutput. So basically (if I have this right) the track is sent to withTrackOutput along with the second main function and what comes back from there is sent along with the rest of the object to withAutomationMode

                                                  You kind of have to unwrap it in your head because the order of operations can seem backwards on first read.

                                                  It's going to take me weeks to completely unpack this one...

                                                  1. I'd be happy to do a public webinar where we discuss complex scripts :) We could take this as an example.

                                                    1. Andrew Scheps @Andrew_Scheps
                                                        2020-11-09 13:39:39.029Z

                                                        That would be great!

                                                        1. Let's do it :)

                                                          1. Would love this!

                                                        2. In reply tochrscheuer:
                                                          AAndy Daddario @Andy_Daddario
                                                            2020-11-12 08:22:28.368Z

                                                            Yes would love that Christian. Just speaking for myself, I get really confused fast when writing directly in scripts (and not starting in a Macro) as the choices open as you type. Because the majority of them I have no idea what they mean, I just kinda back out and re-think how I can do it with Macros. Once I have it "kinda" working in a Macro, convert it to a Script and break it down a bit. That helps a little, but I still never really get the logic of actually writing directly in Java.

                                                            But definitely would watch anything you do as far as writing complex Scripts directly.

                                                            Thanks again for taking all that time, I'm finally headed to the studio tomorrow to give it a spin.

                                                            Thanks!......Andy D.

                                                        3. In reply toAndrew_Scheps:
                                                          Dustin Harris @Dustin_Harris
                                                            2020-11-09 13:05:55.876Z

                                                            I echo (delay) what @Andrew_Scheps said; dissecting scripts here in the forums and downloading other people’s packages and looking how they have implemented things really helped understand how SoundFlow interfaces with programs. Another thing I did was work through these lessons here to understand the JavaScript language itself:

                                                            https://javascript.info/

                                                            You can use the SoundFlow script editor as a sandbox to run the code examples in the tutorial above.
                                                            Note: where it says
                                                            console.log(‘your message here’)
                                                            SoundFlow uses
                                                            log(‘your message here’)

                                                            1. AAndy Daddario @Andy_Daddario
                                                                2020-11-12 08:00:31.765Z

                                                                Thank you for the tips Dustin! I'll check it out for sure!.....Andy D.

                                                              • In reply toAndrew_Scheps:
                                                                AAndy Daddario @Andy_Daddario
                                                                  2020-11-12 07:59:23.942Z

                                                                  Hysterical Andrew, (not sleeping in 6 months) you made me laugh out here in LA!.....:)

                                                                  My eyes start to glaze over after about the 5th line of Java code, so I found the perfect "sleeping pill" replacement......lol....:)

                                                                • In reply tochrscheuer:
                                                                  Kitch Membery @Kitch2020-11-09 18:21:57.870Z

                                                                  Hi @Andy_Daddario,

                                                                  Firstly, I agree with everything @Dustin_Harris and @Andrew_Scheps have said here in this post.

                                                                  My process of learning Javascript (Still learning) was to break things down into the smallest pieces. I started out (like you) by creating macro's and then testing all the properties to see what they did. I'd then convert them into script form and see what changed. When I got stuck, I asked questions on the forum. My questions would be clear and specific usually just focusing one one section or line of code. by doing this I got a greater understanding of how the building blocks worked. Each thing I learned helped me to understand the next concept.

                                                                  Be sure to check out the video's that I've been making here in the Learning SoundFlow playlist on YouTube which can also be found in the "Tutorials" category in the forum. And if you have something specific you'd like me to make a video on I'd love to hear your suggestions.

                                                                  Also... @chrscheuer has put together a great collection of Javascript Resources that are invaluable when trying to get my head around stuff.

                                                                  Most of all... enjoy the process and know that the SoundFlow community is here to help! :-)
                                                                  Rock on!

                                                                  1. AAndy Daddario @Andy_Daddario
                                                                      2020-11-12 08:05:47.619Z

                                                                      Thanks Kitch. Yes, I've been taking in all your videos. Each one is a building block for sure. The XY coordinates for a UI Element had been especially helpful. I was doing it completely by trial and error previously until I magically hit the right spot......Big LOL!!!.

                                                                      But when I looked at what Christian wrote for this I was thinking, "yeah, I've got a VERY long way to go here". I honestly thought it wouldn't be "quite" that difficult, but clearly it is.

                                                                      Thanks again for all the tips, much appreciated!......Andy D.

                                                                      1. Kitch Membery @Kitch2020-11-12 08:28:56.978Z

                                                                        @Andy mate!

                                                                        Thanks for the kind words. You are totally welcome, I'm glad the videos are helping. Let me know if there is anything you get stuck on as I'm keen to hear what people want to learn.

                                                                        Rock on!

                                                                        1. AAndy Daddario @Andy_Daddario
                                                                            2020-11-12 17:44:23.662Z

                                                                            You'll soon regret saying "Let me know if there is anything you get stuck on"......LOL!!!!

                                                                            Like a Monty Python movie, the scroll will roll out!........:)

                                                                    • In reply toAndy_Daddario:

                                                                      If you're looking to get your hands dirty with JavaScript, I found this series of tutorials extremely helpful. Unlike most JS videos these are geared for JS only and do not involve much, if any, HTML.
                                                                      Watching these and dissecting scripts in the store and forum got me going pretty quickly.
                                                                      https://www.youtube.com/watch?v=zjVFuft1O2Y&list=PLyuRouwmQCjkYdv4VjuIbvcMZVWSdOm58

                                                                      1. AAndy Daddario @Andy_Daddario
                                                                          2020-11-13 19:59:25.115Z

                                                                          Thank you Chris, I'll check em out!

                                                                          ....Andy D.

                                                                      2. In reply tochrscheuer:
                                                                        AAndy Daddario @Andy_Daddario
                                                                          2020-11-12 17:54:35.580Z2020-11-12 18:04:58.593Z

                                                                          Hey Christian, works beautifully!!!! The only small change might be to make sure the I/O view is on in the edit window. Typically in my film mix template its not on as that's all pre-assigned. But that's obviously an easy add I actually can do on my own.....:)

                                                                          Thanks again, an amazing time and button pushing saver!!!.........Andy D.

                                                                          P.S. our ADR mixer Jamieson was showing me all the cool new stuff he's been doing in SF this morning. Especially in ADR with talent and film makers not really wanting to be here at all (well before too, but even more so now in our Covid world). Huge deal man. You need to apply for Emmy, Oscar, CAS, MPSE engineering consideration next year. This is a big deal Christian!

                                                                          1. Wow, that's an awesome testimonial. Thank you so much for the kind words, Andy!

                                                                          2. In reply tochrscheuer:
                                                                            AAndy Daddario @Andy_Daddario
                                                                              2020-11-12 18:45:15.233Z

                                                                              Hey Christian, one follow up question. Because Andy is "insanely lazy" when it comes to button pushing, how would I take this one step fruther? Once the level amount is set (let's say -3db), how would I apply that to the remaining Stems without having to input the number each time?

                                                                              Easy for me to script and Select the next Master Track Fader through my Stems, but how would I capture the input number (using -3db as the example) as the variable and apply it to the remaining Master Faders? (without having to input it each time on the screen).

                                                                              Otherwise works beautifully. Added the short script to make sure the I/O view is active, and works perfectly.

                                                                              Thanks!.......Andy

                                                                              1. Hi Andy,

                                                                                Check the template version I added of this in the "Pro Tools Utilities" package. In that, you can have a preset with -3dB for example :)

                                                                                1. AAndy Daddario @Andy_Daddario
                                                                                    2020-11-12 19:32:37.149Z

                                                                                    Hey Christian, not sure why but getting an error on using these. I did make sure the I/O view was open.

                                                                                    1. AAndy Daddario @Andy_Daddario
                                                                                        2020-11-12 19:33:36.354Z

                                                                                        Let me clarify, I'm getting this in the Package, not the script you posted which is working beautifully.

                                                                                      • In reply tochrscheuer:
                                                                                        AAndy Daddario @Andy_Daddario
                                                                                          2020-11-12 19:47:54.407Z

                                                                                          Whoops.....Never mind. My PT system sometimes stops following commands, not sure why. Did a full re-start and it's all fine now. I haven't been able to figure it out, but about once a day some of the SF commands stop communicating.

                                                                                          All is good on the new Package, completely on my end. Thanks......Andy