Python - Events, Descriptors, & Dictionaries | MUSE
In this video, you’ll be introduced to the core concepts of event-driven programming in AMX MUSE using Python. We’ll break down how watches, listeners, and device descriptors work together to drive responsive control logic. You’ll learn how to identify whether an attribute is a parameter or an event by exploring descriptor files in both JSON and text formats. The tutorial also demonstrates how to set up event triggers, write callback functions, and inspect event data using Python dictionaries—giving you deeper insight into the information available for building robust automation.
What You’ll Learn:
• Fundamentals of event-driven programming in MUSE
• Understanding watches, listeners, and device descriptors
• Identifying parameters vs. events using descriptor files
• Working with JSON and text-based descriptor formats
• Setting up event triggers and callback functions
• Inspecting event data using Python dictionaries
• Building responsive logic based on real-time interactions
Hello, and welcome to this video on events in your MUSE Python code. Many aspects of A/V programming are event based. Whether that is someone pressing a button on a touch panel or waiting on a response from a device, it’s these events that we trigger our code on to perform any number of actions.
In MUSE programming, there are two different kinds of events, watches and listeners. Whether it is a watch or a listen depends on the object attribute being referenced. Watches are based on changes to parameters, while listeners are triggered by events.
So, the next question is how do we know if a given attribute is a parameter or an event?
There are two ways to determine whether an attribute is a parameter or an event. One way is to reference the documentation of the object you are communicating with or controlling. The second, and probably more functional method is looking at a device’s Descriptor file.
A Descriptor file is created at runtime when a device is created or connected to a MUSE controller. It contains all the attributes associated with the device. This means everything that can be done to or heard from the device is contained in that file.
To access a Descriptor file, connect to a MUSE controller with VSCode. Under your controller, expand out the Devices section by clicking the arrow beside Devices. Now, right-click on the device you want to look at, in this example we will use idevice, and select Descriptor.
At the top of the screen, you will see a dialogue box that asks if you want to view the descriptor as a json file or a specially formatted text file. Let’s select json to begin with. For this example, let’s look at the receive attribute of a serial port.
You can see the beginning of the attribute on line 18. What we are looking for is the .kind metadata attribute for receive. In this case it is an event and would be listened to. Any .kind metadata attribute listed as param is a parameter and would be watched.
Selecting text as the Descriptor type will show you a specially formatted text document that shows the same information as the json file. In this case, the text is a hierarchical representation of the information where each tabbed in section is a subset of the previous level. If we search for the same ‘receive’ attribute, you can see that receive is shown to be an Event. Also, unlike the json file, parameters are labeled as parameters and not param.
Now that we know the kind of attribute we are dealing with, how does this translate into code? Whether it is a watch or listen method we need to use, the syntax is the same. We create the event trigger and pass the method a callback function.
For this example, we will use a button for our event. Our touch panel contains a button with channel number 1 on port 1. If you look at the Descriptor file for a touch panel, you will see that all buttons are parameters. So, for this example we will be using a watch.
Both watch and listen are methods that are run on an object, in this case our device. Type in the device object, the attributes related to that object, and add the watch method. In this case we will type in
*** Enter code ***
dvTP.port[1].button[1].watch()
*****************
The watch must be passed a callback function, let’s call the function buttonEvent.
*** Enter code ***
dvTP.port[1].button[1].watch(buttonEvent)
*****************
Now we need to create the function and program in what we want it to do. For this example we are going to printout the dictionary for the event. The attribute dictionary, designated by the method __dict__ is a fantastic Python tool that will show you the instance namespace or attributes related to an object. You can printout the dictionary of any event to see all the information that is provided by the event
*** Enter code ***
def buttonEvent(event):
context.log.info(f”Dictionary printout: {event.__dict__})
Notice that this one line of code shows us that the event provided by a button contains the ID, path, device, value, new value, old value, and normalized value of the parameter that was being watched. Using all of this information, you should be able to program anything else necessary to react to the event triggered by the button[R.