Schmitt triggering a list of arbitrary length?

Rodrigo's icon

So I've working on some list post-processing in a patch and I'm running into a bit of a snag when trying to schmitt trigger a list.

It would be easy enough to do if I had a finite list length, but I may get any length of list going into this (including list length = 1).

I've tried a couple of different approaches and each runs into a problem (generally around needing a [change] object in there somewhere, and that breaking the (re)[zl group]-ing of the list back together.

I was also hoping for a "native" [vexpr] solution, but I couldn't figure that out either.

Anyone have any luck schmitt-ing a list?

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

testcase's icon

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

Rodrigo's icon

I was confused at first thinking "man, is it really that easy?!".

Turns out it's not... or at least this isn't quite right.

In yours it evaluates as true when it's between the low and high threshold, whereas in a proper schmitt trigger it keeps track of a state.

So with the thresholds of 0.5 and 1.0, it will be true when it exceeds 1.0 but won't go false again until it goes below 0.5.

Here's a more legible 'single value' version:

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

So if [vexpr] allowed recursion it would be possible as you can update the thresh based on the output, but it doesn't.

There's also js, but there's gonna be a lot of data pumping through this, and with js running in the low priority thread, things are likely going to get bogged down.

testcase's icon

oh sorry. don't know what i was thinking. i think i have another idea.

Rodrigo's icon

The suspense!

testcase's icon

here are two ways but the pure list version has an issue when the list size changes. i am not sure how to solve that

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

Rodrigo's icon

Awesome, those are great solutions!

Man, looking at a string of [vexpr]s takes some thinking to figure out.

Hmm, the purely vexpr version seems to be playing nice with list length changes, but I've not thrown too much at it. In my specific use-case I think it will be fine either way since the list length will be static once it's in use. It may be used in multiple places, with different list lengths.

edit: I see the problem. If you go "small", you can't go "big" again.

With regards to the bit about the "rightmost output", are you referring to the third "l" in the [t l l l]?

Lastly, in taking a look at the jit.gen version, I thought about just doing one in vanilla (Max8) gen. Seems easy enough, with the [history] operator outside of the codebox. There's probably a way to have the recursion happen directly in the codebox, but I couldn't get it working immediately. It also doesn't work on lists either.

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

In terms of which of your options to use, in a high data throughput context, is [jit.spill]-ing "slower" than just straight [vexpr]-ing? (I've not used much jitter outside of a visual context)

Rodrigo's icon

Ok, solved the list size changing problem.

There was one [vexpr] in particular (the [vexpr $f1==1 @scalarmode 1] near the end) that would get "stuck" on the last list length.

So whenever the list length changes, it feeds that a dummy list of appropriate size, then reevaluates the current list. The list length adaptation section is more objects than the actual schmitt trigger part, but at least it's more robust now.

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