Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

corrected wet/dry knob range #3422

Closed
wants to merge 1 commit into from
Closed

Conversation

PaulBatchelor
Copy link
Contributor

@PaulBatchelor PaulBatchelor commented Mar 13, 2017

Fixes #3261.

After examining git commit history, I found a bug introduced nearly 10 years ago! While making some sweeping changes in the LMMS codebase, someone accidentally changed the range of the knob, which has given us the strange behavior we see today. In the git diff I linked to above, you can see the correct ranges being overridden with the incorrect ranges with no explanation.

@grejppi
Copy link
Contributor

grejppi commented Mar 13, 2017

This also breaks projects that rely on this behaviour.

@PaulBatchelor
Copy link
Contributor Author

PaulBatchelor commented Mar 13, 2017

@grejppi Yes, this will make breaking changes, but it has to be done. Right now, this knob is adding unintentional non-linear phase and gain staging to the mixer. Chances are the people using this behavior don't know why it is behaving that way (and they shouldn't, because it's a bug). I cannot stress how bad this is.

@ivhacks
Copy link
Contributor

ivhacks commented Mar 13, 2017

I would like to say that I often use this feature. It is easier than finding the right W/D mix and then adding an Amplifier to just turn the knob under 1. Also, I am one of the more experienced LMMS producers and I have no clue what "unintentional non-linear phase and gain staging" means. Please explain in laymans' terms.

@grejppi
Copy link
Contributor

grejppi commented Mar 13, 2017

I don't think it has to be done. This thing (be it a feature or a bug) has been there for 10 years, and people use it because can sound good with certain effects. I cannot see how this is bad.

@PaulBatchelor
Copy link
Contributor Author

PaulBatchelor commented Mar 13, 2017

@Jousboxx of course! It's not as scary as it sounds.

Basically, to handle wet/dry signal mixing, LMMS gives plugin developers two separate values: a wet value and a dry value. In an ideal world, these values would be between 0-1, and when summed together they equal 1.

To get the output of your signal with the right wet/dry mix, you'd use the following equation:

signal_output = wet_signal * wet_amount + dry_signal * dry_amount

When wet_amount is 0, dry_amount has to be 1, and you get all dry signal. When wet_amount is 1, dry_amount has to be 0, and you get all wet signal. When wet_amount is 0.5, dry_amount is also 0.5, and you get a perfect blend. In LMMS, you have one wet/dry knob, so how do you calculate the the values? LMMS does something like this:

dry_amount = wetdry_knob_value;
wet_amount = 1 - dry_amount;

That is to say, when wet/dry knob is all the way up, it's a dry signal. All the way down, it's an all wet signal. You can flip this the other way around, but ultimately is the same behavior. But this all depends on the knob range being in the range 0 to 1. But it's not.

The main issue isn't really that the wet/dry knob is in the wrong range. Plugin developers could take that value directly and scale it to fit their needs. However, the fact that LMMS is providing separate wet/dry variables for developers creates an issue. Why? Because the wet/dry values are uneven. The Dry value has the range 0 to 2, and the wet value has a range -1 to 1. This means that when the knob is all the way dry, you actually double the signal because you multiply it by two, and when the knob is set to be all wet, this multiplies the signal by -1. What this does is flip the phase. You may recall from a physics class that when you sum two sine waves whose phases are flipped, you cancel out that sine wave. If you are unknowingly flipping the phase of your signal, you are going to have a bad time mixing your track. Typically, this sort of thing happens when you have antinodes and nodes in the room you are mixing, but in LMMS, we apparently emulate this feature ;)

The issue becomes more complex because depending on where the knob is, you are changing the amount of gain and phase modification you are adding. It doesn't behave the way you expect it to because of the different wet/dry values. I would define this behavior non-linear behavior.

@PaulBatchelor
Copy link
Contributor Author

@grejppi

I don't think it has to be done.

See my comment above. I would agree that this knob has some funkiness to it, but it does not exhibit behavior of a wet/dry knob. The solution is to either make it behave like a wet/dry knob in my one line fix, or change the name of this knob.

This thing (be it a feature or a bug) has been there for 10 years, and people use it because can sound good with certain effects.

Some quirky bugs are worth holding onto. This is not one of those bugs. Just because it hasn't been noticed in ten years doesn't make it any less wrong.

I cannot see how this is bad.

Why is it bad? Because this knob doesn't even behave like a wet/dry knob in any way right now. Even when you don't touch it, it's screwing up the mix of your track. LMMS should have a fighting chance to sound as professional as it looks.

@tresf
Copy link
Member

tresf commented Mar 14, 2017

If this becomes a huge backwards compatiblity problem, we split the baby and deprecate it. This can be done by using a visual warning mechanism when using range 0 ... -1 with a clear explanation that the feature will be removed in version x.x.

Note, I used to use a bug in Kicker to make drops and when Vesa fixed it, I kept my mouth shut, knowing it was a bug.

The problem with this bug is it wasn't clearly obvious, so let's deprecate it to be progressive while also being respectful to the musicians.

@softrabbit
Copy link
Member

dry_amount = wetdry_knob_value;
wet_amount = 1 - dry_amount;

It's actually the opposite. The knob value is the wet value, and the dry value is calculated like that.

The Dry value has the range 0 to 2, and the wet value has a range -1 to 1. This means that when the knob is all the way dry, you actually double the signal because you multiply it by two

No, you don't. When the knob is all dry you get dry = 1.0 - 0.0. It's when the wet value is -1.0 that you get dry = 1.0 - (-1.0). Another option for a sane behavior would be taking the absolute value of the wet value before subtraction, which would make the dry value go from 0...1...0 while the wet goes -1...0...1.

Even when you don't touch it, it's screwing up the mix of your track.

Isn't that the point of effects, to screw with the sound in different ways?

@PaulBatchelor
Copy link
Contributor Author

It's actually the opposite. The knob value is the wet value, and the dry value is calculated like that.
Okay. I stand corrected.

No, you don't. When the knob is all dry you get dry = 1.0 - 0.0

Put some printfs in the effect loop, you'll clearly see the ranges are as I stated above.

Another option for a sane behavior would be taking the absolute value of the wet value before subtraction, which would make the dry value go from 0...1...0 while the wet goes -1...0...1.

Sane behavior? Are you kidding me? Why make a function call to fabs for such a simple operation.

Isn't that the point of effects, to screw with the sound in different ways? .

This isn't an effect, though. This just adds more complexity to what really should be simple arithmetic.

@PaulBatchelor
Copy link
Contributor Author

To be even clearer:

  1. Add this line after these two variables are declared in Amplifier.cpp:

printf("dry: %g, wet: %g\n", d, w);

Or use std::cout, if you'd like.

  1. Build LMMS, and run the build from the terminal and start a new project.

  2. Put the amplifier plugin on the master track (or wherever the signal is).

  3. Hit play to see the terminal print stuff out on the terminal.

  4. When turned all the way to the right, I get "dry: 0, wet: 1". When turned all the way to left, I get "dry: 2, wet: -1"

  5. You can see that the DSP code for Amplifier assumes the values are in the range 0-1. But they ain't for me at least.

@softrabbit
Copy link
Member

When turned all the way to the right, I get "dry: 0, wet: 1". When turned all the way to left, I get "dry: 2, wet: -1"

Oh... I've been calling the middle position dry all this time, as it's the place where wet goes to 0.

Why make a function call to fabs for such a simple operation.

The operation can be as simple as one CPU instruction. so I wouldn't worry that much about complexity.

@PaulBatchelor
Copy link
Contributor Author

Okay. It behaves like a normal wet/dry knob... if you use half of the knob. I was wrong in that it isn't changing the gain staging when it's all dry, so things are fine when you don't touch it. Yet another very strange bug-turned-quirk in the LMMS audio engine. sigh.

@jasp00
Copy link
Member

jasp00 commented Mar 18, 2017

Wet/dry formula is correct. We just abuse the formula to achieve some effects; I do not remember whether this was intentional.

  • Is the knob operation intuitive? Should it still work that way? GUI team decides.
  • Is backwards compatibility impossible? No.
  • Can the current behavior be expressed by other means? I think so.

@Animtim
Copy link

Animtim commented Mar 21, 2017

Just a comment about the design of this choice:
-As I'm evaluating the possibilities to play live with lmms, the idea of having the dry/wet go only from 0 to 1 would be sooo much more convenient, to map them to controllers and play with them intuitively, without risking to go on the dangerous zone below 0.
-As for backward compatibility, it shouldn't be too hard to add a "legacy range on wet/dry FX" option in the main settings (not activated by default of course) to make potentially everyone happy.

@tresf
Copy link
Member

tresf commented Mar 21, 2017

I had the liberty of discussing this will @PaulBatchelor last night. For historical reasons, the design should include the backwards-compat option with a deprecation warning. The place for this should be on each effect to ensure new effects are created without this toggled on by default. The toggle would then be completely removed for the next major release (e.g. 1.3 or 2.0 whatever we call it).

We will do our best to detect controllers and project setting which would toggle this on by examining the range used. This should be possible through an upgrade routine.

After the next major release, those in strong opposition of the toggle removal can build from source with the option turned back on.

It's very difficult to quietly revert a 10-year mistake but we must progress forward. I think this offers a compromise between backwards compatibility and future efforts.

Here's a mockup of how we may present this change to the users.

image

@Animtim
Copy link

Animtim commented Mar 21, 2017

This looks like a good plan to move forward.

@jasp00
Copy link
Member

jasp00 commented Mar 22, 2017

It's very difficult to quietly revert a 10-year mistake

Why do you call it a mistake? There are users that were well aware of this behavior. You can perfectly change the knob to [0, 1] without dropping the feature.

@tresf
Copy link
Member

tresf commented Mar 22, 2017

Why do you call it a mistake?

While making some sweeping changes in the LMMS codebase, someone accidentally changed the range of the knob

I call it a mistake because Paul was updating the display names with this update, specifically adding translation support as well as moving a few coordinates.

@Spekular
Copy link
Member

What's the advantage of a legacy range toggle over a 0-1 range with an "invert effect" toggle? I feel like the latter would be better.

@tresf
Copy link
Member

tresf commented Mar 22, 2017

What's the advantage of a legacy range toggle over a 0-1 range with an "invert effect" toggle? I feel like the latter would be better.

I'll quote @PaulBatchelor:

The Dry value has the range 0 to 2, and the wet value has a range -1 to 1. This means that when the knob is all the way dry, you actually double the signal because you multiply it by two, and when the knob is set to be all wet, this multiplies the signal by -1. What this does is flip the phase.

So it's not really an "invert effect" setting. It's more like a "send me junk" setting. 😆

@jasp00
Copy link
Member

jasp00 commented Mar 23, 2017

I call it a mistake because Paul was updating the display names with this update

It is true that the ChangeLog does not mention this, but the mistake certainly turned into feature. Let us call it a "mistake".

What's the advantage of a legacy range toggle over a 0-1 range with an "invert effect" toggle?

As @tresf reminds us, these are different effects. Current behavior is sort of a chaotic sound effect. The "mistake" should be available in the context menu and enhanced by increasing ranges.

@Umcaruje
Copy link
Member

I think this is something that we want adressed for 1.3, so I'm keeping this PR related to master

@grejppi grejppi mentioned this pull request Mar 28, 2017
@Umcaruje Umcaruje added this to the 1.3.0 milestone May 14, 2017
@gi0e5b06
Copy link

gi0e5b06 commented Sep 7, 2017

Still not merged after 6 months...

@ivhacks
Copy link
Contributor

ivhacks commented Sep 7, 2017

@PaulBatchelor I just read your explanation of the problem. I'm not sure why I wasn't notified when you tagged me, or maybe I just missed the email.

I understand what you're saying, but I have not observed that behavior. I use the wet/dry function often for mixing (including setting the knob to negative values) and I am pretty certain I would have noticed if it increased the gain and/or flipped the phase of my sound. Just to be sure, I set up a simple MMPZ that has a sine wave going through an amplifier effect that does nothing (it's set at 100% volume). If what you were saying was a problem, I would expect the following behavior:
At 100% dry/wet, the sine wave would be twice its original volume.
At 0%, it would be exactly the same as the original.
At -50% no sound whatsoever would be heard due to the original signal being canceled out by a phase inverted copy.
And at -100% The volume would be equal to the original, but the wave would be phase inverted.

However, it sounds the same regardless of where I put the wet/dry knob. This is what I expect as it is working properly and the effect produces no change to the signal.

You probably encountered a bug that occurs based on some other thing going on in LMMS, not just in general in all situations.

Here is a link to the MMPZ so you can see what I did and test it for yourself: https://drive.google.com/file/d/0B8dZ3IVOKKA6TzlZMFNfSDg2Nk0/view?usp=sharing

@ivhacks
Copy link
Contributor

ivhacks commented Sep 7, 2017

After thinking about it some more, I realize that the hypothetical behavior I listed is not entirely correct. But the actual behavior seems to be bug-free, and not anything like what you explained in your comment.

@tresf
Copy link
Member

tresf commented Sep 7, 2017

After thinking about it some more, I realize that the hypothetical behavior I listed is not entirely correct. But the actual behavior seems to be bug-free, and not anything like what you explained in your comment.

Right. As I read it, this PR is about how the code should be, not how it's necessarily malfunctioning.

Still not merged after 6 months...

@gi0e5b06 can you please be more insightful with this comment? I think backwards compatibility concerns here are valid and the PR should be regression tested. Unless someone's volunteering to do that, the PR is stuck. This is unfortunate but not uncommon. We do need more help with these types of things and the OP is on semi-permanent leave leaving the responsibility of the merge to those that didn't write it. If you're comfortable with owning this, let's discuss on Discord about it in #devtalk.

@PaulBatchelor
Copy link
Contributor Author

PaulBatchelor commented Sep 7, 2017 via email

@gi0e5b06
Copy link

gi0e5b06 commented Sep 9, 2017

@PaulBatchelor Yes.

@tresf There is no backward compatibility issues here. Merge it into master but not into stable-1.2.
Projects always sound different between versions so they need to be adjusted anyway. Showing the checkbox to activate the old behavior is fine for projects created with LMMS 1.2 or before.

@grejppi
Copy link
Contributor

grejppi commented Sep 9, 2017

LMMS is full of quirks, and this is just one of them. In the interest of preserving even some backwards compatibility am very much against changing this behavior in a minor release.

That said, I would find a 0..1 range more ideal as well, but that is better left for a major breaking release like 2.0 sometime far in the future.

@gi0e5b06
Copy link

gi0e5b06 commented Sep 9, 2017

@grejppi OK. So in 2042, this bug may be fixed. Great...

I was suggesting to merge it into master (1.3), which is planned for 2021 at the earliest (that itself is already a joke) but waiting a few decades seems a safer way to go...

@tresf
Copy link
Member

tresf commented Sep 9, 2017

@gi0e5b06, insulting the project and its maintainers won't be tolerated. Consider this your warning.

@gi0e5b06
Copy link

There was no insult in what I wrote. The history of this project shows that there are on average three years between two minor releases. Back to the topic: every one seems to agree this bug should be fixed. Simple question: when will that happen?

@grejppi
Copy link
Contributor

grejppi commented Sep 10, 2017

Only two people call it a bug though 😌

@tresf
Copy link
Member

tresf commented Sep 10, 2017

Simple question: when will that happen?

This is pushing and off topic. Contributors can't spend their time poking at a clearly back-logged project about how long a bug is going to be open. Crowdsourced projects don't survive on finger pointing or insulting the shortcomings of the admins.

This is a direct insult to the admins that wake up and work on the project and the lack of sympathy in the responses following the warning are a sign that the agenda is not to test, code or debug.

The next comment that's regressive will be removed. Further regressive comments will be reported and dealt the with through the hosting service.

@tresf
Copy link
Member

tresf commented Sep 10, 2017

To get this merged, "it can go to master" is simply the wrong answer. We should weigh the impact of what changing a model's default value has on backwards compatibility and what our options are to mitigate more issues caused by it. This is mentioned in the comments above.

@lukas-w lukas-w mentioned this pull request Nov 2, 2017
@tresf
Copy link
Member

tresf commented Dec 24, 2017

To move this PR forward, we need to rename the attribute or add a new range attribute. Proposal:

e.g.

- m_wetDryModel.loadSettings( _this, "wet" );
+ m_wetDryModel.loadSettings( _this, "wetdry" );

But we need to be able to fall-back onto the old wet value. This is tricky because we generally handle upgrades inside DataFile.cpp, but this one cannot live there without messing with the Effect constructor, which seems like bad design... i.e. A permanent design change to a temporary compat issue feels wrong. Anyway...

m_useDeprecatedWetDry = false;  // true = use old "wet" range (-1, +1)
m_wetDryModel.loadSettings( _this, "wetdry" ); // since 1.3.0

// "wetdry" was previously "wet", but had invalid values for many, many years
// Let's preserve them for projects which may still require them
list = elementsByTagName( "effect" );
for( int i = 0; !list.item( i ).isNull(); ++i )
{
	QDomElement el = list.item( i ).toElement();
	// TODO: Can we just ask the FloatModel if it was null/non-null
	// That would avoid redundant DOM parsing
	if( el.attribute( "wet" ) != null ) {
		delete m_wetDryModel;
		m_wetDryModel = new FloatModel( 1.0f, -1.0f, 1.0f, 0.01f, this, tr( "Wet/Dry mix" ) );
		m_wetDryModel.loadSettings( _this, "wet" );
		m_useDeprecatedWetDry = true;
	}
}

And then on save...

if (useDeprecatedWetDry) {
	m_wetDryModel.saveSettings( _doc, _this, "wet" );
} else {
	m_wetDryModel.saveSettings( _doc, _this, "wetdry" );
}

It's a bit gross, but it would respect the old behavior while deprecating it and forcing the new; living happily together. For those wanting the old knob range, you'd have to edit new projects by hand.

@zonkmachine
Copy link
Member

FYI! I think this is probably what they tried to implement although the response is wrong as described here.

Polarizing mixer (attenuverter).
http://www.doepfer.de/a138c.htm

@JohannesLorenz
Copy link
Contributor

The whole discussion is redundant to #3261 . I'm closing this, as this has been rejected anyways (the majority was in favor of compatibility).

@tresf We should keep discussing your proposal in #3261 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.