No internet connection
  1. Home
  2. How to

Duplicate a track without media or automation, renaming it to remove ".dup" and add a number

By Christian Scheuer @chrscheuer2018-07-29 16:36:39.219Z2018-07-30 15:25:09.526Z

This was developed in coop with @Fokke.

It makes a copy of your current track, removes the ".dup1" suffix and just adds an increasing number.
So if you duplicate "Audio 5" it will create a new copy of that with the name "Audio 6".

I have slightly different duplication settings than Fokke - you can freely set your true/false settings as wished.

//Research and code from Fokke van Saane and Christian Scheuer

sf.ui.proTools.trackDuplicateSelected({
    duplicateActivePlaylist: false,
    duplicateAlternatePlaylists: false,
    duplicateAutomation: false,
    duplicateGroupAssignments: true,
    duplicateInserts: true,
    duplicateSends: true,
    insertAfterLastSelectedTrack: true,
    numberOfDuplicates: 1
})

sf.ui.proTools.selectedTrack.trackRename({
    renameFunction: function (name) {
        var grps = name.match(/^([^\d]*)( ?)(\d*)\.dup.*/);;
        var baseName = grps[1];
        var space = grps[2];
        var numName = grps[3];
        if (numName == "") space = " ";
        var newNum = numName == "" ? 2 : Number(numName) + 1;
        return baseName + space + (newNum + '');
    }
});

For a commented version, see: https://forum.soundflow.org/-232#post-15

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

There are 29 replies. Estimated reading time: 24 minutes

  1. Solution in question

    ReplySolution
    1. ?
      In reply tochrscheuer:
      @anon6770933309
        2018-07-29 17:14:51.226Z

        Nice, I only wish this was commented better so that others can learn from this. These private solutions for a single someone do not help anyone else. 😕

        And it simply doesn't work here.

        What does this mean/do: var grps = name.match(/^([^\d])(\d).dup.*/);; ?

        1. Cool, I'll update with comments. First let's see what doesn't work for you - can you elaborate on doesn't work (what's the track you're trying on, what happens)?

          1. ?@anon6770933309
              2018-07-30 07:42:04.087Z

              I ran the script while selecting a stereo Audio track called "Audio 1", the script duplicated the track and then hang. 100% reproducible. The duplicated track was not renamed. The SF icon stays blue so the script was still running, only way out is to quit SF.
              I'll send you the log file.

              1. ?@anon6770933309
                  2018-07-30 09:25:28.754Z

                  Turns out it fails when the Track List is closed. 😉

                  30.07.2018 11:23:03.41 [Backend]: Clicking with mouse here: 1287, 424

                  30.07.2018 11:23:04.04 [Backend]: Could not get UIElement for AxPtTrackListView: Could not find Track List table in PT11/12

                  30.07.2018 11:23:04.06 [Backend]: Could not get UIElement for AxPtTrackListView: Could not find Track List table in PT11/12

                  1. ?@anon6770933309
                      2018-07-30 09:57:17.149Z

                      And another issue, if the track is called "Bass" or the like -when it has no number- the duplicated track will be named "Bass2" (with no space).
                      I don't wanna sound fussy but I thought I mention it nevertheless. 😉

                      1. Thanks for detailed replys, @Oli_Em. I can repro it here. Looking into it.

                        If you didn't already know - when the blue icon is hanging, there are 2 new options in SF to deal with this:

                        • Stop all running commands
                        • Restart SoundFlow

                        The "Restart SoundFlow" will only restart the backend, so the icon will flash red for a second and you'll be back to normal.

                        1. ?@anon6770933309
                            2018-07-30 12:54:35.371Z

                            Ah yeah, forgot about it, thx for reminding me! I need to get used to the new features. 😉

                          • In reply toanon6770933309:

                            This is fixed in this script (un-commented version first).
                            This script will duplicate "Bass" to "Bass 2" (per default a space), "Bass1" (no space) to "Bass2" (no space), "Bass 1" to "Bass 2", etc.

                            sf.ui.proTools.selectedTrack.trackRename({
                                renameFunction: function (name) {
                                    var grps = name.match(/^([^\d]*)( ?)(\d*)\.dup.*/);;
                                    var baseName = grps[1];
                                    var space = grps[2];
                                    var numName = grps[3];
                                    if (numName == "") space = " ";
                                    var newNum = numName == "" ? 2 : Number(numName) + 1;
                                    return baseName + space + (newNum + '');
                                }
                            });
                            
                            1. Commented version:

                              sf.ui.proTools.selectedTrack.trackRename({
                                  renameFunction: function (name) {
                                       //This function gets called after the Rename track dialog is open
                                      //the argument 'name' holds the existing name, eg. "Audio 4.dup1"
                                      //We're supposed to eventually return the target name we want from this function.
                                      
                                      var grps = name.match(/^([^\d]*)( ?)(\d*)\.dup.*/);;
                                      //This regular expression matches a string containing of the following groups (each group is in parentheses)
                                      //Group 1 - syntax: ([^\d]*) - meaning: Match any number (*) of characters that are NOT digits ([^\d]). This will match "Audio"
                                      //Group 2 - syntax: ( ?) - meaning: Match either 0 or 1 (?) space character 
                                      //Group 3 - syntax: (\d*)  - meaning: Match any number (*) of characters that are digits (\d). This will match "4".
                                      //After last group- syntax: \.dup.* - meaning: Match a dot (\.), the text "dup", and then ANY character (.), any number of times (*)
                              
                                      //Save out the groups, baseName, space, numName
                                      var baseName = grps[1];
                                      var space = grps[2];
                                      var numName = grps[3];
                              
                                      //If you didn't have a number, by default we want a space ' ' before our new #2 track
                                      if (numName == "") space = " ";
                              
                                      //Create the new number. If there wasn't one, we'll default to 2, if there was one, convert our string to a number, and add 1 to that
                                      var newNum = numName == "" ? 2 : Number(numName) + 1;
                              
                                      //Return the new name, a combination of the base name "Audio", a space or not " ", and the new number (converted to a string to make sure we don't mix up types)
                                      return baseName + space + (newNum + '');
                                  }
                              });
                              
                              1. ?@anon6770933309
                                  2018-07-30 18:33:43.974Z

                                  Thank you.

                                  1. In reply tochrscheuer:
                                    ?@anon6770933309
                                      2018-10-03 08:17:52.856Z

                                      Can this be modified so that the renamed tracks don't get number suffixes but letters starting from "b"? So that "Audio.dup1" becomes "Audio b", "Audio b" becomes "Audio c", "Bass 1" becomes "Bass 1b" etc etc.?

                                      1. Yes.
                                        Question is though, the script above deals with it by reading the number from the existing track that you were duplicating. So it would use that input (say you were duping "Audio 6") it would then use the 6 to know that the next track should be called 7.
                                        If we use letters for the numbering the algo would be more difficult (for the user) to understand. Since all words end with a letter, if you had a track "Bass a" it becomes "Bass b". But what if you just have "Bass", then it would become "Bast" (just based on last letter). Should it only match if there is a space followed by a single letter?

                                        1. ?@anon6770933309
                                            2018-10-03 08:33:42.789Z

                                            I know what I asked for is complicated which is why I asked in the first place. Lets make it as easy as possible and less complicated. So yes, it should only match if there is a space followed by a single letter. But then it wouldn't rename track names like"Vo 1b", right? I think I could live with that.

                                            1. @Oli_Em try this:

                                              sf.ui.proTools.selectedTrack.trackRename({
                                                  renameFunction: function (name) {
                                                      var letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
                                              
                                                      //This function gets called after the Rename track dialog is open
                                                      //the argument 'name' holds the existing name, eg. "Audio B.dup1"
                                                      //We're supposed to eventually return the target name we want from this function.
                                              
                                                      var grps = name.match(/^(.*)( )([a-zA-Z])(\.dup.*|)$/);
                                                      //This regular expression matches a string containing of the following groups (each group is in parentheses)
                                                      //Group 1 - syntax: (.*) - meaning: Match any number (*) of any characters (.) This will match "Audio"
                                                      //Group 2 - syntax: ( ) - meaning: Match 1 space character 
                                                      //Group 3 - syntax: ([a-zA-Z])  - meaning: Match 1 character that is a letter. This will match "B"
                                                      //After last group- syntax: \.dup.* - meaning: Match a dot (\.), the text "dup", and then ANY character (.), any number of times (*)
                                              
                                                      //Save out the groups, baseName, space, numName
                                                      var baseName, space, numName;
                                                      if (grps) {
                                                          baseName = grps[1];
                                                          space = grps[2];
                                                          numName = grps[3];
                                                      } else {
                                                          //It didn't match our format. Try again without the requirement of a suffix
                                                          if (name.indexOf('.dup') >= 0)
                                                              baseName = name.substring(0, name.indexOf('.dup')); //Get the base name before any .dup
                                                          else
                                                              baseName = name;
                                                          space = " "; //default space
                                                          numName = "";
                                                      }
                                              
                                                      //If you didn't have a number, by default we want a space ' ' before our new #2 track
                                                      if (numName == "") space = " ";
                                              
                                                      //Create the new number. If there wasn't one, we'll default to 2, if there was one, convert our string to a number, and add 1 to that
                                                      var newIndex = 1; //Start with 2nd index (1 because indices are always 0-based)
                                                      if (numName) {
                                                          var idx = letters.indexOf(numName.toUpperCase()); //Find the index (0-based)
                                                          if (idx >= 0) {
                                                              newIndex = idx + 1; //Set to the found index + 1
                                                          }
                                                          //If not found, default to 2nd index (1) which is already set
                                                      }
                                                      if (newIndex < 0 || newIndex >= letters.length)
                                                          throw 'New index out of bounds'; //We reached Z or some other error
                                              
                                                      //Return the new name, a combination of the base name "Audio", a space or not " ", and the new letter
                                                      return baseName + space + letters[newIndex];
                                                  }
                                              });
                                              
                                              1. And if you try this instead (2nd version) it might help with the 1B -> 1C case:

                                                sf.ui.proTools.selectedTrack.trackRename({
                                                    renameFunction: function (name) {
                                                        var letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
                                                
                                                        //This function gets called after the Rename track dialog is open
                                                        //the argument 'name' holds the existing name, eg. "Audio B.dup1"
                                                        //We're supposed to eventually return the target name we want from this function.
                                                
                                                        var grps = name.match(/^(.*)([ \d])([a-zA-Z])(\.dup.*|)$/);
                                                        //This regular expression matches a string containing of the following groups (each group is in parentheses)
                                                        //Group 1 - syntax: (.*) - meaning: Match any number (*) of any characters (.) This will match "Audio"
                                                        //Group 2 - syntax: ( ) - meaning: Match 1 space character 
                                                        //Group 3 - syntax: ([a-zA-Z])  - meaning: Match 1 character that is a letter. This will match "B"
                                                        //After last group- syntax: \.dup.* - meaning: Match a dot (\.), the text "dup", and then ANY character (.), any number of times (*)
                                                
                                                        //Save out the groups, baseName, space, numName
                                                        var baseName, space, numName;
                                                        if (grps) {
                                                            baseName = grps[1];
                                                            space = grps[2];
                                                            numName = grps[3];
                                                        } else {
                                                            //It didn't match our format. Try again without the requirement of a suffix
                                                            if (name.indexOf('.dup') >= 0)
                                                                baseName = name.substring(0, name.indexOf('.dup')); //Get the base name before any .dup
                                                            else
                                                                baseName = name;
                                                            space = " "; //default space
                                                            numName = "";
                                                        }
                                                
                                                        //If you didn't have a number, by default we want a space ' ' before our new #2 track
                                                        if (numName == "") space = " ";
                                                
                                                        //Create the new number. If there wasn't one, we'll default to 2, if there was one, convert our string to a number, and add 1 to that
                                                        var newIndex = 1; //Start with 2nd index (1 because indices are always 0-based)
                                                        if (numName) {
                                                            var idx = letters.indexOf(numName.toUpperCase()); //Find the index (0-based)
                                                            if (idx >= 0) {
                                                                newIndex = idx + 1; //Set to the found index + 1
                                                            }
                                                            //If not found, default to 2nd index (1) which is already set
                                                        }
                                                        if (newIndex < 0 || newIndex >= letters.length)
                                                            throw 'New index out of bounds'; //We reached Z or some other error
                                                
                                                        //Return the new name, a combination of the base name "Audio", a space or not " ", and the new letter
                                                        return baseName + space + letters[newIndex];
                                                    }
                                                });
                                                
                                                1. ?@anon6770933309
                                                    2018-10-03 09:05:58.957Z

                                                    Excellent! Thx so much. 😀
                                                    I cannot see a difference in the performance of the 2 versions though. I see the code differences but they both handle the 1B -> 1C cases just fine.

                                                    1. Oh cool, but nice that it works!
                                                      The second version considers a digit a valid "space" before the last character so it should take a different code path.
                                                      I don't remember what didn't work for me in the 1st version though :/

                                                      1. ?@anon6770933309
                                                          2018-10-03 09:17:00.177Z

                                                          I see the difference now, a track named “Vo 1b” (exactly like this with no space before lowercase letter b) becomes “Vo 1b B” while the 2nd one renames it to “Vo 1C”, thus better. 😉

                                                          1. Nice. Also try this version. It will use a lowercase letter if your original letter was also lowercase.

                                                            sf.ui.proTools.selectedTrack.trackRename({
                                                                renameFunction: function (name) {
                                                                    var letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
                                                            
                                                                    //This function gets called after the Rename track dialog is open
                                                                    //the argument 'name' holds the existing name, eg. "Audio B.dup1"
                                                                    //We're supposed to eventually return the target name we want from this function.
                                                            
                                                                    var grps = name.match(/^(.*)([ \d])([a-zA-Z])(\.dup.*|)$/);
                                                                    //This regular expression matches a string containing of the following groups (each group is in parentheses)
                                                                    //Group 1 - syntax: (.*) - meaning: Match any number (*) of any characters (.) This will match "Audio"
                                                                    //Group 2 - syntax: ( ) - meaning: Match 1 space character 
                                                                    //Group 3 - syntax: ([a-zA-Z])  - meaning: Match 1 character that is a letter. This will match "B"
                                                                    //After last group- syntax: \.dup.* - meaning: Match a dot (\.), the text "dup", and then ANY character (.), any number of times (*)
                                                            
                                                                    //Save out the groups, baseName, space, numName
                                                                    var baseName, space, numName;
                                                                    if (grps) {
                                                                        baseName = grps[1];
                                                                        space = grps[2];
                                                                        numName = grps[3];
                                                                    } else {
                                                                        //It didn't match our format. Try again without the requirement of a suffix
                                                                        if (name.indexOf('.dup') >= 0)
                                                                            baseName = name.substring(0, name.indexOf('.dup')); //Get the base name before any .dup
                                                                        else
                                                                            baseName = name;
                                                                        space = " "; //default space
                                                                        numName = "";
                                                                    }
                                                            
                                                                    //If you didn't have a number, by default we want a space ' ' before our new #2 track
                                                                    if (numName == "") space = " ";
                                                            
                                                                    //Create the new number. If there wasn't one, we'll default to 2, if there was one, convert our string to a number, and add 1 to that
                                                                    var newIndex = 1; //Start with 2nd index (1 because indices are always 0-based)
                                                                    if (numName) {
                                                                        var idx = letters.indexOf(numName.toUpperCase()); //Find the index (0-based)
                                                                        if (idx >= 0) {
                                                                            newIndex = idx + 1; //Set to the found index + 1
                                                                        }
                                                                        //If not found, default to 2nd index (1) which is already set
                                                                    }
                                                                    if (newIndex < 0 || newIndex >= letters.length)
                                                                        throw 'New index out of bounds'; //We reached Z or some other error
                                                            
                                                                    var letter = letters[newIndex];
                                                                    if (numName && numName.toLowerCase() === numName)
                                                                        letter = letter.toLowerCase(); //Make letter lowercase if the input was lowercase
                                                            
                                                                    //Return the new name, a combination of the base name "Audio", a space or not " ", and the new letter
                                                                    return baseName + space + letter;
                                                                }
                                                            });
                                                            
                                                            1. ?@anon6770933309
                                                                2018-10-03 09:36:53.221Z

                                                                Very cool. 👍

                                            2. In reply tochrscheuer:
                                              ?@anon6770933309
                                                2018-07-30 18:33:32.711Z

                                                Confirmed fixed.

                                            3. In reply toanon6770933309:

                                              This has been fixed now in internal build.

                                    • In reply tochrscheuer:

                                      Commented version of the rename action:

                                      //Rename the selected track - use the renameFunction so we can rename based on the current name
                                      //Since we just made a duplicate, the current track will be called something like "Audio 4.dup1"
                                      sf.ui.proTools.selectedTrack.trackRename({
                                          renameFunction: function (name) {
                                              //This function gets called after the Rename track dialog is open
                                              //the argument 'name' holds the existing name, eg. "Audio 4.dup1"
                                              //We're supposed to eventually return the target name we want from this function.
                                      
                                              //This regular expression matches a string containing of the following groups (each group is in parentheses)
                                              //Group 1 - syntax: ([^\d]*) - meaning: Match any number (*) of characters that are NOT digits ([^\d]). This will match "Audio "
                                              //Group 2 - syntax: (\d*)  - meaning: Match any number (*) of characters that are digits (\d). This will match "4".
                                              //After last group- syntax: \.dup.* - meaning: Match a dot (\.), the text "dup", and then ANY character (.), any number of times (*)
                                      
                                              var grps = name.match(/^([^\d]*)(\d*)\.dup.*/);;
                                              //The groups will be accessible in grps[1] for group 1, grps[2] for group 2, etc.
                                      
                                              //Save the baseName - "Audio "
                                              var baseName = grps[1];
                                      
                                              //If group 2 (the existing number) is empty (Maybe we didn't use "Audio 4.dup1" but a track like "Guitar.dup1"), then set the number to 1 (so that when we increase, we will make "Guitar 2"). If it DID have a number, eg. "4" for "Audio 4", then save the "4" as a number.
                                              var num = grps[2] == "" ? 1 : Number(grps[2]);
                                      
                                              //Make a complete string based on the base name ("Audio ") plus the number "4", increased by 1, ("5"). We're converting the number to a string by appending the empty string and putting that in a parenthesis to make sure the conversion goes fine.
                                      
                                              //By returning the new name, we tell SF that this is the name we would like it to rename the track to.
                                              return baseName + ((num + 1) + '');
                                          }
                                      });
                                      1. ?@anon6770933309
                                          2018-07-30 09:28:00.615Z

                                          This is great, thank you! 👍

                                          1. In reply tochrscheuer:
                                            JJascha Viehl @Jascha_Viehl
                                              2020-11-11 05:16:57.850Z

                                              Hi,

                                              is there any chance anyone could modify this handy script to work for the duplication of multiple tracks?

                                              1. Hi Jascha.

                                                It's best to start a new thread and link to this one as this one is already marked as solved. We prioritize resources towards unsolved threads :)