100$ BugFix bounty

Hi

I’ve been stuck for ages on my plugin, anybody who can fix my phase bug gets 100$ PayPal gift or wire transfer. When I play a note I get a lot of crackling noise. I think it’s my phase that’s off. I had exactly the same phase calculation before putting it into two different audio processors and then it worked.

And some feedback on my coding style would be nice as well.

The code is here:

This will probably not solve your problem, I took a fast glance and this line in your file pluginprocessor.cpp looks suspicious to me

if (*modeParameter == 1.0f || 2.0f || 3.0f)

Did you mean

if (*modeParameter == 1.0f || *modeParameter == 2.0f || *modeParameter == 3.0f)

?

Also in a ComponentCircleCardioid.cpp and ComponentWavetable.cpp on multiple places start and end AngleRadians should to be in a range >= 0 and < (pi * 4) in Slider::setRotaryParameters(…)

1 Like

I built and run the code. I got some jasserts in the debugger relating to Juce Slider. I was able to continue execution from those and I was able to produce some sound playing with my MIDI keyboard. But I am not sure how the sound should actually be like? Do you have any sound examples that could be compared to what your code produces?

If you turn the factor knob (right top corner near circle) to completely closed, and the left bottom under near circle completely open you get a pure sine. The two knobs between the waveforms are the oscillator volumes

The Jasserts are because I did some hackerish stuff in the sample size selection knobs and it does give an error when you control them from a daw (not the gui) and go over the boundary.

Most excellent, thank you

One of the improvement you can do is avoid dynamic casting in the process block

if ((voice = dynamic_cast<SynthVoice*>(synth.getVoice(i))))

These stetting of parameter can be done in

  void setWavetable(std::array<std::array<float, 1081>, 2>* wavetable_h)
  void setParameters (std::atomic<float>* attack, std::atomic<float>* decay,
                      std::atomic<float>* sustain, std::atomic<float>* release,
                      std::atomic<float>* gain_value, std::atomic<float>* tuning,
                      std::atomic<float>* start_sample ,std::atomic<float>* stop_sample)
    {
      if(tune < 0){increment = (frequency / tune_holder) * wt_size / samplerate;}
      else{        increment = (frequency * tune_holder) * wt_size / samplerate;}

      adsr.setParameters(adsr_parameters);
        for (int sample = 0; sample < numSamples; ++sample)
        {
            for (int channel = 0; channel < outputBuffer.getNumChannels(); ++channel)
            {
              outputBuffer.addSample(channel, startSample, (*wavetable)[id][first_sample + (int) phase_0]  * level * adsr.getNextSample() * gain );
              phase_0 = fmod(phase_0 + increment,wt_size);
            }
            ++startSample;
        }
    }

didn’t dive deep, at quick glance perhaps not understanding the logic, but you’re doing all you’re processing doubled up by channel.

so each sample phase is getting incremented twice, your attack env is getting hit twice, etc

I would expect something more like:

{
    for (int sample = startSample; sample < startSample + numSamples; ++sample)
    {
        env_value = adsr.getNextSample()

        for (int channel = 0; channel < outputBuffer.getNumChannels(); ++channel)
        {
          outputBuffer.addSample(channel, sample, (*wavetable)[id][phase_0]  * level * env_value* gain ); <- needs interpolation?
        }

        phase_0 = fmod(phase_0 + increment,wt_size);
    }
}

or even just:

    {
        for (int sample = startSample; sample < startSample + numSamples; ++sample)
        {
            float env_value = adsr.getNextSample()
            float sample_out = (*wavetable)[id][phase_0]  * level * env_value* gain;

            for (int channel = 0; channel < outputBuffer.getNumChannels(); ++channel)
            {
              outputBuffer.addSample(channel, sample, sample_out);
            }

            phase_0 = fmod(phase_0 + increment,wt_size);
        }
    }

Anyways the main point is unless you’re doing something funky like processing the left & right channel differently or making a sampler, you just want to calculate the output sample once and pack it into both Channels.

Also, if you’re using floating point phase, but a indexed wavetable, you’ll need at least linear interpolation for a clean sound.

If you do need independent left & right phase & envelopes, you need to manage them separately

you can PayPal me at penn.jacob@gmail.com :joy:

also: #1 most common programming mistake that we see on the forum

In general the quality and speed of the algorithm is directly proportional to number of decision statements and floating point arithmetic you are carrying out in the algorithm.

  • What I see in your code is lot of if else statements which can be avoided easily.
  • Also the floating point arithmetic is repeated inside the for loop which can be done outside of each for loop.
  • Also setting of parameters is done in the process block which should not take more CPU cycles.
  • If you delay the process block then the output is starving for data and there will be glitches in low configuration machines which does not have enough CPU cores to execute the code.

While it‘s true that code that takes to long to execute will cause glitches, I don‘t see the relation to the number of CPU cores in this specific context. The audio processing callback will only ever be handled by one thread only and therefore by one single CPU core at a time, so while inter-thread stuff is relevant in many cases, here it is not

Try opening multiple heavy application in dual core system. You will see the result.

Thanks for your time, I overlooked this issue because it was working before I put it into two seperate audio processors. And also I’m a bit stupid :stuck_out_tongue:. I can show you the code working like this, no idea why it worked perfectly after you explained I’m hitting it twice.

I changed my code to your second example but I still have exactly the same problem

I’m looking into the linear interpolation and the phase struct. Maybe this might fix my issue. I doubt it, probably sounds cleaner after the problem is fixed though

Thanks for your time, it’s time for operation clean up the code I will check out how I can remove my if else statements.

Also the floating point arithmetic is repeated inside the for loop which can be done outside of each for loop.

Do you mean what jakemumu pointed out in his example?

Also setting of parameters is done in the process block which should not take more CPU cycles.

Okay note taken so I can’t set them once in prepare to play? This will cause errors or what?

If you delay the process block then the output is starving for data and there will be glitches in low configuration machines which does not have enough CPU cores to execute the code.

What do you mean delay the processBlock? I just execute two processblocks one after each other, should work right?

I FIXED IT! I was hitting renderNextBlock 5 times lol

As I see you have added 5 SynthVoice and you are iterating through those and calling renderNextBlock.
Did you wanted to select the SynthVoice based on Id or something?

Yes of course, I didn’t question that at all. Multiple Cores speed up parallel workflows, e.g. as you said multiple applications running in parallel or heavily multithreaded applications.

But how does this relate to the original question of some specific audio processing code running good in one host and bad in another host? While everything else you mentioned makes sense in that context, I don‘t see anything heavily parallel going on here, so mentioning that this could be something to consider here seemed a bit misleading especially for newcomers reading the topic :wink:

Anyway, I’m glad that @Rubenkaller could fix the original issue :slight_smile:

1 Like

You still owe me $100!!! Just kidding it took literally 20 seconds to see that lol. Glad you got it fixed! Congrats! Def add the linear interpolation you’ll need it for wavetables, you will definitely notice it pitched down sounding wrong.

1 Like

Agreed