Low Gain/Volume when trying to play random sine wave

Hey,

I’d like to generate white noise - and whenever I add a random number to my sin function, the volume drops, and nothing seems to be helping the volume to increase (increasing level variable, etc). When I am removing the random factor, volume is great.

What am I missing, and what is the best way to randomize a sine wave without getting the volume dropped?

void getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) override
    {
        auto level = 0.125f;
        auto* leftBuffer  = bufferToFill.buffer->getWritePointer (0, bufferToFill.startSample);
        auto* rightBuffer = bufferToFill.buffer->getWritePointer (1, bufferToFill.startSample);

        for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
        {
            auto currentSample = (float) std::sin (currentAngle * rnd.nextDouble());
            currentAngle += angleDelta;

            leftBuffer[sample]  = currentSample * level;
            rightBuffer[sample] = currentSample * level;
        }
    }

I’m not really an expert but this looks supicious

auto currentSample = (float) std::sin (currentAngle * rnd.nextDouble())

You seem to be multiplying currentAngle with a random number. So at this point you are losing the sinus function, as current angle is completely irrelevant. So you probably intended to do something like this:

auto currentSample = (float) std::sin (currentAngle) * rnd.nextDouble()

So now you have a sine wave, but you mangle it with a random number. Though this will also probably sound messed up because it is too random. You should probably do something like:

auto currentSample = (float) std::sin (currentAngle) + 0.1 * rnd.nextDouble()

So that you append slight noise on top of the signal.
Btw. this is me pulling the code out of the air, so take it with a grain of salt.

1 Like

It should be something like multiplying between 0.5 and 2.0 so that the mean stays balanced. With pow it is possible to do this if the range of the random number is between -1.0 and 1.0, since 2^-1 = 0.5, 2^0 = 1, and 2^1 = 2. So if the random number is between 0 and 1 will suffice to multiply by two and subtract 1 to use as exponent, and intensity as base.

1 Like

Thanks - could you please provide a quick example in psudo code?

I’m sorry, I didn’t review your code and I assumed that the problem could be the multiplication. I have tested your code and it works fine. What value are you using for angleDelta?

Try this:

void getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) override
{
    auto level = 0.125f;
    auto noiseAmount = 0.5f;
    auto* leftBuffer  = bufferToFill.buffer->getWritePointer (0, bufferToFill.startSample);
    auto* rightBuffer = bufferToFill.buffer->getWritePointer (1, bufferToFill.startSample);

    for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
    {
        auto noise = rnd.nextFloat() * 2.0f - 1.0f;
        auto currentSample = jmap (noiseAmount, (float) std::sin (currentAngle), noise);
        currentAngle += angleDelta;

        leftBuffer[sample]  = currentSample * level;
        rightBuffer[sample] = currentSample * level;
    }
}

For starters the random noise number you’re generating needs to be in the [-1, 1] range, rnd.nextDouble() returns [0,1]. Changed it to float here because that’s more than good enough.

The introduced variable ‘noiseAmount’ is a [0,1] gradient between your sine wave and noise. A setting of 0.5 is an equal combination of sine wave and noise. Adjust to taste.

Using jmap to interpolate between the sine and noise means that currentSample will never exceed [-1, 1] which wouldn’t be the case if you just add a scaled random amount.

2 Likes