I wrote a C# class to decode VOX files into WAV files. It follows the Dialogic ADPCM specificationstrictly. If you read through that specification, the code below will become a lot clearer, otherwise you might think you’re reading another language altogether. The specification is really quite simple and nice once you boil it down. Note that the Dialogic ADPCM specification is different from the way NMS Communications libraries create VOX files as their file format is slightly different, and for files such as those, the code below will not work without some tweaks.

My implementation to decode from VOX to WAV files is as follows:

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

It is easily called through the following two lines:

string outputWAVFilePath;
VOXDecoder.Decode(pathToYourVOXFile, out outputWAVFilePath);

Give it a shot with this sample Dialogic ADPCM VOX audio fil

Decoding VOX Files in C# (Converting VOX Files to WAV Files)的更多相关文章

  1. 17.1.1.6 Creating a Data Snapshot Using Raw Data Files 创建一个数据快照使用 Raw Data Files

    17.1.1.6 Creating a Data Snapshot Using Raw Data Files 创建一个数据快照使用 Raw Data Files 如果数据库是大的, 复制raw 数据文 ...

  2. reading words in your computer and changing to female voice, linux festival text2wave saving wav files

    on a brand new linux PC, e.g. ubuntu 14.04 amd64 To hear voice sudo apt-get install festival -y then ...

  3. 【分享】利用Apache的Htaccess Files命令限制訪问文件类型,Files正则

    假设你在你的模板目录中有非常多PSD HTML模板,那么用接下来这个htaccess文件能够保护限制訪问: 文件D:\WebSite\ZBPHP.COM\www\Tpl\.htaccess 所有源代码 ...

  4. Python教程大纲

    缘起:最近想在部门推Python语言,写这个blog主要就是个教程大纲,之前先列出一些资源:Python历史:http://www.docin.com/p-53019548.html          ...

  5. The Python Standard Library

    The Python Standard Library¶ While The Python Language Reference describes the exact syntax and sema ...

  6. Huge CSV and XML Files in Python, Error: field larger than field limit (131072)

    Huge CSV and XML Files in Python January 22, 2009. Filed under python twitter facebook pinterest lin ...

  7. [ImportNew] Perforce - Restoring Mistakenly Deleted Files in Workspace

    Shit happens when you accidentally delete some files in your workspace and you have no ideas which o ...

  8. 详解 Too many open files

    运行在Linux系统上的Java程序可能会出现"Too many open files"的异常情况,且常见于高并发访问文件系统,多线程网络连接等场景. 程序经常访问的文件.sock ...

  9. Embed dll Files Within an exe (C# WinForms)—Winform 集成零散dll进exe的方法

    A while back I was working on a small C# WinForms application in Visual Studio 2008. For the sake of ...

随机推荐

  1. UNIX网络编程——客户/服务器心搏函数 (转)

    下面是关于回送客户和服务器程序开发一些简单的心搏函数.这些函数可以发现对端主机或到对端的通信路径的过早失效.         在给出这些函数之前我们必须提出一些警告.首先,有人会想到使用TCP的保持存 ...

  2. C++防止文件重复包含

    引用自:https://blog.csdn.net/xhfight/article/details/51550446 为了避免同一个文件被include多次,C/C++中有两种方式,一种是#ifnde ...

  3. Android 4.x 获取存储卡路径的方式

    http://blog.sina.com.cn/s/blog_8daaa9ea0101mx7f.html     以前的Android(4.1之前的版本)中,SDcard跟路径通过“/sdcard”或 ...

  4. U3D OnDrawGizmos

    private void OnDrawGizmos() { Debug.Log("OnDrawGizmos"); Gizmos.DrawWireSphere(this.transf ...

  5. Opencv normalize

    #include <iostream>#include <opencv2/opencv.hpp> using namespace std;using namespace cv; ...

  6. 关于@property与@syntheszie的使用问题

    写在前面:在ARC大行其道的“现代化社会”,不少人不再对“完整的“OC”抱有它应该获得的尊重,于是浮躁成了代名词~~ 在使用ARC时,大家声明变量的过程中,往往使用@property来通过编译器,隐式 ...

  7. Cloud Foundry技术资料汇总

    来自:http://cnblog.cloudfoundry.com/2012/05/ 本文是Cloud Foundry的一个简单上手指南和资料汇总,内容将根据产品的发布定期更新. Cloud Foun ...

  8. 面向对象 继承 抽象类 接口 static 权限修饰符

    Day01 面向对象 继承 抽象类 接口 static 1.匿名对象是指创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量. 2.类的继承是指在一个现有类的基础上去构建一个新的类,构建出 ...

  9. Zedboard学习(四):PS+PL搭建SoC最小系统 标签: fpgazedboardxilinxsoczynq 2017-07-07 15:58 7人阅读

    zynq最核心的设计理念就是软件加硬件,即PS+PL.通过软硬件协同设计,结合了FPGA与双arm9内核,对于嵌入式拥有极大的优势. SoC:System on Chip的缩写,称为芯片级系统,也有称 ...

  10. Ubuntu 安装QT5 后编译程序报错: FindQt5Widgets.cmake

    安装QT5.4后,需要编译一个C++程序. Cmakelist 有find_package(Qt5Widgets REQUIRED),cmake 报错如下: CMake Error at CMakeL ...