No internet connection
  1. Home
  2. Script Sharing

A fully automated Beat Detective script

By Kris Crunk @Kris_Crunk
    2021-02-02 21:27:25.458Z2021-02-02 21:34:43.897Z

    I'm still very new to this, so I'm sure this can be improved upon. But it seems to work great as long as the setup is correct. The drum group needs to be labeled "DRUMS" and be the first group under ALL. The kick needs to be labeled "KICK" - you can adjust note value, sensitivity, trigger pad length, and crossfade length to your liking in the code. These numbers generally work great for most things. The drums are soloed at the end so you can check and fine tune. I've tried it in a few sessions and so far so good.

    sf.ui.proTools.appActivateMainWindow();
    
    sf.ui.proTools.menuClick({
        menuPath: ["Event","Beat Detective"],
    });
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Operation').first.radioButtons.whoseTitle.is('Clip Separation').first.checkboxSet({
        targetValue: "Enable",
    });
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Selection').first.popupButtons.first.popupMenuSelect({
        menuPath: ["1/16 Note"],
    });
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Selection').first.buttons.whoseTitle.is('Capture Selection').first.elementClick();
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Detection:').first.buttons.whoseTitle.is('Analyze').first.elementClick();
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Detection:').first.textFields.whoseTitle.is('NumericEntryText').first.elementSetTextFieldWithAreaValue({
        value: "40",
        useMouseKeyboard: true,
    });
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Detection:').first.textFields.whoseTitle.is('NumericEntryText').allItems[1].elementSetTextFieldWithAreaValue({
        value: "3",
        useMouseKeyboard: true,
    });
    
    sf.ui.proTools.groupsActivateOnly({
        groupName: "DRUMS",
    });
    
    sf.ui.proTools.mainWindow.tables.whoseTitle.is('Group List').first.children.whoseRole.is("AXRow").whoseValue.is('').allItems[1].children.whoseRole.is("AXCell").first.buttons.whoseTitle.is('Selected. , Track selection partially contains group').first.checkboxSet({
        targetValue: "Enable",
    });
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.buttons.whoseTitle.is('Separate').first.elementClick();
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Operation').first.radioButtons.whoseTitle.is('Clip Conform').first.checkboxSet();
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.buttons.whoseTitle.is('Conform').first.elementClick();
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Operation').first.radioButtons.whoseTitle.is('Edit Smoothing').first.checkboxSet();
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Smoothing:').first.radioButtons.whoseTitle.is('Fill And Crossfade').first.checkboxSet();
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.groups.whoseTitle.is('Smoothing:').first.textFields.first.elementSetTextFieldWithAreaValue({
        value: "3",
        useMouseKeyboard: true,
    });
    
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.buttons.whoseTitle.is('Smooth').first.elementClick();
    
    sf.ui.proTools.trackGetByName({ name: "KICK", makeVisible: true }).track.trackSetSolo({
        targetValue: "Enable",
    });
    sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first.getElement('AXCloseButton').elementClick();
    
    • 18 replies

    There are 18 replies. Estimated reading time: 16 minutes

    1. Nice! Making quick work out of those drum edits!

      1. In reply toKris_Crunk:
        Kris Crunk @Kris_Crunk
          2021-02-06 04:59:50.355Z

          I've run into a few snags with this - but am working on it

          1. In reply toKris_Crunk:
            Kitch Membery @Kitch2021-02-08 02:20:33.068Z2021-02-09 09:10:59.386Z

            @Kris_Crunk Mate!

            Really great work on this :-) You are kicking goals!

            I've made some updates that hopefully make it a little more stable and easier to read.

            Some of my changes are as follows;

            • Stored all the settings in an object at the top of the script for easy editing.
            • Deleted all fades before trying Beat Detective.
            • Checked to see if the Beat Detective window was open before trying to open it.
            • I used a function to make sure the text entry into the number fields completed before moving onto the next step.
            • Used a function to select all tracks in the drums group.
            • Changed the get track "Kick" to first selected track.
            • Did some general refactoring to tighten up the code.
            • Added Comments.

            Hope this helps... And again, great work!

            const beatDetectiveSettings = {
                selectionContains: "1/16 Note",
                sensitivity: '82',
                triggerPad: '3',
                crossfadeLength: '3',
                drumGroupName: "DRUMS",
            };
            
            /**
             * @param {AxElement} window
             * @param {AxElement} field
             * @param {string} num
             */
            function setNumericEntryTextField(window, field, num) {
                window.elementRaise();
                field.elementClick();
            
                sf.keyboard.type({ text: num });
            
                var i = 0;
            
                while (field.value.invalidate().value !== num) {
                    sf.wait({ intervalMs: 50 });
                };
            
                sf.keyboard.press({ keys: 'return' });
            }
            
            /**
             * @param {string} groupName
             */
            function selectAllTracksInGroup(groupName) {
                sf.ui.proTools.mainWindow.groupListView.childrenByRole("AXRow").filter(r => {
                    r.childrenByRole("AXCell").allItems[1].buttons.first.title.value.split(/-\s/)[1] === groupName &&
                        r.childrenByRole("AXCell").first.buttons.first.title.invalidate().value === 'Selected. , Track selection partially contains group'
                    r.childrenByRole("AXCell").first.buttons.first.elementClick();
                });
            }
            
            function doBeatDetective(settings) {
                //Deconstruct Beat Detective Settings
                const { selectionContains, sensitivity, triggerPad, crossfadeLength, drumGroupName, } = settings;
            
                //Activate Pro Tools main window
                sf.ui.proTools.appActivateMainWindow();
            
                //Get originally selected tracks
                const originalTracks = sf.ui.proTools.selectedTrackNames;
            
                //Delete Fades
                sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Fades', 'Delete'] });
            
                //Variable for Beat Detective window
                const beatDetectiveWindow = sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first;
            
                //Open Beat Detective
                if (!beatDetectiveWindow.exists) {
                    sf.ui.proTools.menuClick({
                        menuPath: ["Event", "Beat Detective"],
                        targetValue: 'Enable'
                    });
                }
            
                //Wait for Beat Detective Window.
                beatDetectiveWindow.elementWaitFor();
            
                //Variables for Beat Detective pannels.
                const operationPanel = beatDetectiveWindow.groups.whoseTitle.is('Operation').first;
                const selectionPanel = beatDetectiveWindow.groups.whoseTitle.is('Selection').first;
                const detectionPanel = beatDetectiveWindow.groups.whoseTitle.is('Detection:').first;
                const smoothingPanel = beatDetectiveWindow.groups.whoseTitle.is('Smoothing:').first;
            
                //Enable "Clip Separation"
                operationPanel.radioButtons.whoseTitle.is('Clip Separation').first.checkboxSet({
                    targetValue: "Enable",
                });
            
                //Set "Selection Contains:" to 1/16 Note
                selectionPanel.popupButtons.first.popupMenuSelect({
                    menuPath: [selectionContains],
                });
            
                //Capture Selection
                selectionPanel.buttons.whoseTitle.is('Capture Selection').first.elementClick();
            
                //Analyze Selection
                detectionPanel.buttons.whoseTitle.is('Analyze').first.elementClick();
            
                //Variable for "Sensitivity" field
                const sensitivityNumberField = detectionPanel.textFields.whoseTitle.is('NumericEntryText').first;
            
                //Set "Sensitivity" field
                setNumericEntryTextField(beatDetectiveWindow, sensitivityNumberField, sensitivity);
            
                //Variable for "Trigger pad" field
                const triggerPadNumberField = detectionPanel.textFields.whoseTitle.is('NumericEntryText').allItems[1];
            
                //Set "Trigger pad" field
                setNumericEntryTextField(beatDetectiveWindow, triggerPadNumberField, triggerPad);
            
                //Activate Drum Group
                selectAllTracksInGroup(drumGroupName);
            
                //Activate "Drum Group"
                sf.ui.proTools.groupsActivateOnly({
                    groupName: drumGroupName,
                });
            
                //Seperate
                beatDetectiveWindow.buttons.whoseTitle.is('Separate').first.elementClick();
            
                //Clip Conform
                operationPanel.radioButtons.whoseTitle.is('Clip Conform').first.checkboxSet();
            
                //Conform
                beatDetectiveWindow.buttons.whoseTitle.is('Conform').first.elementClick();
            
                //Edit Smoothing
                operationPanel.radioButtons.whoseTitle.is('Edit Smoothing').first.checkboxSet();
            
                //Fill and Crossfade
                smoothingPanel.radioButtons.whoseTitle.is('Fill And Crossfade').first.checkboxSet();
            
                //Variable for "Crossfade Length" field
                const crossfadeLengthNumberField = smoothingPanel.textFields.whoseTitle.is('NumericEntryText').first;
            
                //Set "Crossfade Length" field
                setNumericEntryTextField(beatDetectiveWindow, crossfadeLengthNumberField, crossfadeLength);
            
                //Smooth
                beatDetectiveWindow.buttons.whoseTitle.is('Smooth').first.elementClick();
            
                //Reselect original tracks
                sf.ui.proTools.trackSelectByName({names:originalTracks});
            
                //Solo Drums
                sf.ui.proTools.selectedTrack.trackSetSolo({
                    targetValue: "Enable",
                });
            
                beatDetectiveWindow.getElement('AXCloseButton').elementClick();
            }
            
            doBeatDetective(beatDetectiveSettings);
            
            1. Kris Crunk @Kris_Crunk
                2021-02-08 02:26:31.374Z2021-02-08 02:32:37.222Z

                Thanks Kitch - I knew it would get updated and refined by folks like you that know what you are doing!! Rafael was also helping me. Appreciate both of you!

                1. Kitch Membery @Kitch2021-02-08 02:29:16.574Z

                  Back at ya @Kris_Crunk :-)

                2. In reply toKitch:
                  riff @riff
                    2022-08-29 15:14:07.324Z2022-08-29 16:28:29.324Z

                    Would love some help. Seems like this would be the ideal script for my workflow but for whatever reason I'm getting an error on line 36 seems like some naming/grouping issue but I can't seem to make sense of it:

                    /**
                     * @param {string} groupName
                     */
                    function selectAllTracksInGroup(groupName) {
                        sf.ui.proTools.mainWindow.groupListView.childrenByRole("AXRow").filter(r => {
                            r.childrenByRole("AXCell").allItems[1].buttons.first.title.value.split(/-\s/)[1] === groupName &&
                                r.childrenByRole("AXCell").first.buttons.first.title.invalidate().value === 'Selected. , Track selection partially contains group'
                            r.childrenByRole("AXCell").first.buttons.first.elementClick();
                        });
                    }
                    
                    1. Kitch Membery @Kitch2022-08-29 16:33:31.123Z

                      Hi @riff,

                      The best way to get help with a script is by using the Script Help workflow outlined at the following link bit.ly/sfscripthelp.

                      This will provide the community with the information needed to troubleshoot and hopefully solve the issue. :-)

                      1. AAndreas Altmann @Andreas_Altmann
                          2023-01-30 07:04:27.553Z

                          As a matter of fact, all buttons on my streamdeck become unresponsive...

                        • In reply toriff:
                          OOliver Freiberg @Oliver_Freiberg
                            2024-03-06 10:06:54.979Z

                            Did you manage to sort this out? I'm having the same issue

                          • In reply toKitch:
                            AAndreas Altmann @Andreas_Altmann
                              2023-01-30 06:51:53.540Z

                              Hey! Thanks a bunch! Usually one would align the drums using the kick and the snare, or even the HiHat depending on groove. Where would I add or change these attributes?
                              Also, the script stops after opening beat detective. So then I closed beat detective again to try running the script again. But now nothing happens...I'm at a loss.

                              1. In reply toKitch:

                                Jumping on an old post here!

                                @Kitch - is it simple enough to modify this script to do one thing? I often use BD just to do fades - if I'm thinking right, with the right things cut out, this script should be able to:

                                open BD (if it's not already open)
                                delete fades
                                do crossfades (with setting as at top)
                                hide BD again?

                                I could probably work this out if I studied it/trial and error...

                                1. Kitch Membery @Kitch2023-02-16 03:18:16.360Z

                                  Nice, Yeah, I'll take a swing at it over the weekend :-)

                                  1. Kitch Membery @Kitch2023-02-16 03:18:51.782Z

                                    Remind me on Monday if there is no reply from me :-)

                                    1. haha. I think I made it work...there's probably a whole load of stuff that's not needed, but cutting out everything from 73 to 118 seemed to do it!

                                      1. Kitch Membery @Kitch2023-02-16 03:23:50.406Z

                                        Awesome... feel free to share the code here and I'll review it for improvement when I get a chance. :-)

                                        1. AAdrian Breakspear @Adrian_Breakspear
                                            2023-02-16 03:24:58.737Z2023-02-16 03:25:38.408Z
                                            const beatDetectiveSettings = {
                                                selectionContains: "1/16 Note",
                                                sensitivity: '82',
                                                triggerPad: '5',
                                                crossfadeLength: '5',
                                                drumGroupName: "DRUMS",
                                            };
                                            
                                            /**
                                             * @param {AxElement} window
                                             * @param {AxElement} field
                                             * @param {string} num
                                             */
                                            function setNumericEntryTextField(window, field, num) {
                                                window.elementRaise();
                                                field.elementClick();
                                            
                                                sf.keyboard.type({ text: num });
                                            
                                                var i = 0;
                                            
                                                while (field.value.invalidate().value !== num) {
                                                    sf.wait({ intervalMs: 50 });
                                                };
                                            
                                                sf.keyboard.press({ keys: 'return' });
                                            }
                                            
                                            /**
                                             * @param {string} groupName
                                             */
                                            function selectAllTracksInGroup(groupName) {
                                                sf.ui.proTools.mainWindow.groupListView.childrenByRole("AXRow").filter(r => {
                                                    r.childrenByRole("AXCell").allItems[1].buttons.first.title.value.split(/-\s/)[1] === groupName &&
                                                        r.childrenByRole("AXCell").first.buttons.first.title.invalidate().value === 'Selected. , Track selection partially contains group'
                                                    r.childrenByRole("AXCell").first.buttons.first.elementClick();
                                                });
                                            }
                                            
                                            function doBeatDetective(settings) {
                                                //Deconstruct Beat Detective Settings
                                                const { selectionContains, sensitivity, triggerPad, crossfadeLength, drumGroupName, } = settings;
                                            
                                                //Activate Pro Tools main window
                                                sf.ui.proTools.appActivateMainWindow();
                                            
                                                //Get originally selected tracks
                                                const originalTracks = sf.ui.proTools.selectedTrackNames;
                                            
                                                //Delete Fades
                                                sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Fades', 'Delete'] });
                                            
                                                //Variable for Beat Detective window
                                                const beatDetectiveWindow = sf.ui.proTools.windows.whoseTitle.is('Beat Detective').first;
                                            
                                                //Open Beat Detective
                                                if (!beatDetectiveWindow.exists) {
                                                    sf.ui.proTools.menuClick({
                                                        menuPath: ["Event", "Beat Detective"],
                                                        targetValue: 'Enable'
                                                    });
                                                }
                                            
                                                //Wait for Beat Detective Window.
                                                beatDetectiveWindow.elementWaitFor();
                                            
                                                //Variables for Beat Detective pannels.
                                                const operationPanel = beatDetectiveWindow.groups.whoseTitle.is('Operation').first;
                                                const selectionPanel = beatDetectiveWindow.groups.whoseTitle.is('Selection').first;
                                                const detectionPanel = beatDetectiveWindow.groups.whoseTitle.is('Detection:').first;
                                                const smoothingPanel = beatDetectiveWindow.groups.whoseTitle.is('Smoothing:').first;
                                            
                                                
                                                //Edit Smoothing
                                                operationPanel.radioButtons.whoseTitle.is('Edit Smoothing').first.checkboxSet();
                                            
                                                //Fill and Crossfade
                                                smoothingPanel.radioButtons.whoseTitle.is('Fill And Crossfade').first.checkboxSet();
                                            
                                                //Variable for "Crossfade Length" field
                                                const crossfadeLengthNumberField = smoothingPanel.textFields.whoseTitle.is('NumericEntryText').first;
                                            
                                                //Set "Crossfade Length" field
                                                setNumericEntryTextField(beatDetectiveWindow, crossfadeLengthNumberField, crossfadeLength);
                                            
                                                //Smooth
                                                beatDetectiveWindow.buttons.whoseTitle.is('Smooth').first.elementClick();
                                            
                                                //Reselect original tracks
                                                sf.ui.proTools.trackSelectByName({names:originalTracks});
                                            
                                                //Solo Drums
                                                sf.ui.proTools.selectedTrack.trackSetSolo({
                                                    targetValue: "Enable",
                                                });
                                            
                                                beatDetectiveWindow.getElement('AXCloseButton').elementClick();
                                            }
                                            
                                            doBeatDetective(beatDetectiveSettings);
                                            

                                            Erm something like that?

                                  2. M
                                    In reply toKris_Crunk:
                                    Mike Avenaim @Mike_Avenaim
                                      2021-02-09 16:43:00.559Z

                                      Oh yeah! Def gonna try this puppy out.

                                      1. P
                                        In reply toKris_Crunk:
                                        Pete Grossmann @Pete_Grossmann
                                          2021-10-25 16:54:10.513Z

                                          This script works wonderfully. I've found the fields where to change the note value to 1/8, 1/4, etc. Any idea how/where in the script you'd be able to modify it for triplets?