"Changes cannot be triggered by notifications" Error

Jason Aylward's icon

Jason Aylward

5月 26 2020 | 1:19 午後

Hi. I hope this an acceptable place to ask this question because it's not a max4live question specifically. However, it is the only place on the internet that's discussed this error. Can anyone explain what "Changes cannot be triggered by notifications. You will need to defer your response." means?
I've been playing around with the python control surface scripting in Ableton and I run into this error when trying to add tracks to ableton. I see in an older max4live post, someone mentioning the "defer" keyword in max but I don't think there's an equivalent in python so I'm not sure what "deferring your response" would mean.
Thanks for any help you might be able to provide!

tyler mazaika's icon

tyler mazaika

5月 26 2020 | 3:46 午後

Live can't react to a change to the live set caused within a chunk of audio processing to modify the way part of the live set behaves within the same chunk of audio processing.

The 'notification' is something letting the program (you) know that a "change to the live set" has occurred. (In your case like adding a new Live track if you may be observing/listening/asking to be notified when the number of tracks in the set changes). Deferring the response means whatever you are doing in response is done later at a lower priority (than the super-critical audio calculations of this instant). I don't know what it looks like to do this in python in this case, but maybe you can find examples in other hacked python control surface scripts what are obvserving/responding to changes to see how they handle it?

Jason Aylward's icon

Jason Aylward

5月 26 2020 | 3:56 午後

Thanks Tyler! That jives with what I was reading in some of the other posts. That maybe it's an issue with doing lower priority work on a high priority thread.
I've been mostly looking through decompiled python scripts for the Push2 but it's SO complicated, I'm not quite sure how it's working at the lowest levels. I'll take a look and see if I can find someone successfully getting it to work somewhere on github.
Are you aware of any other resources for hacked control surface scripts? I've only been messing with this for a couple weeks now so it's pretty new to me.
Thanks again.

Evan's icon

Evan

5月 27 2020 | 3:00 午後

I've written quite a few scripts, some simple, and a few not so simple. I never ran into that particular error message with working in scripts, only when programming in M4L. What exactly are you trying to do? My instinct is that you are using a change in Live to then add a track to the set?

Jason Aylward's icon

Jason Aylward

5月 27 2020 | 5:06 午後

I've been working on a script to automate running the audio_to_midi conversions so when I select my custom control surface, it runs the script.
I wrapped the actual logic inside a listener because loading data into a clip crashes Live if my control surface is selected when Live is booted.
If this makes any sense, bare boned example below. ( did my best with formatting)

class AudioToMIDI(ControlSurface):
def __init__(self, *args, **kwargs):
app = Live.Application.get_application()
app.add_control_surfaces_listener(load_and_convert_files)

def load_and_convert_files():
     song = Live.Application.get_application().get_document()
     song.create_audio_track(-1)  # throws "Changes cannot be triggered by notifications"
def create_instance(c_instance):
 return AudioToMIDI(c_instance=c_instance)
Evan's icon

Evan

5月 27 2020 | 5:14 午後

Yeah I don't think you want to call that in your init function. That's my best guess though, you're using the Control Surface in a bit of an out of the ordinary way, so all I have are guesses.

Jason Aylward's icon

Jason Aylward

5月 27 2020 | 5:25 午後

haha, yeah... that seems to be a bad habit of mine. Find a tool for X and try to use it for Y.

Can you think of a way to trigger a control surface function automatically? I could tie all the functionality to a button on the Push2 or to a socket connection but I was really trying to get it all to work without having to run a second script to fire off the control surface.

Evan's icon

Evan

5月 28 2020 | 1:37 午前

I'm not sure about that actually. Most functions in a control surface are in response to something, a change in Live, an input from a MIDI controller etc. So I'd look at those options. You could set a flag in the init, and then observe something in Live, if it changes call your function, then set the flag to 0, so you only call it once. Or something, I'm just spitballing here.

xx/xy's icon

xx/xy

5月 01 2021 | 2:05 午後

Just happened upon this thread because I was looking to do the same. After doing some more digging, I found that it is possible to defer execution to the control thread by calling self.schedule_message(0, function) from a ControlSurface object, where 0 is the delay in "ticks" (where a tick is 100ms), and function is the function or lambda you want to call.