Channel Pressure Behavior: Fixed in Custom Firmware
-
- KVRist
- 32 posts since 8 Jan, 2023
TLDR: Official Linnstrument firmware resets pressure data at note on/off, and only sends pressure data for the most recent pad held. For non MPE synths (or any synth played in "One Chan" or "ChPerRow" mode), this causes an abrupt jump in z-values from 0 to/from the value of whatever prior pad is held. This behavior is similar for y-values.
This was fixed in a non-supported and no-promises-made custom firmware modified by teknico, with the result that playing non MPE synths is more predictable and z-data and y-data is more usable to control synth parameters. The changes do not negatively impact MPE function, or other mode use-cases.
Brand new Linnstrument owner. I'm a 99% hardware guy, and have one MPE synth (Hydra) and one PolyAT synth (Ensoniq SD-1) and many other vintage (and newer) Mono AT synths. I intend to use my Linnstrument as my main MIDI performance device. Since most of my synths don't do Poly AT or MPE, I'm using the Linnstrument in Channel Pressure mode with Pressure set to "Aftertouch."
On the Linnstrument, using Channel Pressure and playing more than one note often causes a jarring jump in whatever parameter is being controlled by pressure. For example, if pressure is controlling filter cutoff, pressing a pad firmly opens the filter, and pressing a second pad lightly causes the filter to snap closed. So a firmly held drone note's open filter will "snap shut" if a subsequent pad is touched lightly. Worse (for me) the filter will snap back open when the second pad is released. (Perversely, the slower you release, the more abrupt the jump up.)
This is by design, from the manual under Smart MIDI: "In this case, the sent pressure data is taken only from the most recent touch." But this is very different to how other controllers (pad and keyboard) work, and for me doesn't work great. It almost sounds like the note is re-triggered.
The way I wish it worked: When "Aftertouch" is selected in the Pressure setting column, pressure data from additional touches would only be sent if they exceed the prior pad's pressure value. Example:
Pad 1 pressed, Pressure held around 70; pressure data sent, filter mostly open
Pad 2 pressed, Pressure held below 70; no new pressure data sent, filter remains unchanged
Apply greater pressure to Pad 2 and once it passes 70 (or the current value of Pad 1), the filter opens more
Release Pad 2 and the pressure drops back down to the current level of Pad 1 (or whatever next highest value is there if more keys are pressed), and the filter is closed to that prior highest level
This is basically how all Mono AT keyboards work and how all Channel Aftertouch synths expect their MIDI: the highest pressure value of any one key is sent (since there's only one sensor all keys act as one), and releasing a "high pressure" key reverts down to the next highest value key.
Roger was very responsive by email (thanks again if you read this, Roger), and was very upfront about this not being an issue reported by any other users, and so unlikely to be changed in the mainline code.
I did not see a sub forum devoted to hacking the firmware so I'm posting here. Are there any Arduino programmers here that might be willing to assist me in implementing this myself? I'm no programmer, but I'm not afraid to learn/try!
I feel like the start of my hacking would be around line 531 of ls_touchinfo.ino the trick being making a comparison of the value of lastValueMidiPP and the current loudnessChannelPressure in ls_midi.ino and only sending new Aftertouch/pressure data when loudnessChannelPressure exceeds levels of the last value held.
If no one is motivated by the love of a challenge, let me know and we'll talk beer money or maybe you'd be interested in a gear for code swap. LOL.
Thanks!
This was fixed in a non-supported and no-promises-made custom firmware modified by teknico, with the result that playing non MPE synths is more predictable and z-data and y-data is more usable to control synth parameters. The changes do not negatively impact MPE function, or other mode use-cases.
Brand new Linnstrument owner. I'm a 99% hardware guy, and have one MPE synth (Hydra) and one PolyAT synth (Ensoniq SD-1) and many other vintage (and newer) Mono AT synths. I intend to use my Linnstrument as my main MIDI performance device. Since most of my synths don't do Poly AT or MPE, I'm using the Linnstrument in Channel Pressure mode with Pressure set to "Aftertouch."
On the Linnstrument, using Channel Pressure and playing more than one note often causes a jarring jump in whatever parameter is being controlled by pressure. For example, if pressure is controlling filter cutoff, pressing a pad firmly opens the filter, and pressing a second pad lightly causes the filter to snap closed. So a firmly held drone note's open filter will "snap shut" if a subsequent pad is touched lightly. Worse (for me) the filter will snap back open when the second pad is released. (Perversely, the slower you release, the more abrupt the jump up.)
This is by design, from the manual under Smart MIDI: "In this case, the sent pressure data is taken only from the most recent touch." But this is very different to how other controllers (pad and keyboard) work, and for me doesn't work great. It almost sounds like the note is re-triggered.
The way I wish it worked: When "Aftertouch" is selected in the Pressure setting column, pressure data from additional touches would only be sent if they exceed the prior pad's pressure value. Example:
Pad 1 pressed, Pressure held around 70; pressure data sent, filter mostly open
Pad 2 pressed, Pressure held below 70; no new pressure data sent, filter remains unchanged
Apply greater pressure to Pad 2 and once it passes 70 (or the current value of Pad 1), the filter opens more
Release Pad 2 and the pressure drops back down to the current level of Pad 1 (or whatever next highest value is there if more keys are pressed), and the filter is closed to that prior highest level
This is basically how all Mono AT keyboards work and how all Channel Aftertouch synths expect their MIDI: the highest pressure value of any one key is sent (since there's only one sensor all keys act as one), and releasing a "high pressure" key reverts down to the next highest value key.
Roger was very responsive by email (thanks again if you read this, Roger), and was very upfront about this not being an issue reported by any other users, and so unlikely to be changed in the mainline code.
I did not see a sub forum devoted to hacking the firmware so I'm posting here. Are there any Arduino programmers here that might be willing to assist me in implementing this myself? I'm no programmer, but I'm not afraid to learn/try!
I feel like the start of my hacking would be around line 531 of ls_touchinfo.ino the trick being making a comparison of the value of lastValueMidiPP and the current loudnessChannelPressure in ls_midi.ino and only sending new Aftertouch/pressure data when loudnessChannelPressure exceeds levels of the last value held.
If no one is motivated by the love of a challenge, let me know and we'll talk beer money or maybe you'd be interested in a gear for code swap. LOL.
Thanks!
Last edited by ryanpg on Fri Jan 20, 2023 8:53 pm, edited 4 times in total.
-
- KVRist
- 109 posts since 29 Sep, 2014
What about using an expression pedal conntected to your synth? So you can control channel aftertouch by your foot and on the LinnStrument you set "loudness/z" to "off".
-
- KVRist
- Topic Starter
- 32 posts since 8 Jan, 2023
That's a great idea for a workaround, thanks! Hadn't considered that option. If I can't sort out the code (it's super well organized and thoroughly documented) I now have three* options:
1) don't use channel aftertouch (shame to lose it on an instrument designed for expression)
2) try adding a foot pedal
3) adapt my playing so that "release" pressure between finger presses are even
I've seen this issue reported before, but the resolution isn't really clear in those cases. I think it's true that most linnstrument players use VSTs that do MPE, so a hardware synth guy using a linnstrument is a minority of a minority of musicians and this simply doesn't impact many people.
Still hopeful someone with Arduino coding skills shares my pain.
*Guess option 4 is really learn C/C++, and 5 is maybe linnstrument isn't for me. The former is preferable.
1) don't use channel aftertouch (shame to lose it on an instrument designed for expression)
2) try adding a foot pedal
3) adapt my playing so that "release" pressure between finger presses are even
I've seen this issue reported before, but the resolution isn't really clear in those cases. I think it's true that most linnstrument players use VSTs that do MPE, so a hardware synth guy using a linnstrument is a minority of a minority of musicians and this simply doesn't impact many people.
Still hopeful someone with Arduino coding skills shares my pain.
*Guess option 4 is really learn C/C++, and 5 is maybe linnstrument isn't for me. The former is preferable.
-
- KVRist
- 109 posts since 29 Sep, 2014
From my perspective, the LinnStrument is designed to work best with MPE-synths.
From my experience, your option 3 is not possible, because if you release a key, the z-value always goes down to zero. On the other side, if you press a key (note-on), the z-axis always starts at zero. The problem in playing polyphonic in one-channel-mode is that if you already play a key and hit another key, the z-value will start at zero again and creates the problem you described.
In your case, I would use the LinnStrument for MPE-synths only and for other synths I would stay on traditional keyboards ... or only use MPE-synths at all.
I use the LinnStrument exclusively with VCV Rack (a software synth), everything else doesn't meet my criterias especially for the z-axis. I use the z-axis exclusively for volume, not for filters. For filters I use the y-axis. I always use the x-axis unquantized, because I don't like the pitch quantisation algorithms that are built into the LinnStrument.
IMO the best thing is to learn to play/use the LinnStrument with synths it is designed for. After some practice, I assume the idea of hacking the Arduino code will become less and less important.
From my experience, your option 3 is not possible, because if you release a key, the z-value always goes down to zero. On the other side, if you press a key (note-on), the z-axis always starts at zero. The problem in playing polyphonic in one-channel-mode is that if you already play a key and hit another key, the z-value will start at zero again and creates the problem you described.
In your case, I would use the LinnStrument for MPE-synths only and for other synths I would stay on traditional keyboards ... or only use MPE-synths at all.
I use the LinnStrument exclusively with VCV Rack (a software synth), everything else doesn't meet my criterias especially for the z-axis. I use the z-axis exclusively for volume, not for filters. For filters I use the y-axis. I always use the x-axis unquantized, because I don't like the pitch quantisation algorithms that are built into the LinnStrument.
IMO the best thing is to learn to play/use the LinnStrument with synths it is designed for. After some practice, I assume the idea of hacking the Arduino code will become less and less important.
-
- KVRist
- Topic Starter
- 32 posts since 8 Jan, 2023
Thanks, I appreciate your reply. You're probably right to suggest that I abandon the Linnstrument as a traditional (non PolyAT non MPE) synth controller. Shame because I didn't realize this limitation prior to buying it. A big part of what I love about the Linnstrument is that it's tactile. I just don't enjoy software synths for making music.
Yes, you very succinctly stated the issue (thanks for summarizing my wall of text) "play a key and hit another key, the z-value will start at zero again and creates the problem you described."
The solution is to compare the z-value of the new key to any pre-existing z-value, and only transmit pressure data if the new z-value goes higher than the prior z-value.
I'm reading the code and learning about C/C++. Even though this is probably a 20 minute fix, it'll be another year before I can actually implement it. LOL.
Yes, you very succinctly stated the issue (thanks for summarizing my wall of text) "play a key and hit another key, the z-value will start at zero again and creates the problem you described."
The solution is to compare the z-value of the new key to any pre-existing z-value, and only transmit pressure data if the new z-value goes higher than the prior z-value.
I'm reading the code and learning about C/C++. Even though this is probably a 20 minute fix, it'll be another year before I can actually implement it. LOL.
-
- KVRist
- 109 posts since 29 Sep, 2014
No, it's not a 20 minutes hack.ryanpg wrote: Sun Jan 08, 2023 4:42 pm The solution is to compare the z-value of the new key to any pre-existing z-value, and only transmit pressure data if the new z-value goes higher than the prior z-value.
I'm reading the code and learning about C/C++. Even though this is probably a 20 minute fix, it'll be another year before I can actually implement it. LOL.
You have to keep track of all actual playing notes and deliver the max. pressure of all of that notes over MIDI. Maybe this will introduce a delay for the z-value, and you have to add this delay to all other values as well to keep the MIDI output consistent. Maybe you have to change not one file but a handful of files to get your hack/fix done. Maybe your approch is wrong and you have to start over again several times.
And after the work is done, you have to test your hack/fix with several synths. And as you do so, you will discover bugs you didn't even think of, maybe bugs that were in the firmware before and weren't even discovered yet because they only popped up in combination with your new code. Then you will have to fix those bugs and test again and again until the result meets your conditions.
If you want your fix/hack to be integrated in the official software release, I think you would need to provide a new user-interface entry that gives other users the option to disable your feature, because they rely on the old behavior.
If you your fix/hack will not be integrated into the official software release, you can't upgrade the firmware to a new version without re-implementing and testing your fix/hack.
I'm quite familiar with C++ but I have no experience with coding for the Arduino. I took a look at the firmware code for several times, and I don't want to apply any changes.
-
- KVRist
- Topic Starter
- 32 posts since 8 Jan, 2023
Well, as a person with very limited experience coding, your description of the potential complexity rings true.
"You have to keep track of all actual playing notes and deliver the max. pressure of all of that notes over MIDI."
Well, this already happens right? As the code is, the newest note pressed sends pressure. And when released the prior pad resumes sending pressure data. The only difference in my method would be that no pressure data would be sent until it crosses the threshold of the previous highest pressure value. Less data sent at the cost of doing the comparison.
"If you want your fix/hack to be integrated in the official software release . . ."
I don't really. I get that feature requests are met with a default "no" in most commercial projects.
"you would need to provide a new user-interface entry that gives other users the option to disable your feature, because they rely on the old behavior."
But I think the "Aftertouch" setting is meant to approximate traditional channel pressure behavior. Although I can't imagine a use case for the current method (no other controller in existence does it this way) but you're right, there may be people who love the way the pressure values jump. Evidently I'm the only person that considers this a problem.
"If you your fix/hack will not be integrated into the official software release, you can't upgrade the firmware to a new version without re-implementing and testing your fix/hack."
I anticipate that. Hopefully, if I can figure this out (or someone offers to help) I would probably maintain my own modded source tree.
Honestly, my bet is that people would prefer the way I'm suggesting, but that's what everyone with a feature request thinks! Hah!
Again, I really appreciate your responses! I totally get that this may seem a lot of work for little or no gain to current users.
"You have to keep track of all actual playing notes and deliver the max. pressure of all of that notes over MIDI."
Well, this already happens right? As the code is, the newest note pressed sends pressure. And when released the prior pad resumes sending pressure data. The only difference in my method would be that no pressure data would be sent until it crosses the threshold of the previous highest pressure value. Less data sent at the cost of doing the comparison.
"If you want your fix/hack to be integrated in the official software release . . ."
I don't really. I get that feature requests are met with a default "no" in most commercial projects.
"you would need to provide a new user-interface entry that gives other users the option to disable your feature, because they rely on the old behavior."
But I think the "Aftertouch" setting is meant to approximate traditional channel pressure behavior. Although I can't imagine a use case for the current method (no other controller in existence does it this way) but you're right, there may be people who love the way the pressure values jump. Evidently I'm the only person that considers this a problem.
"If you your fix/hack will not be integrated into the official software release, you can't upgrade the firmware to a new version without re-implementing and testing your fix/hack."
I anticipate that. Hopefully, if I can figure this out (or someone offers to help) I would probably maintain my own modded source tree.
Honestly, my bet is that people would prefer the way I'm suggesting, but that's what everyone with a feature request thinks! Hah!
Again, I really appreciate your responses! I totally get that this may seem a lot of work for little or no gain to current users.
-
- KVRist
- 109 posts since 29 Sep, 2014
You're welcome!
The more I think of this problem, the more the complexity grows:
If you play polyphonically in one-channel-mode, the same issue not only happens for the z-axis, it also happens for the x-axis (pitch-bend) and for the y-axis (CC-1 or CC-74). So there would be a lot more to do to adapt the LinnStrument for playing polyphonically in one-channel-mode without any glitches on the the x/y/z-expressions.
I assume that people who play polyphonically in one-channel-mode only play simple "piano sounds" with no use of the x/y/z-expressions at all, just like this guy:
The more I think of this problem, the more the complexity grows:
If you play polyphonically in one-channel-mode, the same issue not only happens for the z-axis, it also happens for the x-axis (pitch-bend) and for the y-axis (CC-1 or CC-74). So there would be a lot more to do to adapt the LinnStrument for playing polyphonically in one-channel-mode without any glitches on the the x/y/z-expressions.
I assume that people who play polyphonically in one-channel-mode only play simple "piano sounds" with no use of the x/y/z-expressions at all, just like this guy:
- KVRAF
- 2721 posts since 8 Jun, 2010
- Roger Linn Design
Hi ryanpg,
One option to achieve your goal would be to set LinnStrument to send pressure as Poly Pressure, then use a DAW script or some MIDI scripting utility to:
1) read the incoming Poly Pressure messages,
2) in the case of 2 or more simultaneous touches, pass only the one with the highest value, and
3) send that value as a Channel Pressure message.
I realize that you don’t like to use computers so this solution wouldn’t be ideal for you, but at least it would achieve your goal without having to edit the source code.
One option to achieve your goal would be to set LinnStrument to send pressure as Poly Pressure, then use a DAW script or some MIDI scripting utility to:
1) read the incoming Poly Pressure messages,
2) in the case of 2 or more simultaneous touches, pass only the one with the highest value, and
3) send that value as a Channel Pressure message.
I realize that you don’t like to use computers so this solution wouldn’t be ideal for you, but at least it would achieve your goal without having to edit the source code.
-
- KVRist
- 109 posts since 29 Sep, 2014
This tiny device can do some MIDI scripting, maybe it can help:
https://midisolutions.com/prodevp.htm
https://midisolutions.com/prodevp.htm
-
- KVRist
- Topic Starter
- 32 posts since 8 Jan, 2023
Thanks, Roger, that's a great suggestion! But you're correct, my dream was/is to be able to leave the computer turned off while playing my synths. In my view, a big part of the genius of the Linnstrument is the (sorry it's the only word) luscious build quality of the instrument itself. Off-topic gratitude: Thank you for using wood and metal in the construction of Linnstrument! It's a joy just to hold it.
But yes, I just about abhor working with mouse and screen when making music. I love the tactile nature of buttons and knobs. The feel of the Linnstrument is also why I invested in it and not one of the many iPad touchscreen options out there.
I've actually considered coding my own hardware arduino Aftertouch midi filter to implement this behavior. As limited as I am as a coder I've actually adapted a few arduino CC to Sysex translator sketches to build midi powered "cables" to allow modern CC controllers to talk with my old sysex only synths!
@Ahornberg Yeah, I've deliberately ignored the fact that the Y data causes exactly the same problems with non-MPE/PolyAT devices. One issue at a time! Hah. I think you're absolutely right. Most Linnstrumentalists seem to tend strongly towards emulated string and piano sounds and/or are using MPE. I'm way more into atmospheric synth sounds and I've got a collection of older hardware that I would love to use.
For now I just have to not use aftertouch.
Last rant/reason to hopefully explain why I'm so energized around this, I was talking to a friend (who coincidentally is also well know in the instrument manufacturing world), about the difference between doing expressive sound design on a synthesizer (which is what I've done up to now), and using expressive instrument interfaces to facilitate expressive performances. The potential to escape the on/off binary of keyboards the Linnstrument offers is immense, which is another reason I now own one.
But yes, I just about abhor working with mouse and screen when making music. I love the tactile nature of buttons and knobs. The feel of the Linnstrument is also why I invested in it and not one of the many iPad touchscreen options out there.
I've actually considered coding my own hardware arduino Aftertouch midi filter to implement this behavior. As limited as I am as a coder I've actually adapted a few arduino CC to Sysex translator sketches to build midi powered "cables" to allow modern CC controllers to talk with my old sysex only synths!
@Ahornberg Yeah, I've deliberately ignored the fact that the Y data causes exactly the same problems with non-MPE/PolyAT devices. One issue at a time! Hah. I think you're absolutely right. Most Linnstrumentalists seem to tend strongly towards emulated string and piano sounds and/or are using MPE. I'm way more into atmospheric synth sounds and I've got a collection of older hardware that I would love to use.
For now I just have to not use aftertouch.
Last rant/reason to hopefully explain why I'm so energized around this, I was talking to a friend (who coincidentally is also well know in the instrument manufacturing world), about the difference between doing expressive sound design on a synthesizer (which is what I've done up to now), and using expressive instrument interfaces to facilitate expressive performances. The potential to escape the on/off binary of keyboards the Linnstrument offers is immense, which is another reason I now own one.
-
- KVRist
- Topic Starter
- 32 posts since 8 Jan, 2023
Geert and Roger handled vibrato in oneChannel mode in a very clever way, they average the X values to one global value. That's how I think y-axis could work too.Ahornberg wrote: Sun Jan 08, 2023 5:31 pm If you play polyphonically in one-channel-mode, the same issue not only happens for the z-axis, it also happens for the x-axis (pitch-bend) and for the y-axis (CC-1 or CC-74). So there would be a lot more to do to adapt the LinnStrument for playing polyphonically in one-channel-mode without any glitches on the the x/y/z-expressions.
From ls_handleTouches.io
// if X-axis movements are enabled and it's a candidate for
// X/Y expression based on the MIDI mode and the currently held down cells
// if there are several touches for the same MIDI channel (for instance in one channel mode)
// we average the X values to have only one global X value for those touches
If I understand correctly, that's how we get to wiggle chords and get tremolo in One Channel mode!
But as I said, one thing at a time! Z-axis is a different beast as it defaults to sending aftertouch and there's a long standing norm and expectation for how channel/mono aftertouch works.
-
- KVRist
- Topic Starter
- 32 posts since 8 Jan, 2023
My novice idea is to add one bit of logic at 1039 in ls_handleTouches.ino:
Check to see if the newest pressure value is greater than the prior one, and if so send pressure data.
[edited to remove silly code that doesn't build]
Keep in mind the above is not even pseudo code, it's the silly typing of a total novice. And my only goal is to help and in no way suggest I know better. Hah!
Check to see if the newest pressure value is greater than the prior one, and if so send pressure data.
[edited to remove silly code that doesn't build]
Keep in mind the above is not even pseudo code, it's the silly typing of a total novice. And my only goal is to help and in no way suggest I know better. Hah!
-
- KVRist
- Topic Starter
- 32 posts since 8 Jan, 2023
Sorry for the above waste of time, it didn't build of course. But this does. Not sure it'll work.
There's already logic to test if cell pressure is higher.
So I added that as a condition to sending pressure update. The following builds, but no idea if it'll do what I want.
I'm totally in over my head and need to stop using this forum as my scratchpad!
Thank you Roger and Ahornberg for indulging me.
I don't mind putting money (or gear) out there for help so maybe I'll set a "bounty" on this. If anyone is interested in guiding me or implementing, lemme know!
There's already logic to test if cell pressure is higher.
Code: Select all
boolean isReadyForSlideTransfer(byte col) {
return cell(col, sensorRow).pendingReleaseCount || // there's a pending release waiting
sensorCell->currentRawZ > cell(col, sensorRow).currentRawZ; // the cell pressure is higher
}
Code: Select all
// if sensing Z is enabled...
// send different pressure update depending on midiMode
if (Split[sensorSplit].sendZ && isZExpressiveCell() && isReadyForSlideTransfer(sensorSplit)) {
preSendLoudness(sensorSplit, valueZ, valueZHi, sensorCell->note, sensorCell->channel);
}Thank you Roger and Ahornberg for indulging me.
I don't mind putting money (or gear) out there for help so maybe I'll set a "bounty" on this. If anyone is interested in guiding me or implementing, lemme know!
-
- KVRist
- 109 posts since 29 Sep, 2014
If you want to solve the problem by coding, the first thing is to compile the actual firmware as it is and to transfer/install it on your LinnStrument.
After you got that working, it's time to apply your changes to the code, compile again, transfer/install it on your LinnStrument and see how it works.
Repeat this cycle until you are satisfied with your results.
The computer (in this case the Arduino inside your LinnStrument) is the only "person" who can tell you if your ideas are right or not.
Everything else is more or less a speculation about wrong or right, good or bad and so on.
The only real life person you might ask is Geert Bevin, because he wrote the code.
I am just a user of the LinnStrument with no deep unterstanding about what's going on inside the firmware.
After you got that working, it's time to apply your changes to the code, compile again, transfer/install it on your LinnStrument and see how it works.
Repeat this cycle until you are satisfied with your results.
The computer (in this case the Arduino inside your LinnStrument) is the only "person" who can tell you if your ideas are right or not.
Everything else is more or less a speculation about wrong or right, good or bad and so on.
The only real life person you might ask is Geert Bevin, because he wrote the code.
I am just a user of the LinnStrument with no deep unterstanding about what's going on inside the firmware.
