zoukankan      html  css  js  c++  java
  • 如何转换音频数据格式1

    原文在此:http://www.codeproject.com/Articles/501521/How-to-convert-between-most-audio-formats-in-NET


    前面的音频处理背景知识就先跳过,需要的请自行脑补。

    直接上干货。

    一、声道转换

    1、单声道转立体声

    原理,双声道的16位采样,每16位是一个声道,也就是两字节;下一个16位是另外一个声道,交错进行。

    private byte[] MonoToStereo(byte[] input)
    {
        byte[] output = new byte[input.Length * 2];
        int outputIndex = 0;
        for (int n = 0; n < input.Length; n+=2)
        {
            // copy in the first 16 bit sample
            output[outputIndex++] = input[n];
            output[outputIndex++] = input[n+1];
            // now copy it in again
            output[outputIndex++] = input[n];
            output[outputIndex++] = input[n+1];        
        }
        return output;
    }

    2、立体声转单声道

    原理,去掉一半的数据即可。

    private byte[] StereoToMono(byte[] input)
    {
        byte[] output = new byte[input.Length / 2];
        int outputIndex = 0;
        for (int n = 0; n < input.Length; n+=4)
        {
            // copy in the first 16 bit sample
            output[outputIndex++] = input[n];
            output[outputIndex++] = input[n+1];
        }
        return output;
    }

    3、混合立体声转单声道

    如果是混合立体声,则可以把左右声道的数据求平均,得到单声道的值

    private byte[] MixStereoToMono(byte[] input)
    {
        byte[] output = new byte[input.Length / 2];
        int outputIndex = 0;
        for (int n = 0; n < input.Length; n+=4)
        {
            int leftChannel = BitConverter.ToInt16(input,n);
            int rightChannel = BitConverter.ToInt16(input,n+2);
            int mixed = (leftChannel + rightChannel) / 2;
            byte[] outSample = BitConverter.GetBytes((short)mixed);
            
            // copy in the first 16 bit sample
            output[outputIndex++] = outSample[0];
            output[outputIndex++] = outSample[1];
        }
        return output;
    }

    二、位宽转换

    4、16位转32位float

    相对简单,把每个16bit(两个byte,合成一个short)除以16位的最大值,得到一个相对的float值(介于0-1之间)。

    public float[] Convert16BitToFloat(byte[] input)
    {
        int inputSamples = input.Length / 2; // 16 bit input, so 2 bytes per sample
        float[] output = new float[inputSamples];
        int outputIndex = 0;
        for(int n = 0; n < inputSamples; n++)
        {
            short sample = BitConverter.ToInt16(input,n*2);
            output[outputIndex++] = sample / 32768f;
        }
        return output;
    }

    5、24位转32位float

    这个就稍微麻烦了,从原数据中每次取24位,即3个byte,补上一个0,折合成一个int,然后除以3个byte组成的数据最大值,得到一个相对float值(介于0-1之间)。

    public float[] Convert24BitToFloat(byte[] input)
    {
        int inputSamples = input.Length / 3; // 24 bit input
        float[] output = new float[inputSamples];
        int outputIndex = 0;
        var temp = new byte[4];
        for(int n = 0; n < inputSamples; n++)
        {
            // copy 3 bytes in
            Array.Copy(input,n*3,temp,0,3);
            int sample = BitConverter.ToInt32(temp,0);
            output[outputIndex++] = sample / 16777216f;
        }
        return output;
    }

    这种方式其实也相当于把3个采样点,线性拟合变成了2个了。

    6、还原数据

    两种方式还原的代码一样(后一种多的一个点信息已经丢失,还原也只有2个byte了):

    for (int sample = 0; sample < sourceSamples; sample++)
    {
        // adjust volume
        float sample32 = sourceBuffer[sample] * volume;
        // clip
        if (sample32 > 1.0f)
            sample32 = 1.0f;
        if (sample32 < -1.0f)
            sample32 = -1.0f;
        destBuffer[destOffset++] = (short)(sample32 * 32767);
    }

    三、重采样

    采样是这个文章中比较复杂的部分。

    =================== 占坑,以后讲原理====================

    7、一个简单的重采样算法

    原理就是,拉大或缩小采样点的间距。当然,明显的是,如果如果新采样率大于旧的,其实没有意义,造成很多点只会简单重复。

    新采样率小于旧的,就会在现有的点上,等比例往后拉。

    // Just about worst resampling algorithm possible:
    private float[] ResampleNaive(float[] inBuffer, int inputSampleRate, int outputSampleRate)
    {
        var outBuffer = new List<float>();
        double ratio = (double) inputSampleRate / outputSampleRate;
        int outSample = 0;
        while (true)
        {
            int inBufferIndex = (int)(outSample++ * ratio);
            if (inBufferIndex < read)
                writer.WriteSample(inBuffer[inBufferIndex]);
            else
                break;    
        } 
        return outBuffer.ToArray();    
    }


    ========== 留坑,讲重采样的测试==========


    下一部分,音频文件格式的转换







  • 相关阅读:
    MVC在View中页面跳转
    javaEE之------ApectJ的切面技术===标签
    Service的生命周期
    Codeforces Round #253 (Div. 2)
    hdu 3183 A Magic Lamp(给一个n位的数,从中删去m个数字,使得剩下的数字组成的数最小(顺序不能变),然后输出)
    【转】理解红黑树
    概要设计注意事项
    C++ 初始化与赋值
    UE 的使用
    内存泄漏
  • 原文地址:https://www.cnblogs.com/jiangu66/p/2996745.html
Copyright © 2011-2022 走看看