Skip to content

Implemented a new Compressor effect#56

Open
ketsebaoteth wants to merge 1 commit into
neXyon:masterfrom
ketsebaoteth:master
Open

Implemented a new Compressor effect#56
ketsebaoteth wants to merge 1 commit into
neXyon:masterfrom
ketsebaoteth:master

Conversation

@ketsebaoteth
Copy link
Copy Markdown

@ketsebaoteth ketsebaoteth commented Aug 25, 2025

Hello there nexyon !

This PR adds a new, from-scratch audio compressor.

Core Features:

  • RMS Detection: Measures average signal power for a smoother, more musical response
  • Soft Knee: Gradually introduces compression around the threshold for a less aggressive and more transparent effect.
  • Lookahead: Delays the audio path, allowing the detector to anticipate and control transients without artifacts.

Waveform Export From Blender Comparison in FLStudio

exported from blender a new compressor modifier.
image

the one on the top shows the compressed export from blenders VSE in which you can see places where it was higher being tamed down and the lower ones get increased a bit.

Another Waveform more obvious preview

image

Bottom one is compressed on this one

Note: I'm still new to audio programming, so I'm very open to feedback if anything about the results looks wrong or could be improved. 😊

@ketsebaoteth ketsebaoteth changed the title Implemented a new Compressor effect WIP: Implemented a new Compressor effect Aug 26, 2025
Copy link
Copy Markdown
Owner

@neXyon neXyon left a comment

Choose a reason for hiding this comment

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

Hi! I had a first rough look at the code. From a pure coding stand point it looks good, you know your C++! From the audio side: I assume you got the math and everything from some source, do you mind citing it, potentially as comments in the code?

Generally, I saw a few points to be addressed:

  • License/Copyright headers (just copy from other files and update with your name and this year).
  • Format with clang format please.
  • CMakeLists.txt changes are missing.
  • Units should be the same as in the other classes for consistency: seconds instead of milliseconds and possibly also gains not in dB but just as ratio (i.e. 0 dB = 1), though for the latter I think dB are fine too if it simplifies the math inside the methods.
  • It would be awesome if you could add C and Python API for this effect.

Comment thread src/fx/CompressorReader.cpp Outdated
@ketsebaoteth ketsebaoteth marked this pull request as ready for review August 27, 2025 08:35
@ketsebaoteth ketsebaoteth changed the title WIP: Implemented a new Compressor effect Implemented a new Compressor effect Aug 27, 2025
@ketsebaoteth
Copy link
Copy Markdown
Author

ketsebaoteth commented Aug 27, 2025

From the audio side: I assume you got the math and everything from some source, do you mind citing it, potentially as comments in the code?

the math came from multiple places , some sources where easier to understand about a certain concept than others for me, and i have added as many as i can as comments 😊👍

@ketsebaoteth
Copy link
Copy Markdown
Author

ketsebaoteth commented Aug 28, 2025

@neXyon

I’ve ran into a small but important issue with how the modifiers recreator handles audio effects like AUD_Sound_Compress and AUD_Sound_Equalize. Right now, every time a value changes when you call the API's AUD_Sound_Compress or equalize the API creates a new AUD_Sound instance that wraps the effect. and returns a referance to that This means that while dragging a knob, it is rapidly destroying and recreating effect instances, which causes glitchy, unstable audio output.

The current workaround in sound_equalizer is to defer updates until the drag is released. But that’s not ideal — in audio workflows, real-time feedback is crucial. People expect to hear the effect evolve as they tweak parameters, not just after they let go.

if you tweak values in the equalizer as well here is how it sounds like:

2025-08-28.10-02-07.mp4

i am not a 100% sure but i think this is the cause of the zipper glitch problem, and i dont know if its a 100% deal breaker from a usage standpoint.

@neXyon
Copy link
Copy Markdown
Owner

neXyon commented Aug 30, 2025

I’ve ran into a small but important issue with how the modifiers recreator handles audio effects like AUD_Sound_Compress and AUD_Sound_Equalize. Right now, every time a value changes when you call the API's AUD_Sound_Compress or equalize the API creates a new AUD_Sound instance that wraps the effect. and returns a referance to that This means that while dragging a knob, it is rapidly destroying and recreating effect instances, which causes glitchy, unstable audio output.

This has to do with the fact that Audaspace was not designed with this kind of real-time audio editing in mind. Quite contrary, it was designed to build a full signal graph and then let it play. The reason for this is, how sequencing and the animation system in Blender works. You can put a whole scene into another scene, even multiple times and you can play back multiple scenes at the same time. So if you look at a scene as one signal graph, you can have that same graph play multiple times at the same time but with different time offsets. That lead to the aud::ISound and aud::IReader architecture, where the Sound is the blueprint for the signal graph and the reader is the instantiation of it that actually plays back. Animation is done through an animation cache (aud::AnimateableProperty). If you would have to update values from the outside during playback, you would have to be able to access the instantiations (Readers) separately which means that the whole signal graph needs to be duplicated in Blender as well every time playback of a scene starts in one way.

With that background information in mind, I think it's still possible to easily create something interactive with audaspace. Keep in mind though that such an interactive architecture will run into the issues I mentioned in the paragraph above. The idea is simple: you can use a separate object (like aud::AnimateableProperty) as an std::shared_ptr which is handed to the ISound and IReader classes and can be updated during playback. Of course it's important to make access to that separate object thread safe if necessary (either within the object itself, or with locking the playback device while you change something). This can be used to either update parameters of sounds (like the compressor parameters, or EQ parameters) or it can also be used for getting data from audaspace during playback (like the metering you are implementing). If you want an example of this, the AnimatedTimeStretchPitchScale that has recently been added does exactly that with an AnimateableProperty.

Quite a bit of rambling. I hope this make sense. Let me know if something is unclear or you have questions.

Copy link
Copy Markdown
Owner

@neXyon neXyon left a comment

Choose a reason for hiding this comment

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

Thanks for the updates! I think if you change all other dB parameters to ratios, you should have the knee as ratio as well. Some of the documentation and parameter names still mention the old units, please update those.

I tried it briefly and got some noise before the playback actually started, there might be a bug with the lookahead?

It would also be nice to document sensible value ranges for the parameters! Which values are you testing with usually?

Do you want to change the API to work with a shared object for the parameters?

Comment thread bindings/python/PySound.cpp Outdated
Comment on lines +935 to +937
parent->sound = new std::shared_ptr<ISound>(
AUD_Sound_compressor(
reinterpret_cast<AUD_Sound*>(self),
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This doesn't work/compile. It uses the C API, though it should use the C++ API and you should include Compressor.h. You can see how the other methods are doing it.

@ketsebaoteth
Copy link
Copy Markdown
Author

ketsebaoteth commented Aug 30, 2025

Thanks a lot for the feedback and for walking me through the animatable properties—really helpful. I’ll make sure to correct the units during the final cleanup phase; it’s on my radar, no worries.
Lately, I’ve been more focused on resolving the issue I mentioned earlier, since it’s been a major blocker and almost renders things unusable.
Regarding the main problem:
I’ve noticed the initial noise too, and I’ll definitely be addressing that.
As for the API change—I think, it’s a must. I might need a bit of time to fully understand what you explained 😅, but I think I can cook up a something. Recreating effects on every parameter change isn’t ideal, so i think its a must

@AGoldenDragon
Copy link
Copy Markdown
Contributor

Hey, anything new? I'd really like to add this as a modifier to the base Blender repo when ready 😁

@aras-p
Copy link
Copy Markdown
Contributor

aras-p commented Dec 1, 2025

Yeah it would be really good to know how to move forward with this. If @ketsebaoteth can't finish this up for whatever reason, could someone else "take over" the PR?

@ketsebaoteth
Copy link
Copy Markdown
Author

Hey, sorry for leaving this hanging. I’m a uni student and classes got pretty busy, so I had to step away for a bit. Things have calmed down now and I’d like to pick this back up.

@ketsebaoteth
Copy link
Copy Markdown
Author

UPDATE

image image

In the second screenshot, the compressor misses the very first part of the song.
This happens because the compressor is not fast enough to detect the initial transient.

By enabling lookahead, this issue is resolved.
You can see the corrected results in the last screenshot below:

image

@ketsebaoteth ketsebaoteth reopened this Dec 3, 2025
@ketsebaoteth ketsebaoteth requested a review from neXyon December 3, 2025 06:36
Copy link
Copy Markdown
Owner

@neXyon neXyon left a comment

Choose a reason for hiding this comment

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

Thanks for the update! It's very nice to have a python API to test this.

Unfortunately, since I'm not really a DAW user, I hardly know what would be good values to test the effect with. Could you suggest some?

When I tried it with the python API, I still got some noise when starting playback, even with this new version. When I set the lookahead much higher, I got no noise, but significant delay. I think it would be nice if the lookahead parameter was not necessary and the effect would automatically do it with the correct length. Would that be possible?

Some points I mentioned previously that haven't been fully addressed:

  • Format with clang format please. (CompressorReader.cpp especially)
  • Units in dB are mostly ratios, but the knee is still in dB and the python API uses dB too. For consistency and because Python and C bindings use the same documentation, please make everything into ratios! Maybe some computation in the effect can also be changed so that you don't need to keep switching between ratios and dB? I see that at least at the end smoothedGainReduction is turning env back from dB to a ratio.

Comment thread bindings/C/AUD_Sound.cpp
assert(sound);
try
{
return new AUD_Sound(new Compressor(*sound, threshold, ratio, attack, release, makeupGain, kneeWidth, lookahead));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Compressor.h is not included so this gives an error.

Comment thread bindings/C/AUD_Sound.h
Comment on lines +411 to +416
* \param threshold The threshold in dB.
* \param ratio The compression ratio.
* \param attack The attack time in seconds.
* \param release The release time in seconds.
* \param makeupGain The makeup gain in dB.
* \param kneeWidth The knee width in dB.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Docs here still say dB, should be a ratio now?

@AGoldenDragon
Copy link
Copy Markdown
Contributor

Hey, sorry to bother you again, but are there any updates? It looks like this PR is in the final stage with only a few minor tweaks left, and it would be a shame if it didn’t get merged.

If @ketsebaoteth isn’t able to finish it for some reason, I’d be happy to take it over🙃

@neXyon
Copy link
Copy Markdown
Owner

neXyon commented Mar 26, 2026

If you're familiar with compressor effects, I'd appreciate the help. As I wrote, I don't even know good values to test this.

@AGoldenDragon
Copy link
Copy Markdown
Contributor

If you're familiar with compressor effects, I'd appreciate the help. As I wrote, I don't even know good values to test this.

Well, I guess if @ketsebaoteth won't answer in a few days I'll take over🙃

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.

4 participants