-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
base: master
Are you sure you want to change the base?
Conversation
I just realized the code is quite lacking in comments. I'll fix that. |
Alright, I added comments to the code and also removed the "detuneWithOctaves" function which I accidentally left in there. Should be ready now. |
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. |
🤖 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"} |
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... |
Alright, all merge conflicts and bugs have been removed. Feel free to test now. |
I just realized this effect sounds different when the sample rate is changed. Fixed it in the latest commit. 👍 |
@douglasdgi REMINDER. Did you see my reviews? |
@douglasdgi Is this ready for review? |
@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. |
@PhysSong I was wrong, turns out I did make it compatible with sample rate changes, just not in a nice or neat way... 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. |
There was a problem hiding this 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")) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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")), |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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;
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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]; |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
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. |
@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) |
Sorry about that; I had assumed you had meant all of your PRs. |
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". |
(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)