No internet connection
  1. Home
  2. How to

File Handling / Version Control of Pro Tools Session Files

I would love to have some simple scripts to move or copy a file into a specific folder. In particular I would like to have a script that does the following:

  1. Duplicate the session file and up-rev the file name from 01 to 02 (or whatever number comes next)
  2. Move the original session file into a foldewr within the session folder called "old".
Solved in post #3, click to view
  • 23 replies

There are 23 replies. Estimated reading time: 22 minutes

  1. Hi @sbiss

    You can get inspiration to #1 in my package Pro Tools Utilities: "Save Session As New Version"

    1. Christian Scheuer @chrscheuer2019-11-18 20:06:56.674Z2019-11-18 20:38:38.110Z

      For number 2:

      To move a file, you'll need to use the action sf.file.move, like:

      sf.file.move({
          sourcePath: oldPath,
          destinationPath: newPath,
      });
      

      The slight issue with doing this is you shouldn't try to move the existing file before Pro Tools is surely done saving the new file, otherwise you might run into problems. AFAIK there's no way for us to know for sure that PT is done saving, so we would need to add an arbitrary wait of about 1s.

      Anyway, to put the file move command together with the existing script, do something like this:

      function saveSessionAsNewVersion() {
      
          //First save the current version
          sf.ui.proTools.getMenuItem('File', 'Save').elementClick({}, function () { }); //can be disabled
      
          //Get our filename without extension
          var fileNameWithoutExtension = sf.ui.proTools.mainWindow.invalidate().sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
      
          //Create a new name (get the name and suffixed number - if your session name was 'My Session 42' then save 'My Session ' in grps[1] and '42' in grps[2])
          var grps = fileNameWithoutExtension.match(/^(.+?)(\d+)$/);
      
          //Construct a new name based on the prefix and the number (+1), followed by the '.ptx' suffix. If there was no number, just add ' 2'
          var newNumber = !grps || grps.length === 0 || isNaN(Number(grps[2])) ? '_2' : ((Number(grps[2]) + 1) + '');
          var newName = (grps ? grps[1] : (fileNameWithoutExtension)) + newNumber + '.ptx';
      
          //Invoke File Save As.
          sf.ui.proTools.getMenuItem('File', 'Save As...').elementClick();
      
          //Wait for the Save dialog to appear
          var dlg = sf.ui.proTools.windows.invalidate().whoseTitle.is('Save').waitFor().element;
      
          //Enter the new name
          dlg.textFields.first.value.value = newName;
      
          //Click Save
          dlg.buttons.whoseTitle.is('Save').first.elementClick();
      
      }
      
      function moveFileToOldSessions(path) {
          var oldSessionsDir = path.split('/').slice(0, -1).join('/') + '/Old Sessions';
          var filename = path.split('/').slice(-1)[0];
      
          //Make sure "Old Sessions" dir exists
          sf.file.directoryCreate({
              path: oldSessionsDir,
          });
      
          //Move file there
          sf.file.move({
              sourcePath: path,
              destinationPath: oldSessionsDir + '/' + filename,
          });
      }
      
      sf.ui.proTools.mainWindow.invalidate();
      var oldSessionPath = sf.ui.proTools.mainWindow.sessionPath;
      
      saveSessionAsNewVersion();
      
      sf.wait({ intervalMs: 1000 });
      
      moveFileToOldSessions(oldSessionPath);
      

      Note, please test on a test session first, not on production session, since this handles files, so you want to be extra sure that it works as intended :)

      ReplySolution
      1. @sbiss I edited my post with an update to the script, so please copy/paste it again

        1. Actually I think my logic was flawed around the need for a "wait", since the script actually first saves the existing session, and then saves the new version. This way we should be sure that the existing file has been fully written by the time we get to moving the file. Of course that would need testing.

          1. Works perfectly! Except it saves my "Session 01" as "Session 2". But that is a relatively minor issue.

        2. In reply tochrscheuer:

          This script works great....how can I add a function that creates a folder in the bounced mixes folder with the name of the current version session ending in MIXES AND STEMS

          1. Something like this?

            
            var sessionPath = sf.ui.proTools.mainWindow.sessionPath;
            var sessionDir = sessionPath.split('/').slice(0, -1).join('/');
            var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
            var mixesDir = `${sessionDir}/Bounced Files/${sessionName} MIXES AND STEMS`;
            
            //Make sure the mixes directory exists
            sf.file.directoryCreate({
                path: mixesDir,
            });
            
            1. That ALMOST works...the new MIXES AND STEMS folder is created with the prior version ProTools session name, not the newly created one.

              1. var sessionPath = sf.ui.proTools.mainWindow.invalidate().sessionPath;
                var sessionDir = sessionPath.split('/').slice(0, -1).join('/');
                var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
                var mixesDir = `${sessionDir}/Bounced Files/${sessionName} MIXES AND STEMS`;
                
                //Make sure the mixes directory exists
                sf.file.directoryCreate({
                    path: mixesDir,
                });
                
                1. Wammo!!!! Thank you Christian. Another 40 hours added to my free time by using efficicent macros!

                  1. Yay - awesome :D

                    1. Just so I understand, are you inserting this script into the above script and if so where?

                      1. at the bottom

                      2. Sooo....one thing I didn' think of.

                        I'd like to make the first MIXES AND STEMS FOLDER with the current version name. In other words, a macro that does what this one does, without doing the "save as" first.

                        Trying this....but not working.

                        var sessionPath = sf.ui.proTools.mainWindow.invalidate().sessionPath;
                        var sessionPath = sf.ui.proTools.mainWindow.sessionPath;
                        var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
                        var mixesDir = ${sessionDir}/Bounced Files/${sessionName}_MIXES AND STEMS;

                        //Make sure the mixes directory exists
                        sf.file.directoryCreate({
                        path: mixesDir,
                        });

                        sf.appleScript.finder.open(newDir);
                        sf.ui.finder.appActivateMainWindow();
                        sf.ui.finder.windows.first.windowMove({
                        position: { x: 300, y: 200 },
                        size: { x: 1600, y: 500 },
                        });

                        sf.wait({intervalMs:503});

                        //Make sure Pro Tools Main Window is active

                        sf.ui.proTools.appActivateMainWindow();

                        }

                        main();

                      3. In reply tochrscheuer:

                        so another mod on this one. I'd like the macro to save as & rename the session with the suffix "_MIX_V1" and create the folder with the session name +MIXES AND STEMS. However, if I already have a "MIX_V1", then I'd like it to go to the next number. Here's how I have created it in 2 different scripts (with obvious scripting repetition) that I'd like to simplify and marry into one script with an IF/THEN variable.

                        PART 1:

                        function saveSessionAsNewVersion() {

                        //First save the current version
                        sf.ui.proTools.getMenuItem('File', 'Save').elementClick({}, function () { }); //can be disabled
                        
                        //Get our filename without extension
                        var fileNameWithoutExtension = sf.ui.proTools.mainWindow.invalidate().sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
                        
                        //Create a new name (get the name and suffixed number - if your session name was 'My Session 42' then save 'My Session ' in grps[1] and '42' in grps[2])
                        var grps = fileNameWithoutExtension.match(/^(.+?)(\d+)$/);
                        
                        //Construct a new name based on the prefix + MIX_V1
                        var newName = (fileNameWithoutExtension) + '_MIX_V1.ptx';
                        
                        //Invoke File Save As.
                        sf.ui.proTools.getMenuItem('File', 'Save As...').elementClick();
                        
                        //Wait for the Save dialog to appear
                        var dlg = sf.ui.proTools.windows.invalidate().whoseTitle.is('Save').waitFor().element;
                        
                        //Enter the new name
                        dlg.textFields.first.value.value = newName;
                        
                        //Click Save
                        dlg.buttons.whoseTitle.is('Save').first.elementClick();
                        

                        }

                        function moveFileToOldSessions(path) {
                        var oldSessionsDir = path.split('/').slice(0, -1).join('/') + '/Old Sessions';
                        var filename = path.split('/').slice(-1)[0];

                        //Make sure "Old Sessions" dir exists
                        sf.file.directoryCreate({
                            path: oldSessionsDir,
                        });
                        
                        //Move file there
                        sf.file.move({
                            sourcePath: path,
                            destinationPath: oldSessionsDir + '/' + filename,
                        });
                        

                        }

                        sf.ui.proTools.mainWindow.invalidate();
                        var oldSessionPath = sf.ui.proTools.mainWindow.sessionPath;

                        saveSessionAsNewVersion();

                        sf.wait({ intervalMs: 1000 });

                        moveFileToOldSessions(oldSessionPath);

                        var sessionPath = sf.ui.proTools.mainWindow.invalidate().sessionPath;
                        var sessionDir = sessionPath.split('/').slice(0, -1).join('/');
                        var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
                        var mixesDir = ${sessionDir}/Bounced Files/${sessionName}_MIXES AND STEMS;

                        //Make sure the mixes directory exists
                        sf.file.directoryCreate({
                        path: mixesDir,
                        });

                        PART 2:

                        function saveSessionAsNewVersion() {

                        //First save the current version
                        sf.ui.proTools.getMenuItem('File', 'Save').elementClick({}, function () { }); //can be disabled
                        
                        //Get our filename without extension
                        var fileNameWithoutExtension = sf.ui.proTools.mainWindow.invalidate().sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
                        
                        //Create a new name (get the name and suffixed number - if your session name was 'My Session 42' then save 'My Session ' in grps[1] and '42' in grps[2])
                        var grps = fileNameWithoutExtension.match(/^(.+?)(\d+)$/);
                        
                        //Construct a new name based on the prefix and the number (+1), followed by the '.ptx' suffix. If there was no number, just add ' 2'
                        var newNumber = !grps || grps.length === 0 || isNaN(Number(grps[2])) ? '_2' : ((Number(grps[2]) + 1) + '');
                        var newName = (grps ? grps[1] : (fileNameWithoutExtension)) + newNumber + '.ptx';
                        
                        //Invoke File Save As.
                        sf.ui.proTools.getMenuItem('File', 'Save As...').elementClick();
                        
                        //Wait for the Save dialog to appear
                        var dlg = sf.ui.proTools.windows.invalidate().whoseTitle.is('Save').waitFor().element;
                        
                        //Enter the new name
                        dlg.textFields.first.value.value = newName;
                        
                        //Click Save
                        dlg.buttons.whoseTitle.is('Save').first.elementClick();
                        

                        }

                        function moveFileToOldSessions(path) {
                        var oldSessionsDir = path.split('/').slice(0, -1).join('/') + '/Old Sessions';
                        var filename = path.split('/').slice(-1)[0];

                        //Make sure "Old Sessions" dir exists
                        sf.file.directoryCreate({
                            path: oldSessionsDir,
                        });
                        
                        //Move file there
                        sf.file.move({
                            sourcePath: path,
                            destinationPath: oldSessionsDir + '/' + filename,
                        });
                        

                        }

                        sf.ui.proTools.mainWindow.invalidate();
                        var oldSessionPath = sf.ui.proTools.mainWindow.sessionPath;

                        saveSessionAsNewVersion();

                        sf.wait({ intervalMs: 1000 });

                        moveFileToOldSessions(oldSessionPath);

                        var sessionPath = sf.ui.proTools.mainWindow.invalidate().sessionPath;
                        var sessionDir = sessionPath.split('/').slice(0, -1).join('/');
                        var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
                        var mixesDir = ${sessionDir}/Bounced Files/${sessionName}_MIXES AND STEMS;

                        //Make sure the mixes directory exists
                        sf.file.directoryCreate({
                        path: mixesDir,
                        });

              2. In reply tochrscheuer:
                MMatt Cahill @Matt_Cahill
                  2023-01-12 17:54:08.252Z

                  Hi @chrscheuer

                  Trying to find your Pro Tools Utilities package but I can't see it on the store?

                  1. That has been deprecated in favor of the official Pro Tools package that comes with all versions of SF :)

                    1. MMatt Cahill @Matt_Cahill
                        2023-01-13 10:16:01.298Z

                        Okay awesome, thank you Christian!

                  2. J
                    In reply tosbiss:
                    Jeremy Bowker @Jeremy_Bowker
                      2021-07-20 04:33:32.622Z

                      This is all very impressive! Is there a way to have it "up-rev" a session when when an underscore and initials are appended to the end of a session name? Example: "SessionName_01_JD"

                      1. Hi Jeremy,

                        Try this (untested):

                        
                        /**@callback OnGetNewNameCallback
                         * @param {{ fileNameWithoutExtension: string }} args
                         * @return {string}
                        */
                        /**
                         * @param {object} args
                         * @param {OnGetNewNameCallback} args.onGetNewName
                         */
                        function saveSessionAsNewVersion({ onGetNewName }) {
                        
                            //First save the current version
                            sf.ui.proTools.getMenuItem('File', 'Save').elementClick({}, function () { }); //can be disabled
                        
                            //Get our filename without extension
                            var fileNameWithoutExtension = sf.ui.proTools.mainWindow.invalidate().sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
                        
                            var newName = onGetNewName({ fileNameWithoutExtension });
                        
                            //Invoke File Save As.
                            sf.ui.proTools.getMenuItem('File', 'Save As...').elementClick();
                        
                            //Wait for the Save dialog to appear
                            var dlg = sf.ui.proTools.windows.invalidate().whoseTitle.is('Save').waitFor().element;
                        
                            //Enter the new name
                            dlg.textFields.first.value.value = newName;
                        
                            //Click Save
                            dlg.buttons.whoseTitle.is('Save').first.elementClick();
                        
                        }
                        
                        /**
                        * @param {string} path
                        */
                        function moveFileToOldSessions(path) {
                            var oldSessionsDir = path.split('/').slice(0, -1).join('/') + '/Old Sessions';
                            var filename = path.split('/').slice(-1)[0];
                        
                            //Make sure "Old Sessions" dir exists
                            sf.file.directoryCreate({
                                path: oldSessionsDir,
                            });
                        
                            //Move file there
                            sf.file.move({
                                sourcePath: path,
                                destinationPath: oldSessionsDir + '/' + filename,
                            });
                        }
                        
                        function main() {
                        
                            sf.ui.proTools.mainWindow.invalidate();
                        
                            var oldSessionPath = sf.ui.proTools.mainWindow.sessionPath;
                        
                            saveSessionAsNewVersion({
                                onGetNewName: ({ fileNameWithoutExtension }) => {
                                    //Create a new name (get the name and suffixed number - if your session name was 'My Session 42' then save 'My Session ' in grps[1] and '42' in grps[2])
                                    var grps = fileNameWithoutExtension.match(/^(.+?)(\d+)(_[a-zA-Z]+)?$/);
                        
                                    //Construct a new name based on the prefix and the number (+1), followed by a potential '_INITIALS' suffix, and then the '.ptx' extension.
                                    //If there was no number, just add '_2'
                                    var newNumber = !grps || grps.length === 0 || isNaN(Number(grps[2])) ? '_2' : ((Number(grps[2]) + 1) + '');
                        
                                    const str = s => s === undefined ? '' : s;
                                    
                                    var newName = (grps ? grps[1] : (fileNameWithoutExtension)) + newNumber + str(grps && grps[3]) + '.ptx';
                        
                                    return newName;
                                }
                            });
                        
                            sf.wait({ intervalMs: 1000 });
                        
                            moveFileToOldSessions(oldSessionPath);
                        }
                        
                        main();
                        
                        1. JJeremy Bowker @Jeremy_Bowker
                            2021-07-20 16:26:43.062Z

                            Well... THIS is amazing! Thank you. I ended up needing to add a brief wait right after "Invoke File Save As" and it works like a charm. Thank you @chrscheuer !

                        2. S
                          In reply tosbiss:

                          This has been on my to do list. Amazing! Typically our naming uses "01", "02", etc, instead of "1", "2". Is there a tweak to add a zero until the version reaches "10"?

                          1. A
                            In reply tosbiss:
                            Alvin Wee @Alvin_Wee
                              2022-03-17 18:44:53.824Z

                              Following up on this guys. I modified one of script from here and it only works maybe 30% of the time to what Jeremy's saying

                              Context: I also add the "01" "02" and "03" for my save versions. I have a script here that i modified from one of the scripts here I seem to run into weird errors. like once it gets to the "Save as" window and then just freezing there wihtout chanign the numbers and after the delay just pops up the error message:

                              *Element was not found or removed after waiting 5000
                              ms (Save Session as New Version: Line 19)
                              *

                              I'd appreciate any feedback. Thank you!

                              
                              //First save the current version
                              //sf.ui.proTools.getMenuItem('File', 'Save').elementClick({}, function(){}); //can be disabled
                              
                              //Get our filename without extension
                              var fileNameWithoutExtension = sf.ui.proTools.mainWindow.invalidate().sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
                              
                              //Create a new name (get the name and suffixed number - if your session name was 'My Session 42' then save 'My Session ' in grps[1] and '42' in grps[2])
                              var grps = fileNameWithoutExtension.match(/^(.+?)(\d+)$/);
                              
                              //Construct a new name based on the prefix and the number (+1), followed by the '.ptx' suffix. If there was no number, just add '02'
                              var newNumber = !grps || grps.length === 0 || isNaN(Number(grps[2])) ? '02' : ("0" + ((Number(grps[2]) + 1) + '')).slice(-2);
                              var newName = (grps ? grps[1] : (fileNameWithoutExtension)) + newNumber;
                              
                              //Invoke File Save As.
                              sf.ui.proTools.getMenuItem('File', 'Save As...').elementClick();
                              
                              //Wait for the Save dialog to appear
                              var dlg = sf.ui.proTools.windows.invalidate().whoseTitle.is('Save').waitFor().element;
                              //Enter the new name
                              
                              dlg.textFields.first.value.value = newName;
                              //sf.keyboard.type({ text: newName });
                              
                              //Click Save
                              dlg.buttons.whoseTitle.is('Save').first.elementClick();
                              
                              

                              EDITED becuase i pasted the wrong code.