Interpolating between two function tables?

visa tapani's icon

I'm building an inharmonic additive synthesizer, where the frequency relations of the partials are given by a breakpoint graph (a function object). I'd like to be able to interpolate between two function tables to get the partials' frequencies. I can do some kind of interpolation with pattrstorage, but I haven't been able to figure out how to use it to morph the data from two function tables. Also it seems to lose some of the points of the function table while doing the morph.

Any advice?

Here's the main patch:

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

And here's the partial1 patch used by the poly:

For some reason some of the loadbangs and loadmesses don't seem to work, so you need to click some of the buttons in the main patch to get it initialized properly...

Any help is greatly appreciated, thanks in advance!

Tim Lloyd's icon

Have a look at the ej.linterp external from Emmanuel Jourdan :

It's in the ejies 2.0 download.

It's help file shows interpolation between two multisliders with the output displayed on a third multislider. It may help you out.

seejayjames's icon

pattrstorage should morph between the two functions just fine IF the number of points is the same in each. If not, it will lose points, as it can't do a one-to-one. So to make sure the number of points is the same, just have multiple points close to each other if need be to fill up the list length.

Also multislider might work for you too, and in some ways is easier to use. pattrstorage will work fine with that as well, again, assuming the list lengths are the same.

visa tapani's icon

Thanks for the pointers!

Those ej externals seem really cool and the ej.linterp does seem to be able to pull off what I'm looking for. However, since this is a class project where the work should be a self-contained folder, I think I have to refrain from using anything that needs installation for now. Later I'll use them for sure, though!

What I haven't been able to pull off with patternstorage yet is how to have two different function objects and interpolate between them. I'd like to have the two function graphs on the screen simultaneously and a slider with which the user could interpolate between them (much like in the ej.linterp help file). Is this doable with pattrstorage?

seejayjames's icon

Sounds like you'd need three functions: the first, the second, and the third is the interp between the two. the "recall $1 $2 $3" message would be used for this, where $1 and $2 are the stored slots you want to interp between, and $3 is a value from 0. to 1., where 0. is the same as slot 1, 1. is the same as slot 2, and 0.5 is halfway between.

So when you recall slots, they just need to go to the function you want. I'm not sure how to do this with just one pattrstorage though, and if you have two, I don't think you can interp between slots on different pattrstorages. Anyone else weigh in on this? Would be good to know.

I suppose you could use a placeholder function (invisible) to hold the recalls, then based on the slot chosen, these values then go to one of your two display functions. just use a [gate] that toggles back and forth, or maybe choose the destination based on the slot number recalled (like odds go to one, evens to the other, use %2 to determine odd or even).

Probably don't want to try setting the interp values back into a function that holds one of the slots, you could run into issues with the set messages and trying to create new slots. Better to use a third function that shows the interp result, or just use one for everything. If you use the "swap back and forth" technique above, you could have the other two functions on top of the real one, with transparent backgrounds, to show all three at once. Only the result one would be clickable.

mudang's icon

Here's an approach without pattr or externals.

It basically makes one list per breakpoint-envelope, interpolates between them and sets a third breakpoint object.

BTW, this way you can also do extrapolation (1.)

The interpolate-list subpatch maybe a bit cumbersome. I'm sure you could do this a lot more efficient with javascript.

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

seejayjames's icon

That's a nice approach. I don't think the subpatch is cumbersome, I like what you did with the iteration and the zl slice/zl reg. Though you could probably have just used [iter] if you're processing the elements one at a time. That said, anytime I see a new way to do recursion I'm definitely interested, especially with something like a list-interpolation.

Maybe the javascript version would be cleaner, but really you'd be doing the same thing: going through all the array elements, finding the difference between corresponding points, and applying the scale factor to determine the interp point. So it seems pretty much the same to me. Actually, using [vexpr] would be better here, process the lists all at once.

Anyone weigh in on the possible speed differences between these two approaches (max vs. js)? Assuming there are (say) thousands of points, where it would actually matter? Maybe jit.expr would be the best approach for speed with massive lists...

Emmanuel Jourdan's icon
Max Patch
Copy patch and select New From Clipboard in Max.

I would use vexpr. If you don't set the scalarmode attribute of the vexpr $f1+$f2, it will automatically adapt to the smallest list. Finally if you want more than 128 points, you'll have to set the first argument of zl iter 2 to something bigger.

mudang's icon

Wow!
What a beautifully elegant solution.
Emmanuel, you've shown once more, that max patching belongs to the fine arts

i really appreciate that.

visa tapani's icon

Thanks a lot, those are very inspiring pieces of code! They do exactly what I was looking for.

However, I've been thinking of another application of this list interpolation for my additive synth, which I'm not entirely sure how to pull off. I'd like to use interpolation between two breakpoint functions also for the amplitude envelopes of the partials in the following manner:

- Func1 gives the amplitude envelope for the lowest partial
- Func2 gives the amplitude envelope for the highest partial
- the partials in between would have amplitude envelopes interpolated between these two
(-> ie. if I had 21 partials, the 2nd partial would have an envelope of 95% f1 and 5% f2 and the 11th partial would have 50%/50% interpolation of the two functions.)

Or something of that sort, I thought it would be a fairly intuitive way of having a different amplitude envelope for the highest partials than the lowest ones. Should generate interesting results.

I suppose I could just duplicate for example the code by Emmanuel Jourdan 20 times, but I'm sure there's a more elegant way?

Tj Shredder's icon

Interestingly I was working on a similar project this summer. It is broken in 5.1 though. In 5.08 it works, haven't found the time to fix it (maybe I should just send it to support?)
Its an additive synth with some interpolation including complex sustain loop modes... Have a look at it...

Another sort of primitive physical model of a bowed string I made for MaxFor Live is also using some function interpolation derived from my "Yet Another Additive Synth"...

Have fun...

Stefan