Modify volume gain on audio sample buffer
Asked Answered
A

1

6

I want to increase a volume on buffer with voice data. The point is I'm using DirectSound and I have one primary and one secondary buffer - all streams mixing is done by hand. In a voice chat all participants can have independent volume levels. I multiply each stream data by a value (gain) and sum it to one buffer. Everything works fine but when I try to multiply data by a value greater than 1.0f - I hear some clipping or what.

I've tried using Audacity effect compressor but this doesn't help reducing the strange noise.

Probably I should modify gain in some other way? Or just use another post-processing algorithm?

UPDATE: Wow, I've just found out interesting thing! I've dumped audio before increasing volume and right after that.

Here is the pic Clipped audio

Sorry for the quality - I think that's how the sound is supposed to appear (I've drawn red line myself). Really looks like values exceed the sample data type. But I cannot understand WHY? My samplebuffer is BYTE but I access it only via short pointer. It is signed but clipping happens even when *ptr is about 15-20 thousand.

Argilliferous answered 29/11, 2010 at 5:6 Comment(3)
what is "some clipping or what" - do your values actually exceed the bounds for the sample data type? and what do you mean by "tried using Audacity effect compressor"? Is it on the clipped output or on the output before clipping?Teary
The sample is 200ms audio with 22050hz sampling rate. 2 bytes - short. If I multiply this sample by 1.f - the original volume - everything is fine. If I multiply by a value less than 1.f - the volume becomes lower. But If I multiply it by e.g. 1.3f - the volume becomes higher but with ugly scratch noice. I used audacity effect compressor on the mixed buffer (with clipping).Argilliferous
Here is my answer with some code - it's out of my head, so don't expect it to work as is.Luciusluck
H
8

For every sample - convert it to some larger data type - if you have 16 bit signed samples, they originally fit in SHORT - extract it from the stream, then cast to local double, then multiply, then CLIP, then cast back to SHORT.

It MUST work that way...

I can even provide code sample if needed.

EDIT:

Your picture is exact evidence that you didn't expand to larger type before multiplication - you can't 'capture' clipping condition on SHORT because it will wrap automatically.

short* sampleBuffer;
...
short sample=*sampleBuffer;
double dsample=(double)sample * gain;
if (dsample>32767.0) {dsample=32767.0;}
if (dsample<-32768.0) {dsample=-32768.0;}
*sampleBuffer=(short)dsample;
sampleBuffer++;

And one more EDIT:

if you have several voices - first put them all to double - then GAIN each one - then add them - and CLIP them as the last step.

One more EDIT (+1s are inspiring me):

If you have STEREO, same stuff will work also, just count all the samples x2 i.e.

number of shorts = number of samples * 2.

Hydrogen answered 29/11, 2010 at 14:26 Comment(2)
Wow! That's just a super answer! Thanks a lot - I'll try this approach tomorrow and mark as answered if everything will be ok ;)Argilliferous
Yep, it works! Honestly, it's a kind of stupid mistake I've done :'( Daniel, thanks a lot for your help!Argilliferous

© 2022 - 2024 — McMap. All rights reserved.