Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to increase volume/amplitude on raw audio bytes

Tags:

c#

.net

audio

I'm working with phone raw phone sounds and recordings and I want to normalize them to a certain volume level in a .Net C# project.

The sound is a collection of raw audio bytes (mono unheadered 16-bit signed PCM audio 16000Hz).

The audio is split into blocks of 3200 bytes == 100ms.

Any suggestions how to increase the volume/amplitude so the sounds is louder?

I haven't got a clue if I need to add a constant or multiply values, or if I need to do it to every 1,2,3.... bytes? And maybe there is already a open source solution for this?

like image 534
Toine db Avatar asked Apr 01 '16 12:04

Toine db


1 Answers

To answer my own question (for others).

The solution is to multiply every sample (when 16bit PCM that are 2 bytes) with a constant value.

Do avoid overflow\to much increase you can calculate the highest constant value you can use by looking for the highest sample value and calculate the multiply factor to get it to highest sample value possible, in 16bit PCM case thats 32676 or something.

Here is litle example:

    public byte[] IncreaseDecibel(byte[] audioBuffer, float multiplier) 
    {
        // Max range -32768 and 32767
        var highestValue = GetHighestAbsoluteSample(audioBuffer);
        var highestPosibleMultiplier = (float)Int16.MaxValue/highestValue; // Int16.MaxValue = 32767
        if (multiplier > highestPosibleMultiplier)
        {
            multiplier = highestPosibleMultiplier;
        }

        for (var i = 0; i < audioBuffer.Length; i = i + 2)
        {
            Int16 sample = BitConverter.ToInt16(audioBuffer, i);
            sample *= (Int16)(sample * multiplier);
            byte[] sampleBytes = GetLittleEndianBytesFromShort(sample);
            audioBuffer[i] = sampleBytes[sampleBytes.Length-2];
            audioBuffer[i+1] = sampleBytes[sampleBytes.Length-1];
        }

        return audioBuffer;
    }

// ADDED GetHighestAbsoluteSample, hopefully its still correct because code has changed over time

    /// <summary>
    /// Peak sample value
    /// </summary>
    /// <param name="audioBuffer">audio</param>
    /// <returns>0 - 32768</returns>
    public static short GetHighestAbsoluteSample(byte[] audioBuffer)
    {
        Int16 highestAbsoluteValue = 0;
        for (var i = 0; i < (audioBuffer.Length-1); i = i + 2)
        {
            Int16 sample = ByteConverter.GetShortFromLittleEndianBytes(audioBuffer, i);

            // prevent Math.Abs overflow exception
            if (sample == Int16.MinValue)
            {
                sample += 1;
            }
            var absoluteValue = Math.Abs(sample);

            if (absoluteValue > highestAbsoluteValue)
            {
                highestAbsoluteValue = absoluteValue;
            }
        }

        return (highestAbsoluteValue > LowestPossibleAmplitude) ?
                    highestAbsoluteValue : LowestPossibleAmplitude;
    }
like image 84
Toine db Avatar answered Sep 28 '22 09:09

Toine db