C# VOX文件转WAV文件

C# VOX录音文件转WAV文件

using System;
using System.IO;

class VOXDecoder
{

    static float signal = 0;
    static int previousStepSizeIndex = 0;
    static bool computedNextStepSizeOnce = false;
    static int[] possibleStepSizes = new int[49] { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 };

    public static void Decode(string inputFile, out string outputFile)
    {
        outputFile = String.Format("{0}\\{1}.wav", Path.GetDirectoryName(inputFile), Path.GetFileNameWithoutExtension(inputFile));
        using (FileStream inputStream = File.Open(inputFile, FileMode.Open))
        using (BinaryReader reader = new BinaryReader(inputStream))
        using (FileStream outputStream = File.Create(outputFile))
        using (BinaryWriter writer = new BinaryWriter(outputStream))
        {
            // Note that 32-bit integer values always take up 4 bytes.
            // Note that 16-bit integer values (shorts) always take up 2 bytes.
            // Note that HEX values resolve as 32-bit integers unless casted as something else, such as short values.
            // ChunkID: "RIFF"
            writer.Write(0x46464952);
            // ChunkSize: The size of the entire file in bytes minus 8 bytes for the two fields not included in this count: ChunkID and ChunkSize.
            writer.Write((int)(reader.BaseStream.Length * 4) + 36);
            // Format: "WAVE"
            writer.Write(0x45564157);
            // Subchunk1ID: "fmt " (with the space).
            writer.Write(0x20746D66);
            // Subchunk1Size: 16 for PCM.
            writer.Write(16);
            // AudioFormat: 1 for PCM.
            writer.Write((short)1);
            // NumChannels: 1 for Mono. 2 for Stereo.
            writer.Write((short)1);
            // SampleRate: 8000 is usually the default for VOX.
            writer.Write(8000);
            // ByteRate: SampleRate * NumChannels * BitsPerSample / 8.
            writer.Write(12000);
            // BlockAlign: NumChannels * BitsPerSample / 8. I rounded this up to 2. It sounds best this way.
            writer.Write((short)2);
            // BitsPerSample: I will set this as 12 (12 bits per raw output sample as per the VOX specification).
            writer.Write((short)12);
            // Subchunk2ID: "data"
            writer.Write(0x61746164);
            // Subchunk2Size: NumSamples * NumChannels * BitsPerSample / 8. You can also think of this as the size of the read of the subchunk following this number.
            writer.Write((int)(reader.BaseStream.Length * 4));
            // Write the data stream to the file in linear audio.
            while (reader.BaseStream.Position != reader.BaseStream.Length)
            {
                byte b = reader.ReadByte();
                float firstDifference = GetDifference((byte)(b / 16));
                signal += firstDifference;
                writer.Write(TruncateSignalIfNeeded());
                float secondDifference = GetDifference((byte)(b % 16));
                signal += secondDifference;
                writer.Write(TruncateSignalIfNeeded());
            }
        }
    }

    static short TruncateSignalIfNeeded()
    {
        // Keep signal truncated to 12 bits since, as per the VOX spec, each 4 bit input has 12 output bits.
        // Note that 12 bits is 0b111111111111. That's 0xFFF in HEX. That's also 4095 in decimal.
        // The sound wave is a signed signal, so factoring in 1 unused bit for the sign, that's 4095/2 rounded down to 2047.
        if (signal > 2047)
        {
            signal = 2047;
        }
        if (signal < -2047)
        {
            signal = -2047;
        }
        return (short)signal;
    }

    static float GetDifference(byte nibble)
    {
        int stepSize = GetNextStepSize(nibble);
        float difference = ((stepSize * GetBit(nibble, 2)) + ((stepSize / 2) * GetBit(nibble, 1)) + (stepSize / 4 * GetBit(nibble, 0)) + (stepSize / 8));
        if (GetBit(nibble, 3) == 1)
        {
            difference = -difference;
        }
        return difference;
    }

    static byte GetBit(byte b, int zeroBasedBitNumber)
    {
        // Shift the bits to the right by the number of the bit you want to get and then logic AND it with 1 to clear bits trailing to the left of your desired bit. 
        return (byte)((b >> zeroBasedBitNumber) & 1);
    }

    static int GetNextStepSize(byte nibble)
    {
        if (!computedNextStepSizeOnce)
        {
            computedNextStepSizeOnce = true;
            return possibleStepSizes[0];
        }
        else
        {
            int magnitude = GetMagnitude(nibble);
            if (previousStepSizeIndex + magnitude > 48)
            {
                previousStepSizeIndex = previousStepSizeIndex + magnitude;
                return possibleStepSizes[48];
            }
            else if (previousStepSizeIndex + magnitude > 0)
            {
                previousStepSizeIndex = previousStepSizeIndex + magnitude;
                return possibleStepSizes[previousStepSizeIndex];
            }
            else
            {
                return possibleStepSizes[0];
            }
        }
    }

    static int GetMagnitude(byte nibble)
    {
        if (nibble == 15 || nibble == 7)
            return 8;
        else if (nibble == 14 || nibble == 6)
            return 6;
        else if (nibble == 13 || nibble == 5)
            return 4;
        else if (nibble == 12 || nibble == 4)
            return 2;
        else
            return -1;
    }
}

使用如下:

string outputWAVFilePath;
VOXDecoder.Decode(pathToYourVOXFile, out outputWAVFilePath);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值