如何增加原始音频字节的音量/幅度

问题描述 投票:0回答:2

我正在处理电话原始电话声音和录音,我想在 .Net C# 项目中将它们标准化到一定的音量级别。

声音是原始音频字节的集合(单声道无头 16 位签名 PCM 音频 16000Hz)。

音频被分成 3200 字节 == 100ms 的块。

有什么建议如何增加音量/幅度以使声音更大吗?

我不知道是否需要添加常量或乘法值,或者是否需要每 1,2,3.... 字节执行一次?也许已经有一个开源解决方案了?

c# .net audio
2个回答
6
投票

回答我自己的问题(其他人)。

解决方案是将每个样本(16位PCM时为2字节)乘以一个常数值。

避免溢出或增加太多,您可以通过查找最高样本值来计算可以使用的最高常数值,并计算乘法因子以使其达到可能的最高样本值,在16位PCM情况下,即32676或其他值。

这是一个小例子:

    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;
    }

// 添加了 GetHighestAbsoluteSample,希望它仍然正确,因为代码随着时间的推移而发生了变化

    /// <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;
    }

0
投票

@托尼db

我修改了你添加的方法

public static 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)
    {
        short sample = BitConverter.ToInt16(audioBuffer, i);
        sample *= (short)(sample * multiplier);
        byte[] sampleBytes = GetLittleEndianBytesFromShort(sample);

        if (!BitConverter.IsLittleEndian)
        {
            sampleBytes = sampleBytes.Reverse().ToArray();
        }
        audioBuffer[i] = sampleBytes[sampleBytes.Length - 2];
        audioBuffer[i + 1] = sampleBytes[sampleBytes.Length - 1];
    }

    return audioBuffer;
}
public static short GetHighestAbsoluteSample(byte[] audioBuffer)
{
    short highestAbsoluteValue = 0;
    for (var i = 0; i < (audioBuffer.Length - 1); i = i + 2)
    {

        short sample;
        if (BitConverter.IsLittleEndian)
        {
            sample = (short)((audioBuffer[i + 1] << 8) | audioBuffer[i]);
        }
        else
        {
            byte[] tempBuffer = audioBuffer.Reverse().ToArray();
            sample= (short)((tempBuffer[i + 1] << 8) | tempBuffer[i]);
        }
        // prevent Math.Abs overflow exception
        if (sample == Int16.MinValue)
        {
            sample += 1;
        }
        var absoluteValue = Math.Abs(sample);

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

    return highestAbsoluteValue;
}
public static byte[] GetLittleEndianBytesFromShort(short data)
{
    byte[] b = new byte[2];
    b[0] = (byte)data;
    b[1] = (byte)(data >> 8 & 0xFF);
    return b;
}

由于上一个答案中添加的方法返回了编译错误。但声音似乎不太对劲。也许应该有一个正确的倍数值。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.