The instrument loader in the Logic Pro X SoundFlow package is great for creating basic user presets, however, if you create a "User Patch" with custom multi-outputs, it appears to only be accessible through the Library pane...(let me know if there's another option). I thought it appeared in the channel strip settings, but it doesn't seem to be an option there either.
Does anyone have a script to load a User Patch with SoundFlow? Or some ideas to write a script? Thanks!

- Kitch Membery @Kitch2024-06-15 18:16:18.374Z
Hi @Justin_Krol,
This is one feature that I should add to the Logic Pro package for sure. I’ll add it to my list and see if I can make it happen. Thanks for the great suggestion/request. :-)
- JIn reply toJustin_Krol⬆:Justin Krol @Justin_Krol
@Kitch Thanks man! Much appreciated.
Kitch Membery @Kitch2024-06-18 08:10:46.662Z
Ok @Justin_Krol,
Below is a work in progress... Unfortunately, the script needs to use a mouse click as the UI elements are not responding to the
.elementClick()
method.I'll take another swing at it when I have a chance but this should provide you with some functionality till I can dig deeper.
const logic = sf.ui.logic; logic.appActivate(); logic.invalidate(); function ensureLibraryVisibility() { const libraryGroup = logic.mainWindow.groups.whoseDescription.is("Library").first; // Check if the Library panel is visible if (!libraryGroup.exists) { const viewLibraryButton = sf.ui.logic.mainWindow.controlBar.viewLibraryButton; // Check if the Library button is available and toggle it if necessary if (viewLibraryButton.exists) { if (!viewLibraryButton.isEnabled) { viewLibraryButton.checkboxSet({ targetValue: "Enable" }); } } else { // Navigate through the menu to show the Library if the button isn't available logic.getMenuItem("View").elementClick(); logic.getMenuItem("View", "Show Library").elementClick(); } } // Wait for the library element to be visible after attempting to enable it libraryGroup.elementWaitFor(); } function recallLibraryPreset({ path }) { const libraryGroup = logic.mainWindow.groups.whoseDescription.is("Library").first; // Ensure the Library panel is visible ensureLibraryVisibility(); const libraryPanel = libraryGroup.groups.whoseDescription.is("Library").first; const libraryBrowser = libraryPanel.groups.first.splitGroups.first.groups.allItems[2].children.whoseRole.is("AXBrowser") const horizontalScrollBar = libraryBrowser.whoseDescription.is("Library").first .scrollAreas.first.getElement("AXHorizontalScrollBar").children.whoseRole.is("AXValueIndicator").first; // If the Horizontal Scroll Bar exists scroll it all the way to the left if (horizontalScrollBar.exists) horizontalScrollBar.value.intValue = 0; const columns = libraryBrowser.whoseDescription.is("Library").first.scrollAreas.first.scrollAreas; // Click each path item path.forEach((item, index) => { const column = columns.invalidate().allItems[index]; const list = column.children.whoseRole.is("AXList").first; const textFields = list.children.whoseRole.is("AXStaticText"); const targetElement = textFields.find(e => e.value.value === item); if (!targetElement) throw `Could not find the path item "${item}" in the path:${JSON.stringify(path)}` // Requires Menu Click targetElement.mouseClickElement(); }); } recallLibraryPreset({ path: ["Voice", "Experimental", "Delay Vocal"] });
- JJustin Krol @Justin_Krol
Amazing, thanks so much! I'm gonna take it for a spin in a little bit.
- JJustin Krol @Justin_Krol
Hey @Kitch, I finally got back around to playing with this one. When I try to update the script to my specific patches, the script closes out the second column. For example, using the screenshot from my original post above, when I run the command, the user patch "AD DRUM TEST NEW" vanishes from the column. No rush at all, but maybe to help me better understand, could you update your script specifically to my example path? It would be "User Patches" > "AD DRUM TEST NEW" (for this specific example).
Thanks so much!
Kitch Membery @Kitch2024-08-30 03:36:50.343Z
Hi @Justin_Krol ,
It looks like I'll have to take a different approach to it, instead using the search field.
Try out this script. (unfortunately, it still requires a mouse click, but only one).
const logic = sf.ui.logic; logic.appActivate(); logic.invalidate(); function ensureLibraryVisibility() { const libraryGroup = logic.mainWindow.groups.whoseDescription.is("Library").first; // Check if the Library panel is visible if (!libraryGroup.exists) { const viewLibraryButton = sf.ui.logic.mainWindow.controlBar.viewLibraryButton // Check if the Library button is available and toggle it if necessary if (viewLibraryButton.exists && viewLibraryButton.value.intValue === 0) { viewLibraryButton.checkboxSet({ targetValue: "Enable" }); } else { // Navigate through the menu to show the Library if the button isn't available logic.getMenuItem("View").elementClick(); logic.getMenuItem("View", "Show Library").elementClick(); } } // Wait for the library element to be visible after attempting to enable it libraryGroup.elementWaitFor(); } function recallLibraryPreset({ name }) { ensureLibraryVisibility(); const mainLibraryGroup = sf.ui.logic.mainWindow.groups.whoseDescription.is("Library") .first.groups.whoseDescription.is("Library") .first.groups .first.splitGroups .first.groups; const searchField = mainLibraryGroup.allItems[1].textFields.first; searchField.value.value = name searchField.elementClick({ actionName: "AXConfirm" }); const rows = mainLibraryGroup.allItems[2].scrollAreas.first.tables.first.children.whoseRole.is("AXRow"); const targetRow = rows.find(row => row.children.first.children.first.value.value === name); targetRow.children.first.children.first.mouseClickElement(); } recallLibraryPreset({ name: "AD DRUM TEST NEW", });
Let me know if it works for you. :-)
- JJustin Krol @Justin_Krol
Beautiful! Works perfectly over here. Thank you so much!
Kitch Membery @Kitch2024-08-30 19:13:33.308Z
Awesome!!
- JJustin Krol @Justin_Krol
PS - this would be an awesome one to add to future package updates, even if it's just me being selfish about having to edit the script for my 50+ user patches :)
Kitch Membery @Kitch2024-09-09 19:36:16.128Z
This could easily be turned into a command template. Do you know how to make command templates?
- JJustin Krol @Justin_Krol
I haven't done it before, but I bet I could figure it out. I'll play around with it this week!
Kitch Membery @Kitch2024-09-10 01:19:25.783Z
I bet you could too...
Check out this link for more information. :-)
https://soundflow.org/docs/how-to/custom-commands/command-templatesIf you get stuck let me know!
- JJustin Krol @Justin_Krol
Awesome, thanks! Will do.
- In reply toKitch⬆:JJustin Krol @Justin_Krol
Question - Am I adding a property for every step and the functions (like the pause, check if piano roll is open, etc)?
Kitch Membery @Kitch2024-09-10 17:47:21.648Z
Hi @Justin_Krol,
For this one, you'd just create a command template property with the Title "Preset Name" with the "Type" set to "String".
And then change the script to this...
const {presetName} = event.props; const logic = sf.ui.logic; logic.appActivate(); logic.invalidate(); function ensureLibraryVisibility() { const libraryGroup = logic.mainWindow.groups.whoseDescription.is("Library").first; // Check if the Library panel is visible if (!libraryGroup.exists) { const viewLibraryButton = sf.ui.logic.mainWindow.controlBar.viewLibraryButton // Check if the Library button is available and toggle it if necessary if (viewLibraryButton.exists && viewLibraryButton.value.intValue === 0) { viewLibraryButton.checkboxSet({ targetValue: "Enable" }); } else { // Navigate through the menu to show the Library if the button isn't available logic.getMenuItem("View").elementClick(); logic.getMenuItem("View", "Show Library").elementClick(); } } // Wait for the library element to be visible after attempting to enable it libraryGroup.elementWaitFor(); } function recallLibraryPreset({ name }) { ensureLibraryVisibility(); const mainLibraryGroup = sf.ui.logic.mainWindow.groups.whoseDescription.is("Library") .first.groups.whoseDescription.is("Library") .first.groups .first.splitGroups .first.groups; const searchField = mainLibraryGroup.allItems[1].textFields.first; searchField.value.value = name searchField.elementClick({ actionName: "AXConfirm" }); const rows = mainLibraryGroup.allItems[2].scrollAreas.first.tables.first.children.whoseRole.is("AXRow"); const targetRow = rows.find(row => row.children.first.children.first.value.value === name); targetRow.children.first.children.first.mouseClickElement(); } recallLibraryPreset({ name: presetName, });
Then you can create presets for each of your patches.
- JJustin Krol @Justin_Krol
Oh, amazing! Thanks so much for this. I'll hop on this as soon as I get chance today!
Kitch Membery @Kitch2024-09-10 18:30:46.319Z
Let me know if you get stuck.
- JJustin Krol @Justin_Krol
And we have liftoff!! Thanks so much...as always!
Kitch Membery @Kitch2024-09-10 20:09:27.995Z
Woo!!!
- JIn reply toJustin_Krol⬆:Justin Krol @Justin_Krol
Hey @Kitch!
Something weird is happening now where my "edit a copy" button is missing from the default preset for this command. Let me know if you have any ideas. I've got about 30 more patches to add :)
- JJustin Krol @Justin_Krol
PS - the source code is still the same as above (the last one from you).
- In reply toJustin_Krol⬆:
Kitch Membery @Kitch2024-10-24 21:38:51.782Z
Hi Justin,
Do you mean the "Add Preset" button? If so, you need to select the "USER PATCH LOADER" in the Command Name column. :-)
- JIn reply toJustin_Krol⬆:Justin Krol @Justin_Krol
Yeah--like what's highlighted here? It's still not showing unless I'm having a massive brain fart here. Which is entirely possible :)
- JJustin Krol @Justin_Krol
Update: So it appears that any user created template that I've made is missing the "Edit a copy" button. All of the SoundFlow package ones are still there, so it only seems to be affecting the ones that I've created. If that helps.
Chad Wahlbrink @Chad2024-10-29 16:27:48.851Z
Hey @Justin_Krol,
Chiming in.
The "Add New Preset" and "Make Editable Copy" buttons are only available when you install a package from the Store.
For example, I don't have those options when editing my CW Pro Tools Utilities package from "My Packages." In this scenario, you can select any preset and use the "New" button to create a preset or a preset folder for your package. Alternatively, you can use CMD+D to duplicate your presets. Then you can rename them, etc.
When I install the same package from the store, I can use the "Add New Preset" and "Make Editable Copy" buttons for the same command when I have the parent command ("Show Automation Lanes for Tracks" in this case):
- JJustin Krol @Justin_Krol
Oh man, there's that brain fart I was talking about! Sorry, it's been a minute since I tweaked my own presets and I completely forgot about this crucial piece of information, haha.
Many thanks!