Just use a "clone" of your operator! In theory, this should work for an arbitrary wavetable.

Perhaps somebody could tell me if I'm missing something important, but aurally, the difference between the naive approach and this are night and day, an sound sufficiently DX7-y to me.

The other trick, if you're trying to design a matrix-style with abstractions, is to make sure that you keep the "original" operator output out of its input, and that the modulation index goes to your "clone". I've accomplished that with dollar variables, as above, (e.g. operator 1 mods operator 1, "[r op-$1-mod-$1]") and in my matrix abstraction:

Basic flow-control here, $1 is the modulator operator id and $2 is the carrier operator id. So if they're the same (feedback!) don't let the signal through.

Anyway, I hope this helps anybody. I'll get the full synth up when the interfaces are a bit more usable, I'm pleased with how simple it's turning out to be.

]]>Just use a "clone" of your operator! In theory, this should work for an arbitrary wavetable.

Perhaps somebody could tell me if I'm missing something important, but aurally, the difference between the naive approach and this are night and day, an sound sufficiently DX7-y to me.

The other trick, if you're trying to design a matrix-style with abstractions, is to make sure that you keep the "original" operator output out of its input, and that the modulation index goes to your "clone". I've accomplished that with dollar variables, as above, (e.g. operator 1 mods operator 1, "[r op-$1-mod-$1]") and in my matrix abstraction:

Basic flow-control here, $1 is the modulator operator id and $2 is the carrier operator id. So if they're the same (feedback!) don't let the signal through.

Anyway, I hope this helps anybody. I'll get the full synth up when the interfaces are a bit more usable, I'm pleased with how simple it's turning out to be.

]]>Here is what I've come up with for doing matrix-style modulation of multiple operators including feedback, and it's based on the patch in the same topic you've linked.

https://forum.pdpatchrepo.info/topic/10745/3-op-fm-synth-with-mod-matrix

It's quite expansive but to me the difference between doing phase feedback at block 1 and 64 is indeed night and day, and I couldn't think of a simpler (and cheaper) way to do it other than with multiple [tabsend~], [tabreceive~] and block 1.

]]>I looked at your patch, and I have to admin that I don't really have the time to figure out where everything is in it. Though maybe with your help, I can get you far enough along to implementing my method as an experiment. In particular, I see [tabsend~ $2-$3.phase1] at the bottom of PMop.pd, but I can't find the corresponding [tabreceive~] for these signals.

I do see [tabreceive~ $2-$3.phase1] but that doesn't correspond to the naming schema above. So I guess if you could show me where the feedback is actually taking place, that'd be very helpful.

It may be that my implementation is too simplified a use-case for what you're trying to do, but in looking at the algorithm described in the post we both referenced, as well my own intuitive understanding of what the DX7 is doing with its feedback'd operators, I figured that it's just a cosine modulating the phase of a cosine of the same frequency. So instead of trying to feed the signal of a cosine back into itself, with all its attendant blocking issues, I figured it was easy enough to just use another [cos~] being read by the same [phasor~]. That's what you should see in the first screenshot in my original post.

The other second inlet~ marked "phase" is a mix of the other operator outputs sent through by the matrix. As described by the second screenshot, it doesn't contain any of the "self" operator signal, i.e. the "naive" feedback approach that sounds awful.

HOWEVER. I do see now how this does not actually implement the original algorithm, so you can disregard all of this. I'll keep working on it and I'll let you know if I find anything different.

]]>I'll try and explain my method in the linked patch: in the post we both linked there was a patch that used [tabsend~] and [tabreceive~] with [block~ 1] for doing the feedback, and to me that sounds a lot better than doing it with block~ 64. (this is shown in the feedback.fm patch attached).

When I'm modulating one operator with the output of another one, I can't really hear a difference between the two block sizes (you can hear this in the fm.blocksize patch).

However, in a multi-operator situation where there is also feedback, all the phases get added together and if the phase from the other operators is being updated every 64 samples, whereas the feedback works at block 1, it sounds awful so I figured it was best to have all phase modulation work at block size 1.

So, the way I've done it is to have a table for each operator to pull the phases from, and then the output of each operator is sent to each of these tables according to the indexes specified in the matrix. You can see these tables in the "tables" abstraction inside PMops.

Therefore, if for example operator 2 and 1 both send some of their output to operator 1 (one being the feedback), the phase table for operator 1 gets the sum of those two outputs (both updated at block size 1), which is then added to the [phasor~] phase of operator 1.

I think it sounds more complex than it actually is, and of course the patch is not very readable because of the dollar sign values I had to use in order to re-use the same abstraction for each operator.

]]>]]>HOWEVER. I do see now how this does not actually implement the original algorithm, so you can disregard all of this. I'll keep working on it and I'll let you know if I find anything different.