Getting linear sound level ?

I’ve been trying since 4 days to get a linear sound level like you can get in Unity, but with the Audio Visualizations Plugin, and so far the results are not anything near linear.

How can I get that ?

What I mean by linear, is that 0.0 is no sound at all, and 1.0 is the loudest sound you could ever get.

Bump. Really needing it.
It looks odd having a sound value nearing 0 when you hear a lot of sound.

Did this, but it doesn’t work (causes a crash).
Can anyone tell me why or where I’m wrong ?


void ULinearSound::getRawData(USoundWave * SoundWave, float StartTime, float TimeLength, TArray<float>& OutData)
{
	if (SoundWave->RawData.GetBulkDataSize() > 0)
	{
		uint8* RawWaveData = (uint8*)SoundWave->RawData.Lock(LOCK_READ_ONLY);
		int32 RawDataSize = SoundWave->RawData.GetBulkDataSize();
		FWaveModInfo WaveInfo;
		if (WaveInfo.ReadWaveHeader(RawWaveData, RawDataSize, 0))
		{
			uint32 SampleCount = 0;
			uint32 FirstSample = *WaveInfo.pSamplesPerSec * StartTime;
			uint32 LastSample = *WaveInfo.pSamplesPerSec * (StartTime + TimeLength);
			int16* SamplePtr = reinterpret_cast<int16*>(WaveInfo.SampleDataStart);
			for (uint32 SampleIndex = FirstSample; SampleIndex < LastSample; ++SampleIndex)
			{
				OutData.Add(FMath::Abs(*(SamplePtr + SampleIndex + SoundWave->ChannelOffsets[0] / 2)));
			}

		}
		SoundWave->RawData.Unlock();
	}
	return;
}


A few notes:

  • You should be checking to make sure that the pointers are valid (SoundWave)
  • Does “RawDataSize” get set to 0?
  • Placing a breakpoint at the start of the function and stepping through(F10) and or stepping into the function(F11) would probably be helpful
  • The return statement at the end is not needed.
  • I would place the const(ants) on the left side of any if branch ( 0 < SoundWave->RawData.GetBulkDataSize() )

HTH

I’ve got it : The error come from that line :


OutData.Add(FMath::Abs(*(SamplePtr + SampleIndex + SoundWave->ChannelOffsets[0] / 2)));

But I don’t know why.

Does the VS output window have a entry that explains what happens at the line? (Like a first chance exception was caught)
It could be de that it is trying to read beyond the allocation size of the buffer.
It may be helpful later on to store the calculation in a variable and then add that to the array, That way you can investigate the values of it.

Could you elaberate what this line is supposed to be doing?

HTH

It comes from here :


void USoundVisualizationStatics::GetAmplitude(USoundWave* SoundWave, const bool bSplitChannels, const float StartTime, const float TimeLength, const int32 AmplitudeBuckets, TArray< TArray<float> >& OutAmplitudes)
{

	OutAmplitudes.Empty();

#if WITH_EDITORONLY_DATA
	const int32 NumChannels = SoundWave->NumChannels;
	if (AmplitudeBuckets > 0 && NumChannels > 0)
	{
		// Setup the output data
		OutAmplitudes.AddZeroed((bSplitChannels ? NumChannels : 1));
		for (int32 ChannelIndex = 0; ChannelIndex < OutAmplitudes.Num(); ++ChannelIndex)
		{
			OutAmplitudes[ChannelIndex].AddZeroed(AmplitudeBuckets);
		}

		// check if there is any raw sound data
		if( SoundWave->RawData.GetBulkDataSize() > 0 )
		{
			// Lock raw wave data.
			uint8* RawWaveData = ( uint8* )SoundWave->RawData.Lock( LOCK_READ_ONLY );
			int32 RawDataSize = SoundWave->RawData.GetBulkDataSize();
			FWaveModInfo WaveInfo;

			// parse the wave data
			if( WaveInfo.ReadWaveHeader( RawWaveData, RawDataSize, 0 ) )
			{
				uint32 SampleCount = 0;
				uint32 SampleCounts[10] = {0};

				uint32 FirstSample = *WaveInfo.pSamplesPerSec * StartTime;
				uint32 LastSample = *WaveInfo.pSamplesPerSec * (StartTime + TimeLength);

				if (NumChannels <= 2)
				{
					SampleCount = WaveInfo.SampleDataSize / (2 * NumChannels);
				}
				else
				{
					for (int32 ChannelIndex = 0; ChannelIndex < NumChannels; ++ChannelIndex)
					{
						SampleCounts[ChannelIndex] = (SoundWave->ChannelSizes[ChannelIndex] / 2);
						SampleCount = FMath::Max(SampleCount, SampleCounts[ChannelIndex]);
						SampleCounts[ChannelIndex] -= FirstSample;
					}
				}

				FirstSample = FMath::Min(SampleCount, FirstSample);
				LastSample = FMath::Min(SampleCount, LastSample);

				int16* SamplePtr = reinterpret_cast<int16*>(WaveInfo.SampleDataStart);
				if (NumChannels <= 2)
				{
					SamplePtr += FirstSample;
				}

				uint32 SamplesPerAmplitude = (LastSample - FirstSample) / AmplitudeBuckets;
				uint32 ExcessSamples = (LastSample - FirstSample) % AmplitudeBuckets;

				for (int32 AmplitudeIndex = 0; AmplitudeIndex < AmplitudeBuckets; ++AmplitudeIndex)
				{
					if (NumChannels <= 2)
					{
						int64 SampleSum[2] = {0};
						uint32 SamplesToRead = SamplesPerAmplitude + (ExcessSamples-- > 0 ? 1 : 0);
						for (uint32 SampleIndex = 0; SampleIndex < SamplesToRead; ++SampleIndex)
						{
							for (int32 ChannelIndex = 0; ChannelIndex < NumChannels; ++ChannelIndex)
							{
								SampleSum[ChannelIndex] += FMath::Abs(*SamplePtr);
								SamplePtr++;
							}
						}
						for (int32 ChannelIndex = 0; ChannelIndex < NumChannels; ++ChannelIndex)
						{
							OutAmplitudes(bSplitChannels ? ChannelIndex : 0)][AmplitudeIndex] = SampleSum[ChannelIndex] / (float)SamplesToRead;
						}
					}
					else
					{
						uint32 SamplesRead = 0;
						int64 SampleSum = 0;
						uint32 SamplesToRead = SamplesPerAmplitude + (ExcessSamples-- > 0 ? 1 : 0);
						for (int32 ChannelIndex = 0; ChannelIndex < NumChannels; ++ChannelIndex)
						{
							uint32 SamplesToReadForChannel = FMath::Min(SamplesToRead, SampleCounts[ChannelIndex]);

							if (SamplesToReadForChannel > 0)
							{
								if (bSplitChannels)
								{
									SampleSum = 0;
								}

								for (uint32 SampleIndex = 0; SampleIndex < SamplesToReadForChannel; ++SampleIndex)
								{


									SampleSum += FMath::Abs(*(SamplePtr + FirstSample + SampleIndex + SoundWave->ChannelOffsets[ChannelIndex] / 2));



								}

								if (bSplitChannels)
								{
									OutAmplitudes[ChannelIndex][AmplitudeIndex] = SampleSum / (float)SamplesToReadForChannel;
								}
								SamplesRead += SamplesToReadForChannel;
								SampleCounts[ChannelIndex] -= SamplesToReadForChannel;
							}
						}

						if (!bSplitChannels)
						{
							OutAmplitudes[0][AmplitudeIndex] = SampleSum / (float)SamplesRead;
						}

						FirstSample += SamplesToRead;
					}
				}
			}

			SoundWave->RawData.Unlock();
		}
	}
#else
	UE_LOG(LogSoundVisualization, Warning, TEXT("Get Amplitude does not work for cooked builds yet."));
#endif
}

and, as far as I know, that was the only line that could extract the samples out of the sound.
also, the VS doesn’t explain anything to me.

While this is usefull for the context, It does not tell me what you are trying to do with that line.
It looks like you are trying to access a value in the buffer, But I don’t know if that is what it is supposed to do.

HTH

I’m trying to get the samples of the sound being played, but it doesn’t seem simple.

Okay, I am going to have to do some digging around to see if I can find something useful to add.

I have just remembered that Exi has released a plugin that reads data from a sound.
You should be able to find out how he does it from there, I may take a look at that later.

HTH

Are you making progress?

A quick question: Why are you not using a audio tool (Audacity, Audition, Etc) to normalize the sounds ?

Not making any progress, it looks like it’s unimplemented.
I’m not using this kind of thing because it’ll be moddable, so the sounds will not always be normalized.