Adsr~ and muting issue

Peter McCulloch's icon

Something I've noticed in my poly~ patches is that when I first load them, all voices are on. I have thispoly~ connected to adsr~ in the standard way (including muting info), so it seems that what should happen is this:
all voices muted, envelopes off
but what I'm getting instead is:
all voices on, envelopes off

Using loadmess 0 doesn't work, because adsr~ already thinks it's off, so it doesn't send the mute message again. (adsr~ only sends mute 1 messages once, though it sends mute 0 messages every time there's an attack)

Max Patch
Copy patch and select New From Clipboard in Max.

I can fix this by loadbanging a message box with "1, 0" going into adsr~, but this is a bit of a kluge because it involves turning everything on and then turning everything off, and this problem really shouldn't require two states. I could loadmess the mute message into this poly~, but it would be nicer if adsr~ could handle this on its own.

Chris Muir's icon

Why not just directly hit thispoly~ with an initialization message, and not rely on adar~ to set the initial state?

Peter McCulloch's icon

Of course that's doable, but if a poly~ voice of a synth isn't producing any sound, it would generally also make sense for it to be muted, and since adsr~ is supposed to take care of the mute state automagically, it would make sense that those two things go together.

There's very few use cases where you want no output but signal processing, and far more where you need output and muting alternately. I'm just saying that it makes much more sense for this to be the default than vice versa, and poly~ is something that people always seem to struggle with, so why add one more loadmess to the equation?

Chris Muir's icon
Max Patch
Copy patch and select New From Clipboard in Max.

But it's not another loadmess, is it? Just a different destination. Here's a version of my StupidSynth example:

Peter McCulloch's icon

No, in your patch it really is another, but what I mean is that if adsr~ defaults to being off, then it should output the mute state when the object is initialized, because that is what you would normally expect from adsr~ when it's not outputting.

This way, in your patch, there's no need at all for a loadmess to turn muting on, because the default state of the voice (adsr~) is off, consequently the patch is muted. Imagine your synth had 1000 voices; do you really want them all to be consuming CPU while they're initialized to being off (via their envelopes)? Granted there are a few instances where you might want CPU to be on, but the envelope would also be switched on, so it doesn't make sense to have the envelope and the mute state out of sync.

It's a minor point, but it would make things more consistent, and it would make polyphonic patching slightly easier for the newbie.

Chris Muir's icon

It's certainly not another compared to your top patch, but I take your meaning that those were already extra messages that would not be needed if adsr~ worked the way you propose. One issue I can think of is that adsr~ has no idea when things that it may be connected to are actually instantiated. loadbang and loadmess are special cases that fire after a patch is completely loaded.

I'm not saying that it couldn't be done, but I can't imagine that it's worth the effort, given how easy it is to sent a message with the existing rules. Also, many patches use things other than adsr~ to hit thispoly~, and it sounds to me like quite a rabbit hole trying to get them all to behave in the manner you propose.

Peter McCulloch's icon

Yes, I agree that you can't always know what adsr~ is connected to, but it actually shouldn't matter in this circumstance. I can't think of a reason why I would have adsr~'s mute outlet connected to thispoly~ if I didn't intend it to be muted when the envelope is off, especially since this is how it normally operates.

It's a little weird that the first thing that I'm doing with my synth is muting everything (even though it's not making sound), then on. This doesn't mirror normal operation where when an envelope starts, the voice is unmuted, and when the envelope is finished with the release, the voice is muted.

It's not a big deal for me, but I teach Max, and my students always have trouble with poly~. It's nice to say "just hook up adsr~ and thispoly~ for now (until you know more) and it will take care of things." I do address more complicated envelope situations, but it's nice to have a consistent simple example, and since that's the point of adsr~'s mute outlet, I think this behavior makes sense, and I really can't think of a use case where it has a negative effect, since if you're using it, you already expect muting anyways, and there's no advantage to having it unmuted once when you load it.

Chris Muir's icon

Right, but because Max is more or less a data flow language, the patch network needs to be complete before it can send anything. During patch instantiation, adsr~ could be created before whatever it's controlling and when it sent its initial mute state, the thing that it is trying to mute might not be created yet. It's been a long time since I used the Max SDK, but I don't think that at instantiation time an external knows when the things it's hooked up to are ready. A different thing to lobby for is to have thispoly~ come up muted, but I don't think that that is any more likely to happen.

Look at it this way, with the current behavior, your students will get a "high water mark" on DSP usage before they start muting things through the normal use of poly~. Maybe if the message was "pauseDSP" instead of "mute," it wouldn't feel like you were doing something extra.

Peter McCulloch's icon

I understand this, but the mute message is tied to the completion of the envelope, so it's not really even an instantiation issue, save for the fact that the object itself instantiates to an in-between state that is otherwise unreachable.

When the dsp turns on, adsr~ should correctly indicate its mute state in a manner that is consistent with its internal state. This works fine within almost any context, poly~ or otherwise, and is consistent with the expected behavior; otherwise, why would you have something hooked up to the mute outlet?

The current behavior is more of a bug than a feature, and the fact that it requires a workaround every time I build a synth indicates that. There doesn't seem to be any function for the current behavior, and I can't think of a usage case where it's helpful. (feel free if you have one, though) When a user is adding a synth to the rack in Max4Live that could chew up say 20% of their CPU, do you really want that to be the default? (especially when there seems to be no advantage to the end user)

Chris Muir's icon

Yeah, but if "the mute message is tied to the completion of the envelope" the current behavior is consistent: there hasn't been an envelope completed, so no message has been sent.

Most things in Max only send things when something happens, either internal state changes or some message is received. The adsr~ mute message is sent when something happens, not continuously to indicate state.

Maybe I've been using Max too long, but IMO, there are _lots_ of things that need proper initialization in Max, mute status to thispoly~ is just one of them.

Peter McCulloch's icon

But the state of the envelope is as is if had been completed. Since the outlet is there to simplify the operation of poly~, why not?

You've been here longer than me, but I've had 13 years myself, and it seems like this is something simple to fix and worth fixing. There's no downside that I can see, other than minor philosophically.