soloud icon indicating copy to clipboard operation
soloud copied to clipboard

mixBus_internal can get stuck in an infinite loop when writesamples is 0

Open AniCator opened this issue 3 years ago • 1 comments

Expected behavior

The function does not get stuck in an infinite loop and the application does not lock up.

Actual behavior

In mixBus_internal, writesamples and outofs can, in rare cases, both be 0; causing the resampling while loop to never finish execution.

Steps to reproduce the problem

I was repeatedly playing a sound over a bus at a regular interval with its rate being adjusted to that of a hailstone sequence. In some cases it would happen almost immediately, in other cases I had to wait 30 seconds or longer.

I suspect it happens when the playback rate of a sound is near 0.0.

Workaround

I've temporarily just stuck a break in the while loop when writesamples is 0.

// Call resampler to generate the samples, once per channel
if (writesamples)
{
	...
}
else
{
	// NOTE: Breaking here because this thing can get stuck in an infinite loop.
	break;
}

This creates an audible noise whenever the issue occurs but it at least stops my game engine from getting stuck.

SoLoud version, operating system, backend used, any other potentially useful information

Custom fork, branched from main, with the last merged in change being 4d72336a8855f3f421f95ec75cda9062da3fe7eb From the looks of it, the code in the master branch has not changed in this area since then.

AniCator avatar Feb 23 '22 21:02 AniCator

The hailstone sequence function in question. SoLoud functions are abstracted away by other classes in my engine.

void HailStone()
{
	static CSound* Bleep = CAssets::Get().CreateNamedSound( "bleep", "Audio/UI/Placeholder/Message.ogg" );
	static SoundInstance BleepInstance = SoundInstance( Bleep );
	static float LastBleep = -1.0f;
	static auto Hailstone = Math::RandomRangeInteger( 1, 20000 );

	if( LastBleep < 0.0f )
	{
		LastBleep = GetCurrentTime();
	}

	const auto BleepDelta = GetCurrentTime() - LastBleep;

	if( Bleep && BleepDelta > 0.15f )
	{
		LastBleep = GetCurrentTime();

		const auto HailstonePrevious = Hailstone;
		if( Hailstone % 2 )
		{
			Hailstone = Hailstone * 3 + 1;
		}
		else
		{
			Hailstone /= 2;
		}

		if( Hailstone <= 1 )
		{
			Hailstone = Math::RandomRangeInteger( 1, 20000 );
		}

		const auto HailstoneDelta = abs( HailstonePrevious - Hailstone );
		const auto Delta = StaticCast<float>( HailstoneDelta ) / 20000.0f;

		auto Spatial = Spatial::CreateUI();
		Spatial.Bus = Bus::Auxilery7;
		Spatial.Rate = Delta * 100.0f;

		if( Spatial.Rate > 0.1f )
		{
			Spatial.Volume = Math::Clamp( Spatial.Rate * 100.0f, 10.0f, 100.0f );

			// BleepInstance.Stop( 0.1f );
			BleepInstance.Start( Spatial );
		}
	}
}

AniCator avatar Feb 23 '22 21:02 AniCator