lmms icon indicating copy to clipboard operation
lmms copied to clipboard

Add Per-Note Pitch Bending to Local ZynAddSubFX

Open regulus79 opened this issue 6 months ago • 2 comments

This PR adds pitch bending support to the local ZynAddSubFX plugin, so you can pitch bend from the piano roll and have the notes actually change pitch correctly.

Demo

https://github.com/user-attachments/assets/16747424-43c8-4ff7-9c0e-5d2c3ba74249

Per-note demonstration (because I forgot to in the previous video)

https://github.com/user-attachments/assets/db7df50b-33f7-4777-ad40-57dad3bf0c3b

How it works

  1. A note is played by the user
  2. ZynAddSubFX::playNote() is triggered, which calls LocalZynAddSubFX::setKeyDetuning(note, detuning)
  3. LocalZynAddSubFX::setKeyDetuning reaches into the actual ZynAddSubFX plugin and calls Master::setKeyDetuning
  4. Master::setKeyDetuning calls Part::setKeyDetuning on each of its parts, which saves the detuning float in the note struct corresponding to the note being pitch-bended.
    • This is possible because ZynAddSubFX only allows one note to be played per key at once, so instead of indexing each note by some kind of global id which would need to be shared with LMMS, you can index it by its key and it works just fine.
  5. In the audio side, Part::RunNote calls SynthNote::setKeyDetuning on the note about to be played. The behavior of this function depends on which synth is used, AdSynth, SubSynth, or PadSynth.
  6. In each synth implementation, Ad/Sub/PadSynth::computecurrentparameters() is usually changed to incorperate the detuning amount in the pitch calculation. It depends though, since each synth is different.

Notes

Unfortunately, this PR only works when the UI is closed. This is because when the UI is open, the ZynAddSubFXRemotePlugin is used, which appears to only accept communication via standard midi signal codes/remote plugin codes. I do not believe per-note pitch bending is one of them, so it may be difficult to get that working.

... Or I could just invent a new midi code and use that I guess LOL... That's probably a bad idea though.

Also, I can't figure out how to modify the pitch of SubSynth, so currently it only works for AdSynth and PadSynth.

regulus79 avatar May 26 '25 19:05 regulus79

Apologies while I try to figure out how to link submodule changes into a PR

regulus79 avatar May 26 '25 19:05 regulus79

One time lmms crashed:

Oh good, I also encountered this crash when testing a while back. It ended up crashing my entire desktop lol. I will have to look into this further.

regulus79 avatar Jun 15 '25 19:06 regulus79

First of all, this is quite an interesting PR.

I do not believe per-note pitch bending is one of them, so it may be difficult to get that working.

I think MIDI MPE should do it. I think zyn cannot do it yet (src/Nio/MidiIn).

You could send it on the LMMS side and implement it on the zyn side - we could later even re-use the LMMS part for Lv2 and others, and even re-use the zyn part on zyn's master.

JohannesLorenz avatar Jul 16 '25 22:07 JohannesLorenz

I was just thinking about this PR, and I'm starting to feel like my method of calling a function on zynaddsubfx rather than passing it through the midi may be a bad idea.

I think MIDI MPE should do it. I think zyn cannot do it yet (src/Nio/MidiIn).

You could send it on the LMMS side and implement it on the zyn side - we could later even re-use the LMMS part for Lv2 and others, and even re-use the zyn part on zyn's master.

That's probably a way better idea. I am not familiar with the MIDI MPE format though, so it may take some time for me to figure out how to implement it that way. But I totally agree, that sounds like a much cleaner way to do it.

I was originally hesitant to touch the midi signal stuff, but if it's in the actual midi spec (although perhaps a more advanced version) then maybe it's fine.

regulus79 avatar Jul 16 '25 23:07 regulus79

I also had an idea and just want to put it out there--it may be beneficial to (either in addition or instead of) also implement an option for the per-note pitchbending to not be "per-note", and instead just override the midi pitchwheel. That would allow some instruments to be pitchbent without having to make an automation clip for it. Not as powerful, but perhaps more general and compatable with normal midi. But that's just an idea, idk.

regulus79 avatar Jul 16 '25 23:07 regulus79

I had the idea to let LMMS per-note pitchbend call MIDI pitchwheel, too. I think that could be used as a fallback. But MPE is the way to go IMO.

Your current implementation can still be use if we cannot make MPE work.

JohannesLorenz avatar Jul 17 '25 09:07 JohannesLorenz