creating a multiband gui
-
@Maarid-Ekimmu I mean it is quite hard and fiddly to make an intuitive multiband UI imo, i have not started to try @Lindon s promising script yet. @Christoph-Hart A multiband container inside HISE or even scriptnode would definitely be a big plus if its easy to integrate into the UI. i was also wondering about the upper curve of the LR filter but then i found this and thought its just the mathematical definition and there is no other way.
-
the link to the source of the Monster plugin is above, the name of the plugin is clickable, you can make sure it works and not find a formula for compensating the edge of each selected channel, although maybe we are blind and you will succeed?
We also read about Linkwitz Riley, watched the Juce forums, well, it works for an open source person, without problems, miraclesadded
the only thing that comes to my mind is to contact the developer directly, explain this situation and ask for the formula, if it exists. It will be very funny if he answers the same way the programmer answered me - there is no formula, there is nothing to compensate :beaming_face_with_smiling_eyes: -
@Maarid-Ekimmu well that looks pretty much like the resonance of the two filters in your example.
-
@Lindon and?
I can't make any obvious sense out of your idiomatic sarcasm.Maybe you can point a finger at a silly boy, where is the compensation for the volume surge, which is missing in this plugin? :baby_light_skin_tone:
#include "CrossoverProcessors.hpp" namespace { void processBand(BandState& band, juce::AudioBuffer<float>& buffer) { if (band.isMuted) { buffer.clear(); } else { float* leftSamples {buffer.getWritePointer(0)}; float* rightSamples {buffer.getWritePointer(1)}; // Do the processing if (!band.isBypassed) { for (size_t index {0}; index < buffer.getNumSamples(); index++) { const double mid {(leftSamples[index] + rightSamples[index]) * 0.5}; const double side {(rightSamples[index] - leftSamples[index]) * (band.width / 2)}; leftSamples[index] = mid - side; rightSamples[index] = mid + side; } } // Update the envelope for (size_t index {0}; index < buffer.getNumSamples(); index++) { band.env.getNextOutput(leftSamples[index] - rightSamples[index]); } } } } namespace CrossoverProcessors { void prepareToPlay(CrossoverState& state, double sampleRate, int samplesPerBlock) { // We don't filter sidechain channels but do copy them to each buffer - so filters may need less channels than the buffers do for (juce::dsp::LinkwitzRileyFilter<float>& filter : state.lowpassFilters) { filter.prepare({sampleRate, static_cast<juce::uint32>(samplesPerBlock), static_cast<juce::uint32>(2)}); } for (juce::dsp::LinkwitzRileyFilter<float>& filter : state.highpassFilters) { filter.prepare({sampleRate, static_cast<juce::uint32>(samplesPerBlock), static_cast<juce::uint32>(2)}); } for (juce::dsp::LinkwitzRileyFilter<float>& filter : state.allpassFilters) { filter.prepare({sampleRate, static_cast<juce::uint32>(samplesPerBlock), static_cast<juce::uint32>(2)}); } for (juce::AudioBuffer<float>& buffer : state.buffers) { buffer.setSize(2, samplesPerBlock); } for (BandState& band : state.bands) { band.env.setSampleRate(sampleRate); } state.sampleRate = sampleRate; state.samplesPerBlock = samplesPerBlock; } void reset(CrossoverState& state) { for (juce::dsp::LinkwitzRileyFilter<float>& filter : state.lowpassFilters) { filter.reset(); } for (juce::dsp::LinkwitzRileyFilter<float>& filter : state.highpassFilters) { filter.reset(); } for (juce::dsp::LinkwitzRileyFilter<float>& filter : state.allpassFilters) { filter.reset(); } for (juce::AudioBuffer<float>& buffer : state.buffers) { buffer.clear(); } for (BandState& band : state.bands) { band.env.reset(); } } void processBlock(CrossoverState& state, juce::AudioBuffer<float>& buffer) { const size_t numCrossovers {state.bands.size() - 1}; // First split everything into bands and apply the processing for (int crossoverNumber {0}; crossoverNumber < numCrossovers; crossoverNumber++) { // We need to make a copy of the input buffer before processing // lowBuffer will be lowpassed, highBuffer will be highpassed juce::AudioBuffer<float>& lowBuffer = crossoverNumber == 0 ? buffer : state.buffers[crossoverNumber - 1]; juce::AudioBuffer<float>& highBuffer = state.buffers[crossoverNumber]; highBuffer.makeCopyOf(lowBuffer); { juce::dsp::AudioBlock<float> block(juce::dsp::AudioBlock<float>(lowBuffer).getSubsetChannelBlock(0, 2)); juce::dsp::ProcessContextReplacing context(block); state.lowpassFilters[crossoverNumber].process(context); // Crop the internal buffer in case the DAW has provided a buffer smaller than the specified block size in prepareToPlay juce::AudioBuffer<float> lowBufferCropped(lowBuffer.getArrayOfWritePointers(), lowBuffer.getNumChannels(), buffer.getNumSamples()); processBand(state.bands[crossoverNumber], lowBufferCropped); } { juce::dsp::AudioBlock<float> block(juce::dsp::AudioBlock<float>(highBuffer).getSubsetChannelBlock(0, 2)); juce::dsp::ProcessContextReplacing context(block); state.highpassFilters[crossoverNumber].process(context); // If this is the last band we need to apply the processing if (crossoverNumber + 1 == numCrossovers) { // Crop the internal buffer in case the DAW has provided a buffer smaller than the specified block size in prepareToPlay juce::AudioBuffer<float> highBufferCropped(highBuffer.getArrayOfWritePointers(), highBuffer.getNumChannels(), buffer.getNumSamples()); processBand(state.bands[crossoverNumber + 1], highBufferCropped); } } } // Finally add the bands back together if (state.numBandsSoloed > 0 && !state.bands[0].isSoloed) { buffer.clear(); } for (int crossoverNumber {0}; crossoverNumber < numCrossovers; crossoverNumber++) { // If there is another crossover after this one, we need to use an allpass to rotate the phase of the lower bands if (crossoverNumber + 1 < numCrossovers) { juce::dsp::AudioBlock<float> block(juce::dsp::AudioBlock<float>(buffer).getSubsetChannelBlock(0, 2)); juce::dsp::ProcessContextReplacing context(block); state.allpassFilters[crossoverNumber].process(context); } if (state.numBandsSoloed == 0 || state.bands[crossoverNumber + 1].isSoloed) { for (int channelNumber {0}; channelNumber < 2; channelNumber++) { buffer.addFrom(channelNumber, 0, state.buffers[crossoverNumber], channelNumber, 0, buffer.getNumSamples()); } } } } }
-
@Maarid-Ekimmu said in creating a multiband gui:
@Lindon and?
I can't make any obvious sense out of your idiomatic sarcasm.Why would you assume its sarcasm? Have I been sarcastic at anyone expense here?
To be clear nearly all filters have some resonant component at the freq cut-off point, if we look at your image:
its clearly demonstrating that resonant "bump" in both the low pass and the high pass filters....which appears to be what is appearing in the second of your images:
Of course this may well be wrong as I have no idea what is being measured here. If so please feel free to ignore me, and pursue your solution elsewhere.
-
@Lindon said in creating a multiband gui:
If so please feel free to ignore me, and pursue your solution elsewhere.
Do I understand correctly that the lack of response initiates trolling? Otherwise, why should I ignore anyone when they are diligently trying to help me?
I sincerely assure you, we can kindly exchange subtleties and barbs for any length of time, moreover, I will be sincerely glad to do so.
You're not trying to turn the topic of conversation offtop by ignoring common sense, I hope? -
@Maarid-Ekimmu he's trying to help you mate....
-
@DanH of course, ignore, just like you do. understand?
It's a pity all this tripe does not solve the question of why there is no glitch on C++ Juce, but there is on Scriptnode, lasers, piu, piu, piu
-
@Maarid-Ekimmu then I look forward to you solving the problem on your own
-
@DanH then, I will make vst available in an independent application by bringing it to the daw constructor, as soon as I learn c++