midi menu list

234 views
Skip to first unread message

Kalman Tarr

unread,
Aug 10, 2025, 10:54:44 AMAug 10
to QLab
Hello pros!
I have a problem. I want to get the names of the midi patches of a timecode cue. When I click on the pop-up button, I get a list like this:
You can see that there is a gray menu item called "Patches:". When the midi patches are empty in the Settings window of the Qlab application
the list shows the following: Figure 2
But when they are not, it shows the following: Figure 1
My goal is to get ONLY the patch lines from the menu in a script. I will show you my solution, but it will get all the menu items. I don't need this! This is the task I need help with. Thanks in advance!

Kalman

fig1:
Screenshot 2025-08-10 at 16.31.19.png
fig2:
Screenshot 2025-08-10 at 16.39.20.png

This is my script:

tell application "System Events" to tell (first application process whose bundle identifier is "com.figure53.QLab.5")

tell (first pop up button whose description is "patch")

click

set theNames to (get name of menu items of menu 1) as list

set defaultValue to (get value)

end tell

end tell


Kalman Tarr

unread,
Aug 26, 2025, 4:35:33 AM (11 days ago) Aug 26
to QLab
Hi there,
I figured this out.
Experts, what do you think, is there a easier way to  solve the problem?

tell application "System Events" to tell (first application process whose bundle identifier is "com.figure53.QLab.5")

set menuElements to {}

tell group 1 of splitter group 1 of window 1

try

click (first button whose description is "Settings")

end try

tell (first pop up button whose description is "patch")

click

set theNames to (get name of menu items of menu 1) as list

set defValue to (get value)

click menu item defValue of menu 1

repeat with i from 1 to count of theNames

if ((item i of theNames) as text) contains (" - ") then

copy item i of theNames to end of menuElements

end if

end repeat

return menuElements

end tell

end tell

end tell


If the return variable is empty, then the display dialog should say "no midi patches".

It is all!


Yours,

Kalman



Rich Walsh

unread,
Aug 26, 2025, 5:15:27 AM (11 days ago) Aug 26
to ql...@googlegroups.com
I did reply to your original question on 10 August but it doesn’t seem to have made it to the forum:

Begin forwarded message:

From: "'Rich Walsh' via QLab" <ql...@googlegroups.com>
Subject: Re: [QLab] midi menu list
Date: 10 August 2025 at 17:50:57 BST

It’s a bit obvious, but can’t you just filter the list?

tell application "System Events" to tell (first application process whose bundle identifier is "com.figure53.QLab.5")
tell group 1 of splitter group 1 of window 1 -- This would have been a useful line for you to have included, as without it your script does not work!
tell (first pop up button whose description is "patch")
click
set theNames to name of menu items of menu 1 whose name begins with "Patch "
end tell
end tell
end tell
theNames

Rich



--
Contact support anytime: sup...@figure53.com
User Group Code of Conduct: https://qlab.app/code-of-conduct/
 
Instagram: https://www.instagram.com/Figure53
Bluesky: https://bsky.app/profile/qlab.app
---
You received this message because you are subscribed to the Google Groups "QLab" group.
To unsubscribe from this group and stop receiving emails from it, send an email to qlab+uns...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/qlab/c2f5b811-3ec3-4cf8-a5b9-26aad1397b92n%40googlegroups.com.

Kalman Tarr

unread,
Aug 26, 2025, 12:56:47 PM (10 days ago) Aug 26
to QLab
Hi Rich,

I checked the forum every 2 days but I didn't see any response from anyone, including you.
Well, I tried something similar but it didn't work for me.
I tried your suggestion, it works!
Thanks a lot!
Kalman

Kalman Tarr

unread,
Aug 29, 2025, 5:47:03 AM (8 days ago) Aug 29
to QLab
Hi Rich,

In my experience, if I open an empty workspace in the Qlab app and navigate to the 'timecode' tab of the 'main cue list', I can see what midi patches are in the system. I don't need to open the 'settings' window. open.
My question: how does Qlab read out what midi patches exist in the MAC system? How can I access this data without opening the Qlab app?
Can I access it at all? 

With your help, there are two methods for reading out the patches, one is to put a 'timecode' cue on the workspace and the midi patches are immediately visible there.
Or I put any cue (even a memo) on the empty workspace and I can also read out the current midi patches on the 'timecode' tab of the Cue list.
I find that some kind of cue is necessary for the data to be read out.
I ask for your help with this.

Thank you in advance.

Best,
Kalman

Richard Williamson

unread,
Aug 29, 2025, 5:50:44 AM (8 days ago) Aug 29
to ql...@googlegroups.com
If you go to "applications->utilities->Audio midi setup” then in the window menu select “Show Midi Studio” then you can see midi devices and similar, and create additional internal midi busses

--

Kalman Tarr

unread,
Aug 29, 2025, 6:58:01 AM (7 days ago) Aug 29
to QLab
Thank you a lot Richar,.

I know all this! I forgot to mention that I want to extract the midi patch data using AppleScript. 
There is a big problem though, the Audio Midi app is not scriptable!
You scroll up a bit then ...

Rich Walsh

unread,
Aug 29, 2025, 10:50:59 AM (7 days ago) Aug 29
to ql...@googlegroups.com
As ever, the question is WHY?

Followed by, have you tried Google?

If you want to retrieve the information QLab is getting from the OS without using QLab then you’re probably looking at the CoreMIDI framework.

You can’t really get at CoreMIDI via AppleScript or even AppleScriptObjC; this will tell you how many MIDI devices QLab should list, but that’s about as much as you can do:

use AppleScript version "2.4"

use scripting additions

use framework "CoreMIDI"

set countDevices to current application's MIDIGetNumberOfDestinations()

countDevices


A little bit of determined work with Google will tell you that you’ll need to roll your own executable to get, say, a list of names – and a Swift script is probably simplest:

#!/usr/bin/env swift
import CoreMIDI
import Foundation

func getDisplayName(_ obj: MIDIObjectRef) -> String? {
    var param: Unmanaged<CFString>?
    let status = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, &param)
    guard status == noErr, let name = param?.takeRetainedValue() else {
        return nil
    }
    return name as String
}

func isOffline(_ obj: MIDIObjectRef) -> Bool {
    var offline: Int32 = 0
    let status = MIDIObjectGetIntegerProperty(obj, kMIDIPropertyOffline, &offline)
    return status == noErr && offline != 0
}

func listActiveMIDIDestinations() {
    let count = MIDIGetNumberOfDestinations()
    var activeDestinations: [String] = []
    for i in 0..<count {
        let endpoint = MIDIGetDestination(i)
        if endpoint != 0 {
            if !isOffline(endpoint) {
                if let name = getDisplayName(endpoint) {
                    activeDestinations.append(name)
                }
            }
        }
    }
    if activeDestinations.isEmpty {
        print("No active MIDI destinations found")
    } else {
        for name in activeDestinations {
            print("\(name)")
        }
    }
}

listActiveMIDIDestinations()

You make this into a file named “listActiveMIDIDestinations.swift" on the Desktop and chmod +X that to be executable, then:

do shell script quoted form of (POSIX path of (path to desktop) & "listActiveMIDIDestinations.swift")


What has this got to do with using QLab though?

I did cheat a bit with Google’s AI mode to help me sort through the results a bit quicker as I’m not remotely interested in learning to write this code myself yet. The bits are all there in Apple’s Developer documentation or on forums.

The alternative is to work out how to get and parse the reply to /settings/midi/patchList… This, of course, lists which system-level devices QLab has created “patches” for, not what system-level devices exist; it’s a bit unclear which one you want as “patches” is a QLab concept that exists per-workspace and is tricky to get at without opening QLab, which you don't want to do…

You could also go diving into the qlab5 file in an XML editor and find, for example:

<string>midiPatches</string>
<dict>
<key>$class</key>
<dict>
<key>CF$UID</key>
<integer>128</integer>
</dict>
<key>NS.objects</key>
<array>
<dict>
<key>CF$UID</key>
<integer>209</integer>
</dict>
</array>
</dict>
<dict>
<key>$class</key>
<dict>
<key>CF$UID</key>
<integer>220</integer>
</dict>
<key>deviceDescription</key>
<dict>
<key>CF$UID</key>
<integer>212</integer>
</dict>
<key>name</key>
<dict>
<key>CF$UID</key>
<integer>211</integer>
</dict>
<key>uniqueID</key>
<dict>
<key>CF$UID</key>
<integer>210</integer>
</dict>
</dict>
<string>8DF8CA42-FB59-42F0-BFCE-DC6136767C24</string>
<string>Patch 1</string>
<dict>
<key>$class</key>
<dict>
<key>CF$UID</key>
<integer>205</integer>
</dict>
<key>NS.keys</key>
<array>
<dict>
<key>CF$UID</key>
<integer>213</integer>
</dict>
<dict>
<key>CF$UID</key>
<integer>214</integer>
</dict>
<dict>
<key>CF$UID</key>
<integer>215</integer>
</dict>
<dict>
<key>CF$UID</key>
<integer>5</integer>
</dict>
</array>
<key>NS.objects</key>
<array>
<dict>
<key>CF$UID</key>
<integer>216</integer>
</dict>
<dict>
<key>CF$UID</key>
<integer>217</integer>
</dict>
<dict>
<key>CF$UID</key>
<integer>218</integer>
</dict>
<dict>
<key>CF$UID</key>
<integer>219</integer>
</dict>
</array>
</dict>
<string>manufacturer</string>
<string>longName</string>
<string>name</string>
<string>Apple Inc.</string>
<string>IAC Driver IAC Bus 1</string>
<string>IAC Bus 1</string>
<integer>-1021912664</integer>
<dict>
<key>$classes</key>
<array>
<string>MIDIPatch</string>
<string>F53PasteboardObject</string>
<string>NSObject</string>
</array>
<key>$classname</key>
<string>MIDIPatch</string>
</dict>

You could read the file as text into AppleScript, search for "<string>midiPatches</string>” then iterate from there to try to spot whatever info you think you need about the MIDI patches.

Rich

Kalman Tarr

unread,
Aug 30, 2025, 12:02:15 PM (6 days ago) Aug 30
to QLab
Hi Rich,

Your first question was why. Interesting, interesting, and more.

Querying the timecode tab of the cue list will give you the answer.
I was also curious how the application itself (QLAB) is able to pick up this data (coreMIDI) when it loads. I admire the Applescript language, how many ways it can achieve the same result. I'm an old man, sitting at home and enjoying the opportunity to learn from you, Rich, and the other pros. I'm going to try the coreMIDI framework. I'll Google it.
Of course I don't understand the solution you presented. It's too high for me. But I'm glad and thank you for taking the time to find a solution.
I really do say that reading the cue list gives a satisfactory answer.
I noticed that 'Audio MIDI Setup' is not scriptable.
Thanks for the help!
Best,
Kalman

Rich Walsh

unread,
Aug 31, 2025, 1:31:00 PM (5 days ago) Aug 31
to ql...@googlegroups.com
Your question was:

how does Qlab read out what midi patches exist in the MAC system? How can I access this data without opening the Qlab app?

Your explanation as to why you want to be able to do this is:

Querying the timecode tab of the cue list will give you the answer.

This doesn’t make a lot of sense…

The Timecode tab of a cuelist in the Inspector lists the MTC sources available in the system. This list is completely independent of the “patches” defined in the workspace – which is what you started out querying via a Timecode Cue in the script you first posted in this thread. At the very least, if you’d been after the MTC sources you could have been poking around the UI of a cuelist in the Inspector – which wouldn’t have required making any cues either, unless you had a workspace with no cuelists in it… Which would be perverse if you were obsessing over MTC sources available to QLab.

I would hazard a guess that QLab is not using AppleScript to retrieve the list of MTC sources available. The MIDI functionality provided by the system to an app doesn’t appear to be exposed to AppleScript in any useful way.

If you desperately want the patches in a workspace without opening QLab you’ll need to coax that information out of the XML available in the workspace file.

If you desperately want the list of MIDI sources available to apps via the CoreMIDI framework you will have to learn how to do more than just AppleScript. It doesn’t take long with no knowledge of Swift to find the answers to build a Swift script to run via the command line – or “do shell script” – to extract a list of MIDI sources (not destinations as suggested in your previous posts).

None of this answers why on earth you need any of these lists, particularly outside of the context of running QLab? You aren’t going to find many other apps that can sit between AppleScript and MIDI as effectively; perhaps MIDIPipe? It’s never clear what you’re actually trying to achieve though…

Rich

--
Contact support anytime: sup...@figure53.com
User Group Code of Conduct: https://qlab.app/code-of-conduct/
 
Instagram: https://www.instagram.com/Figure53
Bluesky: https://bsky.app/profile/qlab.app
---
You received this message because you are subscribed to the Google Groups "QLab" group.
To unsubscribe from this group and stop receiving emails from it, send an email to qlab+uns...@googlegroups.com.

Sam Kusnetz

unread,
Aug 31, 2025, 2:21:27 PM (5 days ago) Aug 31
to ql...@googlegroups.com
I would hazard a guess that QLab is not using AppleScript to retrieve the list of MTC sources available. 

That is accurate.

Now, Kalman, I think the disconnect is that it seems that you are using the QLab Google group as a tool to explore learning about AppleScript and macOS programming in general. This is not necessarily a bad thing, but it is definitely not what most people use this Google group for!

Most people in this group use it to discuss how to use QLab to achieve specific performance goals. For example, when I’m not working with Figure 53 I work in live theater. When I use QLab, the end goal is presenting the show to an audience. If I have a technical question about using AppleScript or OSC or doing something else complex, it is always in service of that end goal of performing a show for an audience.

When you ask highly technical questions like this one, it can often be confusing to other list members because it’s not clear WHY you are asking, and knowing why someone is asking a question makes it easier to answer it.

Everyone on this list (except for Figure 53 employees like me) volunteers their time and energy to answer questions as an act of community. Sometimes, when someone asks lots of tricky questions without any reason other than “I want to know,” it can feel like that volunteer community service is being taken advantage of.

I’m not saying you or anyone else is doing anything wrong. But I do ask that you are mindful of how this group functions and careful about how you ask for the time and energy of others.

Thank you
Sam

Sam Kusnetz (he/him) | Figure 53



Kalman Tarr

unread,
Sep 2, 2025, 8:57:01 AM (3 days ago) Sep 2
to QLab
Hello Sam and Rich,
I understand the comment about the group's goal. I don't want to violate the basic principles. With your help, I learned a lot about scripting. As I wrote, I really like it! I try to approach a solution from several sides, examining the possibilities. This is where I fall.
Since I don't have a deep knowledge of the relationship between MAC OS and scripting languages, I admit that I'm asking stupid questions.
Sorry for that.

Why don't I start at the beginning? Because I've already solved the core of the problem. However, there are possible issues that apply to the creation of internal subroutines.

Well. Let me give you an example: we use an audio cue with markers. These markers need to give an instruction to an external device. In this case, a light control device. There, a light change needs to be performed. My solution: create a TimeCode cue.
First of all, two patches need to be set in the Settings Window MIDI interface. One that provides control between the two devices, the other is the internal patch (IAC driver).
Next, the script creates a MIDI cue series according to the number of markers.
MIDI cue
On the Settings tab, the passing patch must be set. Figure 1
On the Trigger tab, the timecode trigger must be set according to the markers. Figure 2
Of course, the settings shown on the main cue list timecode tab of the workspace. Figure 3
The task is to create the above work in a script.

When you start the timecode cue at the same time as the audio cue, it fires the MIDI cues one after the other.
This was the task. I hope my description is understandable. Sorry for the non-English terms.

I apologize again if I ask inappropriate questions.
Thanks for all the help, both of you!

Best regards.
Kalman

fig1
:
MIDISettingsTab.jpg

fig2:

MIDITriggerTab.png

fig3:
CL-TimeCodeTab.png


Rich Walsh

unread,
Sep 2, 2025, 10:59:02 AM (3 days ago) Sep 2
to ql...@googlegroups.com
I wouldn’t want to put money on it, but I think what you are actually asking is “How do I programatically set the mtc sync source name for a cue list without knowing in advance what sources are available?”, which isn’t something you’re going to need to do "without opening the Qlab [sic] app”…

-- Assuming you have the Inspector showing the Timecode tab for a Cue List


tell application "System Events" to tell application process "QLab"

click pop up button 2 of group 1 of splitter group 1 of window 1

set availableChoices to name of menu items of menu 1 of pop up button 2 of group 1 of splitter group 1 of window 1

click (first menu item of menu 1 of pop up button 2 of group 1 of splitter group 1 of window 1 whose selected is true)

end tell


set sortedList to (item 1 of availableChoices as list) & bubbleSort(items 2 thru -1 of availableChoices)


tell application id "com.figure53.QLab.5"

set theChoice to choose from list sortedList with prompt "Choose MTC destination:"

if theChoice is false then error number -128 -- User cancelled

set mtc sync source name of current cue list of front workspace to theChoice as text

end tell


-- Subroutines


on bubbleSort(theList) -- Standard bubble sort subroutine

set listLength to count theList

set itemsSwapped to true

repeat while itemsSwapped

set itemsSwapped to false

repeat with i from 1 to listLength - 1

set itemOne to item i of theList

set itemTwo to item (i + 1) of theList

if itemOne > itemTwo then

set item i of theList to itemTwo

set item (i + 1) of theList to itemOne

set itemsSwapped to true

end if

end repeat

end repeat

return theList

end bubbleSort


I chucked in a bubble sort as the list isn’t alphabetical.

If you want to be fancy and avoid the UI scripting, make an executable file named “listActiveMIDISources.swift” on your Desktop”

#!/usr/bin/env swift
import CoreMIDI
import Foundation

func getDisplayName(_ obj: MIDIObjectRef) -> String? {
    var param: Unmanaged<CFString>?
    let status = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, &param)
    guard status == noErr, let name = param?.takeRetainedValue() else {
        return nil
    }
    return name as String
}

func isOffline(_ obj: MIDIObjectRef) -> Bool {
    var offline: Int32 = 0
    let status = MIDIObjectGetIntegerProperty(obj, kMIDIPropertyOffline, &offline)
    return status == noErr && offline != 0
}

func listActiveMIDISources() {
    let count = MIDIGetNumberOfSources()
    var activeSources: [String] = []
    for i in 0..<count {
        let endpoint = MIDIGetSource(i)
        if endpoint != 0 {
            if !isOffline(endpoint) {
                if let name = getDisplayName(endpoint) {
                    activeSources.append(name)
                }
            }
        }
    }
    if activeSources.isEmpty {
        print("No active MIDI destinations found")
    } else {
        for name in activeSources {
            print("\(name)")
        }
    }
}

listActiveMIDISources()

Then:

set availableChoices to paragraphs of (do shell script quoted form of (POSIX path of (path to desktop) & "listActiveMIDISources.swift"))


set sortedList to {"None"} & bubbleSort(availableChoices)


tell application id "com.figure53.QLab.5"

set theChoice to choose from list sortedList with prompt "Choose MTC destination:"

if theChoice is false then error number -128 -- User cancelled

set mtc sync source name of current cue list of front workspace to theChoice as text

end tell


-- Subroutines


on bubbleSort(theList) -- Standard bubble sort subroutine

set listLength to count theList

set itemsSwapped to true

repeat while itemsSwapped

set itemsSwapped to false

repeat with i from 1 to listLength - 1

set itemOne to item i of theList

set itemTwo to item (i + 1) of theList

if itemOne > itemTwo then

set item i of theList to itemTwo

set item (i + 1) of theList to itemOne

set itemsSwapped to true

end if

end repeat

end repeat

return theList

end bubbleSort


You can develop the Swift scripts in Swift Playground, which is actually a much better IDE than Script Editor.

Rich

On 2 Sep 2025, at 13:57, Kalman Tarr <tarr....@gmail.com> wrote:

Hello Sam and Rich,
I understand the comment about the group's goal. I don't want to violate the basic principles. With your help, I learned a lot about scripting. As I wrote, I really like it! I try to approach a solution from several sides, examining the possibilities. This is where I fall.
Since I don't have a deep knowledge of the relationship between MAC OS and scripting languages, I admit that I'm asking stupid questions.
Sorry for that.

Why don't I start at the beginning? Because I've already solved the core of the problem. However, there are possible issues that apply to the creation of internal subroutines.

Well. Let me give you an example: we use an audio cue with markers. These markers need to give an instruction to an external device. In this case, a light control device. There, a light change needs to be performed. My solution: create a TimeCode cue.
First of all, two patches need to be set in the Settings Window MIDI interface. One that provides control between the two devices, the other is the internal patch (IAC driver).
Next, the script creates a MIDI cue series according to the number of markers.
MIDI cue
On the Settings tab, the passing patch must be set. Figure 1
On the Trigger tab, the timecode trigger must be set according to the markers. Figure 2
Of course, the settings shown on the main cue list timecode tab of the workspace. Figure 3
The task is to create the above work in a script.

When you start the timecode cue at the same time as the audio cue, it fires the MIDI cues one after the other.
This was the task. I hope my description is understandable. Sorry for the non-English terms.

I apologize again if I ask inappropriate questions.
Thanks for all the help, both of you!

Best regards.
Kalman

fig1
:
<MIDISettingsTab.jpg>

fig2:

<MIDITriggerTab.png>

fig3:
<CL-TimeCodeTab.png>


Reply all
Reply to author
Forward
0 new messages