A fully automated Beat Detective script
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();
Linked from:
- Raphael Sepulveda @raphaelsepulveda2021-02-02 21:30:32.456Z
Nice! Making quick work out of those drum edits!
- In reply toKris_Crunk⬆:Kris Crunk @Kris_Crunk
I've run into a few snags with this - but am working on it
- 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);
Kris Crunk @Kris_Crunk
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!
Kitch Membery @Kitch2021-02-08 02:29:16.574Z
Back at ya @Kris_Crunk :-)
- In reply toKitch⬆:
riff @riff
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(); }); }
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. :-)
- AAndreas Altmann @Andreas_Altmann
As a matter of fact, all buttons on my streamdeck become unresponsive...
- In reply toriff⬆:OOliver Freiberg @Oliver_Freiberg
Did you manage to sort this out? I'm having the same issue
- In reply toKitch⬆:AAndreas Altmann @Andreas_Altmann
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. - In reply toKitch⬆:AAdrian Breakspear @Adrian_Breakspear
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...
Kitch Membery @Kitch2023-02-16 03:18:16.360Z
Nice, Yeah, I'll take a swing at it over the weekend :-)
- In reply toAdrian_Breakspear⬆:
Kitch Membery @Kitch2023-02-16 03:18:51.782Z
Remind me on Monday if there is no reply from me :-)
- AAdrian Breakspear @Adrian_Breakspear
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!
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. :-)
- AAdrian Breakspear @Adrian_Breakspear
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?
- MIn reply toKris_Crunk⬆:Mike Avenaim @Mike_Avenaim
Oh yeah! Def gonna try this puppy out.
- PIn reply toKris_Crunk⬆:Pete Grossmann @Pete_Grossmann
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?