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

Add Disintegrator effect to LMMS #5161

Open
wants to merge 24 commits into
base: master
Choose a base branch
from

Conversation

LostRobotMusic
Copy link
Contributor

@LostRobotMusic LostRobotMusic commented Aug 30, 2019

(Made this whole thing in like 30 minutes, haha)

I'm not going to try to hide it, this effect is a blatant ripoff of Ableton's Erosion. You could probably even call it a clone. That was less because I intended to copy them and more because I couldn't think of anything else I'd want to add.

Disintegrator (and Erosion) is an effect that delays the sound with a modulated delay in super aggressive ways to get some very digital-sounding distortion. The first mode modulates the delay with white noise, which is filtered by the two filtering knobs before it does any modulation. The second mode is identical to the first, except the white noise is stereo rather than mono, which sounds much wider. The third mode uses a sine wave as the modulator, which sounds very similar to FM and can result in some very cool timbres.

Notice that the two filtering knobs are replaced with a frequency knob when the sine wave mode is selected.

This effect is quite basic and doesn't make any changes to other parts of LMMS, so I'm assuming the review-and-merge process will go by fairly quickly.

The effect is also 100% sample exact. I think. If I did that part right.

(And sorry for commit mess, Squash-And-Merge should prevent that from being a problem)

@LostRobotMusic LostRobotMusic added needs code review A functional code review is currently required for this PR needs style review A style review is currently required for this PR labels Aug 30, 2019
@LostRobotMusic
Copy link
Contributor Author

I just realized the code is quite lacking in comments. I'll fix that.

@LostRobotMusic
Copy link
Contributor Author

Alright, I added comments to the code and also removed the "detuneWithOctaves" function which I accidentally left in there. Should be ready now.

plugins/Disintegrator/Disintegrator.cpp Outdated Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.h Outdated Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.cpp Outdated Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.cpp Outdated Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.cpp Outdated Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.cpp Outdated Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.cpp Outdated Show resolved Hide resolved
plugins/Disintegrator/DisintegratorControls.cpp Outdated Show resolved Hide resolved
@LostRobotMusic
Copy link
Contributor Author

An absolute galaxy brain (known as Oncill) suggested that I add a new mode that modulates the delay time depending on the audio input. I tested it out. The result can work as an aggressive exciter, as well as something that (although is very violent and digital) is unnaturally good at enhancing the general timbre of any instrument you feed it. The filters are still enabled for this mode, which filter the input audio modulator (but not the "carrier", if that's even the correct term in this case). The new mode was added in the latest commit.

@PhysSong PhysSong added needs testing This pull request needs more testing and removed needs style review A style review is currently required for this PR labels Sep 15, 2019
plugins/CMakeLists.txt Outdated Show resolved Hide resolved
@LmmsBot
Copy link

LmmsBot commented Nov 24, 2019

🤖 Hey, I'm @LmmsBot from github.com/lmms/bot and I made downloads for this pull request, click me to make them magically appear! 🎩

Linux

Windows

🤖
{"platform_name_to_artifacts": {"Linux": [{"artifact": {"title": {"title": "(AppImage)", "platform_name": "Linux"}, "link": {"link": "https://11785-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.79%2Bgfb5471d-linux-x86_64.AppImage"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/11785?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}], "Windows": [{"artifact": {"title": {"title": "64-bit", "platform_name": "Windows"}, "link": {"link": "https://11788-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.79%2Bgfb5471d17-mingw-win64.exe"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/11788?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}, {"artifact": {"title": {"title": "32-bit", "platform_name": "Windows"}, "link": {"link": "https://11787-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.79%2Bgfb5471d17-mingw-win32.exe"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/11787?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}]}, "commit_sha": "88ea50dd3e2812efd1d71dc1158de5691eb0a098"}

@LostRobotMusic
Copy link
Contributor Author

Don't test this out yet, I found some weird bug with the self modulation mode that isn't appearing in my copy for some reason...

@LostRobotMusic
Copy link
Contributor Author

Alright, all merge conflicts and bugs have been removed. Feel free to test now.
Here's a video of me messing around with this effect: https://youtu.be/nzUV3gDL4Wo

@PhysSong PhysSong self-requested a review April 19, 2020 02:42
@LostRobotMusic
Copy link
Contributor Author

I just realized this effect sounds different when the sample rate is changed. Fixed it in the latest commit. 👍

plugins/Disintegrator/Disintegrator.cpp Outdated Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.cpp Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.cpp Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.cpp Show resolved Hide resolved
plugins/Disintegrator/Disintegrator.cpp Outdated Show resolved Hide resolved
@PhysSong
Copy link
Member

PhysSong commented Jun 8, 2020

@douglasdgi REMINDER. Did you see my reviews?

@PhysSong
Copy link
Member

@douglasdgi Is this ready for review?

@LostRobotMusic
Copy link
Contributor Author

@PhysSong I was planning on rewriting this, it's incompatible with sample rate changes and isn't written very well in general. It shouldn't take more than a few days to rewrite (maybe even just one day, it's a fairly simple plugin), I'll get to that as soon as I'm done with the Phaser changes I've been working on.

@LostRobotMusic
Copy link
Contributor Author

LostRobotMusic commented Dec 27, 2020

@PhysSong I was wrong, turns out I did make it compatible with sample rate changes, just not in a nice or neat way...
Anyway, the whole code was kind of a mess and it turns out it was super buggy as well. The last commit fixes everything. The filters should actually work correctly now, and the Self Modulation mode should sound significantly cleaner.

Also, the Amount knob is now in units of milliseconds like it should have been, rather than samples like it was before. Should be ready for review now.

Copy link
Contributor

@curlymorphic curlymorphic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nice plugin, seam to get a lot for your money as they say. It is really simple and effective. I have left some comments in the code, I feel these are minor amendments, leading to a substantial improvement.

My other concern is the name "Disintegrator", Lmms already comes bundled with a LADSPA effect of the same name. Maybe now would be a good time to reconsider the name, as a name change would not be viable once release.

I have kept my review to the audio processing code, I have not reviewed any UI components, or comment on style.

m_highCutModel(20000.0f, 20.0f, 20000.0f, 0.01f, this, tr("High Cut Frequency")),
m_amountModel(1.6f, 0.0f, 10.0f, 0.001f, this, tr("Amount")),
m_typeModel(this, tr("Type")),
m_freqModel(100.0f, 1.0f, 21050.0f, 0.01f, this, tr("Frequency"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where have these range values originated from? The lower end of 100Hz seems reasonable if that suits you desired effect, the upper limit seems a strange value, I can see this is not limiting to the audio spectrum or any common fs/2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100 is the default value, not the lowest value. The lowest value is 1. The highest value... I think that's a typo. Pretty sure I meant 22050.

m_effect(effect),
m_lowCutModel(20.0f, 20.0f, 20000.0f, 0.01f, this, tr("Low Cut Frequency")),
m_highCutModel(20000.0f, 20.0f, 20000.0f, 0.01f, this, tr("High Cut Frequency")),
m_amountModel(1.6f, 0.0f, 10.0f, 0.001f, this, tr("Amount")),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depth may be a more suitable name for this control.


void sampleRateChanged();

inline float realfmod(float k, float n);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason this function is declared inline?

{
m_sampleRate = Engine::mixer()->processingSampleRate();
m_2PiOverSR = F_2PI / m_sampleRate;
m_lp = new BasicFilters<2>(Engine::mixer()->processingSampleRate());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The necessity for the creation of a new filter whenever the sample rate changes is an unfortunate historical requirement. This pull request creates new filters but does not yet handle the disposal of any existing filters, thus causing a memory leak.

I am suggesting using std::unique pointers to solve this. lmms has a handy function, that did not make it into the c++ standard until c++14 make_unique. if you update the two lines of code to :

	m_lp = make_unique<BasicFilters<2>>(Engine::mixer()->processingSampleRate());
	m_hp = make_unique<BasicFilters<2>>(Engine::mixer()->processingSampleRate());

and include stdshims.h

The declaration in the header would need to be amended to

	std::unique_ptr<BasicFilters<2>>  m_lp;
	std::unique_ptr<BasicFilters<2>>  m_hp;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We recently switched to C++14, FYI.


float m_sineLoc = 0;

BasicFilters<2> * m_lp;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please see comments in cpp file, these could be unique pointers

	std::unique_ptr<BasicFilters<2>>  m_lp;
	std::unique_ptr<BasicFilters<2>>  m_hp;

m_lp = new BasicFilters<2>(Engine::mixer()->processingSampleRate());
m_hp = new BasicFilters<2>(Engine::mixer()->processingSampleRate());
m_lp->setFilterType(0);
m_hp->setFilterType(1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be an improvement if the filter types were selectable, like in the Dual Filter effect, this would then lead to the addition of resonance and possibly gain controls, and may extend the pallet of sounds?

If the filter types are to remain constant then the use of the constant types 0 and 1 should be changed to BasicFilters::FilterTypes::lowpass and the respectave hi pass

}
else// For when the interpolation wraps around to the beginning of the buffer
{
s[i] = m_inBuf[i][m_bufferSize - 1] * (1 - newInBufLocFrac[i]) + m_inBuf[i][0] * newInBufLocFrac[i];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above comment

float newInBufLoc[2] = {0, 0};
float newInBufLocFrac[2] = {0, 0};

// Generate white noise or sine wave, apply filters, subtract the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be preferable to just call it noise, not White Noise. White Noise has defined mathematical properties, that fast_rand() does not provide.


sample_t s[2] = {buf[f][0], buf[f][1]};

// Increment buffer read point
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when implementing a circular buffer, it is common to have the buffer size a power of 2, with 512 being the next closest to the 500 you stare in the header.

The index increment and wrap at end of buffer can then be reduced to:

++m_inBufLoc;
m_inBufLoc &= (m_bufferSize - 1)

This is preferable as conditional branches can be processor expensive, and may also hinder some compiler side optimisations.

}
if(m_needsUpdate || m_disintegratorControls.m_lowCutModel.isValueChanged())
{
m_hp->calcFilterCoeffs(m_disintegratorControls.m_lowCutModel.value(), 0.5);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The updating of the filter coefficients should be done per frame using the value buffer, not once per buffer.

The current implementation is block size dependant, so the audio will be different depending on the block size. This is not desirable, and the effect should remain independent.

One of the drives for sample exactness was to remove the buzzing and zipping noises, these are caused by sudden stepped changes in parameters on a per-block basis, and are removed by smoothly updating the parameters on a per-frame basis.

@rdrpenguin04
Copy link
Contributor

Douglas is offline for an indeterminate amount of time. He has, in the past, requested his unfinished PRs to be closed pending his ability to work on them more. I will now forward that request again, since he won't be here to close the PR for potentially a very long time.

@LostRobotMusic
Copy link
Contributor Author

LostRobotMusic commented Jan 15, 2021

@rdrpenguin04 I definitely did not request that... I did request something similar for Microwave, but for everything else I'd much rather keep them open to give others the chance to finish them if they're able to.

(And I'm back for the time being by the way, I should be able to finish this one up)

@rdrpenguin04
Copy link
Contributor

@rdrpenguin04 I don't actually recall requesting that... I did request something similar for Microwave, but for everything else I'd much rather keep them open to give others the chance to finish them if they're able to.

(And I'm back for the time being by the way, I should be able to finish this one up)

Sorry about that; I had assumed you had meant all of your PRs.

@LostRobotMusic LostRobotMusic added the rework required Pull requests which must be reworked to make it able to merge or review label Jan 2, 2024
@tresf
Copy link
Member

tresf commented Jan 28, 2025

My other concern is the name "Disintegrator", Lmms already comes bundled with a LADSPA effect of the same name. Maybe now would be a good time to reconsider the name, as a name change would not be viable once release.

Yes, the CMT plulgins ship one under the same name and this is a good observation but I think the same argument can be made for names like "Reverb", "Eq" and "Compressor", so duplicate names are OK.

I asked AI for some better names given Lost's description and none of them were as good as "Erosion" and "Disintegrator".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs code review A functional code review is currently required for this PR needs testing This pull request needs more testing rework required Pull requests which must be reworked to make it able to merge or review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants