Hey All! Im working on one that feels a little challenging for my current skill level with SF- I basically need to create a script that will help me make all drum hits the same length (looking at between 15-25ms) so I can trigger gates and samples without them staying open too long. my current plan is just:
-Tab to Transient
-Highlight Time Selection Box
-Enter 25ms
-Hit CMD+T to trim sides
-Tab to Transient again to get past the edit
is there something like this already floating around that I haven't found or a smarter work around?
thank you!
- BBrandon Jiaconia @Brandon_Jiaconia
You should look into automating Strip Silence. There are a couple good threads on the forum:
- In reply toJesse_Field7⬆:Dustin Harris @Dustin_Harris
Here's something I threw together, let me know if it works well enough. There may be a faster way to trim the clips to the desired length, but I can't think of one at the moment...
const CLIP_LENGTH_IN_MILLISECONDS = 25; /**@param {number} clipLengthInMs */ function splitClipAtSelection(clipLengthInMs) { if (sf.ui.proTools.getMenuItem("Edit", "Separate Clip", "At Transients").isEnabled) { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Separate Clip", "At Transients"] }) sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.textFields.first.elementSetTextFieldWithAreaValue({ value: String(clipLengthInMs), useMouseKeyboard: true }) sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.buttons.whoseTitle.is("OK").first.elementClick(); sf.wait({ intervalMs: 250 }) } } /**@param {{targetTrackNames: string[], inTime: string, outTime: string, clipLengthInMs: number}} args */ function trimClipsToLengthInMs({ targetTrackNames, inTime, outTime, clipLengthInMs }) { const clipLengthInSamples = (clipLengthInMs * sf.app.proTools.getSessionSampleRate().sampleRateNumerical) / 1000 targetTrackNames.forEach(trackName => { sf.app.proTools.selectTracksByName({ trackNames: [trackName] }) sf.app.proTools.setTimelineSelection({ inTime, outTime }); sf.ui.proTools.clipDoForEachSelectedClip({ action: _ => { const {inTime} = sf.app.proTools.getTimelineSelection({timeScale: "Samples"}); const outTime = String(Number(inTime) + clipLengthInSamples); sf.app.proTools.setTimelineSelection({ inTime, outTime }); sf.app.proTools.trimToSelection(); } }) }) } /**@param {{targetTrackNames: string[], inTime: string, outTime: string}} args */ function splitAtTransients({ targetTrackNames, inTime, outTime }) { targetTrackNames.forEach(trackName => { //select track sf.app.proTools.selectTracksByName({ trackNames: [trackName] }) //go to start of selection sf.app.proTools.setTimelineSelection({ inTime: inTime, outTime: outTime, }) //mass separate clips splitClipAtSelection(CLIP_LENGTH_IN_MILLISECONDS); }) } function main() { sf.ui.proTools.appActivateMainWindow(); const { inTime, outTime } = sf.app.proTools.getTimelineSelection({ timeScale: "Samples" }); const targetTrackNames = sf.app.proTools.tracks.allItems.filter(t=>t.isSelected).map(t => t.name); splitAtTransients({ targetTrackNames, inTime, outTime }) trimClipsToLengthInMs({ targetTrackNames, inTime, outTime, clipLengthInMs: CLIP_LENGTH_IN_MILLISECONDS }) } main();
- JJesse Field @Jesse_Field7
this is incredible thank you so much!! This works perfectly for what im trying to do. the only thing im noticing is that if I let the script split the clips at the beginning it adds a trigger pad and then misses the transient but that might be because I added sf.ui.proTools.clipDoForEachClip({action:main}) to the bottom so that it would repeat for every clip in the highlight. is there a smoother way to do that? if I precut the clips with Beat Detective it seems to work perfectly, just leaves a few stray clips but they're always silence before transients so its not a big deal. thank you so much for working on that, you just saved me so much time haha.
Dustin Harris @Dustin_Harris
I don't think you need to add anything at the bottom of the script, do for each selected clip and each selected track is already built in; just select everything you want to separate+shorten and run it... try it without your addition and see if it does what you expect? I also might need to have separate constants for the clip length and the transient pre-separate amount (maybe it should be 0?) anyway try it without your additions and let me know if it works any better, and I'll adapt it after your findings :)
- JJesse Field @Jesse_Field7
oh weird!! I must have done something goofy the first time I tried it because it only did 1 clip and stopped. its definitely doing them all now! but still has that trigger pad in the front so it looks like this:
Dustin Harris @Dustin_Harris
ok, slightly tweaked version, let me know if this works better!
const CLIP_LENGTH_IN_MILLISECONDS = 25; /**@param {number} clipLengthInMs */ function splitClipAtSelection(clipLengthInMs) { if (sf.ui.proTools.getMenuItem("Edit", "Separate Clip", "At Transients").isEnabled) { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Separate Clip", "At Transients"] }) sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.textFields.first.elementSetTextFieldWithAreaValue({ value: "0", useMouseKeyboard: true }) sf.ui.proTools.windows.whoseTitle.is("Pre-Separate Amount").first.buttons.whoseTitle.is("OK").first.elementClick(); sf.wait({ intervalMs: 250 }) } } /**@param {{targetTrackNames: string[], inTime: string, outTime: string, clipLengthInMs: number}} args */ function trimClipsToLengthInMs({ targetTrackNames, inTime, outTime, clipLengthInMs }) { const clipLengthInSamples = (clipLengthInMs * sf.app.proTools.getSessionSampleRate().sampleRateNumerical) / 1000 targetTrackNames.forEach(trackName => { sf.app.proTools.selectTracksByName({ trackNames: [trackName] }) sf.app.proTools.setTimelineSelection({ inTime, outTime }); sf.ui.proTools.clipDoForEachSelectedClip({ action: _ => { const {inTime} = sf.app.proTools.getTimelineSelection({timeScale: "Samples"}); const outTime = String(Number(inTime) + clipLengthInSamples); sf.app.proTools.setTimelineSelection({ inTime, outTime }); sf.app.proTools.trimToSelection(); } }) }) } /**@param {{targetTrackNames: string[], inTime: string, outTime: string}} args */ function splitAtTransients({ targetTrackNames, inTime, outTime }) { targetTrackNames.forEach(trackName => { //select track sf.app.proTools.selectTracksByName({ trackNames: [trackName] }) //go to start of selection sf.app.proTools.setTimelineSelection({ inTime: inTime, outTime: outTime, }) //mass separate clips splitClipAtSelection(CLIP_LENGTH_IN_MILLISECONDS); }) } function main() { sf.ui.proTools.appActivateMainWindow(); const { inTime, outTime } = sf.app.proTools.getTimelineSelection({ timeScale: "Samples" }); const targetTrackNames = sf.app.proTools.tracks.allItems.filter(t=>t.isSelected).map(t => t.name); splitAtTransients({ targetTrackNames, inTime, outTime }) trimClipsToLengthInMs({ targetTrackNames, inTime, outTime, clipLengthInMs: CLIP_LENGTH_IN_MILLISECONDS }) } main();
- JJesse Field @Jesse_Field7
This is literally perfect thank you so much for doing this!!!! so excited!!!
- JIn reply toJesse_Field7⬆:Jesse Field @Jesse_Field7
Hey Dustin! for some reason since I updated pro tools and my OS this no longer works. I tried to switch around anything I could or find a work around but i'm a bit stumped. any help would be massively appreciated since I use it a ton!