soloud icon indicating copy to clipboard operation
soloud copied to clipboard

setProtectVoice does nothing

Open klein-j opened this issue 3 years ago • 5 comments

Version "SoLoud 20200207" (most recent as of today)

I have a scene with plenty of 3D voices and 2D background music. I want the music to be always audible, however when the 3D sounds become too loud, the music is paused.

I used setProtectVoice and verified the state change via getProtectVoice, but there is no effect.

I searched through the source code, and apparently this feature is just not implemented. The only time the flag is used outside the setter/getter is in "findFreeVoice_internal", which looks for a free spot in the 1024 voice slots.

The problem is however than there is a very limited number of sounds that can play concurrently (e.g. 8) and my music is often kicked out of this selection. This seems to happen in calcActiveVoices_internal, but this function does not seem to care at all about the PROTECTED flag.

klein-j avatar Oct 13 '20 20:10 klein-j

Suggested fix

In Soloud::calcActiveVoices_internal() replace the old sorting code which is

int left = 0, stack[24], pos = 0, right;
		int len = candidates - mustlive;
		unsigned int *data = mActiveVoice + mustlive;
		int k = mActiveVoiceCount;
		for (;;) 
		{                                 
			for (; left + 1 < len; len++) 
			{                
				if (pos == 24) len = stack[pos = 0]; 
				int pivot = data[left];
				float pivotvol = mVoice[pivot]->mOverallVolume;
				stack[pos++] = len;      
				for (right = left - 1;;) 
				{
					do 
					{
						right++;
					} 
					while (mVoice[data[right]]->mOverallVolume > pivotvol);
					do
					{
						len--;
					}
					while (pivotvol > mVoice[data[len]]->mOverallVolume);
					if (right >= len) break;       
					int temp = data[right];
					data[right] = data[len];
					data[len] = temp;
				}                        
			}
			if (pos == 0) break;         
			if (left >= k) break;
			left = len;                  
			len = stack[--pos];          
		}

By

		auto comp = [this](const unsigned int & a, const unsigned int & b)
		{
			// Test a>b
			if((mVoice[a]->mFlags & AudioSourceInstance::PROTECTED) && !(mVoice[b]->mFlags & AudioSourceInstance::PROTECTED))
				return true;
			if((mVoice[b]->mFlags & AudioSourceInstance::PROTECTED) && !(mVoice[a]->mFlags & AudioSourceInstance::PROTECTED))
				return false;
			return mVoice[a]->mOverallVolume > mVoice[b]->mOverallVolume;
		};

		std::stable_sort(&mActiveVoice[0+mustlive], &mActiveVoice[candidates], comp);

and include .

Explanation: Sounds that are protected should always compare as louder than unprotected ones. I tried for about an hour to implement this in the given sort algorithm, but it was completely impossible to understand what it actually does. Besides, since sorting is a solved problem there is really no reason to implement your own sorting algorithm. The provided fix is much shorter and much much easier to understand or adapt in the future.

In my tests, it seemed to work as expected. Please comment.

klein-j avatar Oct 13 '20 22:10 klein-j

I had this exact problem, and can confirm that your change fixed it.

Anuken avatar Nov 07 '20 19:11 Anuken

Nice to hear. I attached a diff file in case others want to use the code as well. (The index in line 2 belongs to my repository, maybe the patch can't be applied directly to other repos)

Sad to see that the author is not responding to the issues here. SoLoud is a nice library but has so many issues that this sort of polishing through the community really needs to happen and also be applied to the official versions.

soloud.cpp.txt

klein-j avatar Nov 08 '20 09:11 klein-j

I uploaded my fix (along with some others) here:

https://github.com/klein-j/soloud_fixed/tree/soloud_fixed

klein-j avatar Mar 23 '24 20:03 klein-j

@klein-j thank you!

alnitak avatar Mar 23 '24 23:03 alnitak