HTK3.4程序员手册(1.1)--HTK中的wav文件格式
by 云龙
1.1.1 HTK中的Wav文件格式
HTK3.4支持wav文件格式称为HTK格式。头部为HTKhdr结构,占12个字节。无头的wav文件。默认16000Hz,单声道(mono),16位。Motorola PCM(MSB,LSB)格式。平时通过Cool Edit录制的语音是wav带文件头的Intel PCM(LSB,MSB)格式。
Wav文件格式有两种,Motorola PCM(MSB,LSB)格式和Intel PCM(LSB,MSB)格式。Motorola PCM(MSB,LSB)格式是采用Big Endian方式存储。Intel PCM(LSB,MSB)格式是采用Little Endian的方式存储。那么如何将Intel PCM(LSB,MSB)的Little Endian转换为Big Endian格式呢?
//将Intel PCM(LSB,MSB)的Little Endian转换为Big Endian格式
int ConvertIntelPCMtoMotorolaPCM(int Src,int *Dst){
int Low8 = (Src&0xFF)<<8;
int High8 = (Src&0xFF00)>>8;
int New16 = Low8 | High8 ;
*Dst = New16;
return 1;
}
HTK3.4支持的wav文件格式(无头的wav文件。默认16000Hz,单声道(mono),16位。Motorola PCM(MSB,LSB)格式)又是怎么样的呢?
HTK3.4中的HTK Header结构:
typedef struct { /* HTK File Header */
int32 nSamples; //4字节,语音样本数。一个样本16byte。
int32 sampPeriod; //4字节,一个样本持续的时间(百ns)。/* Sample period in 100ns units */
short sampSize; //2字节,一个语音样本占的字节数。16byte=2字节
short sampKind; //2字节,种类。这里=0
} HTKhdr;
注意:HTK中写到文件的时候要把字节位置颠倒。比如nSamples的1-4字节写为4-1位置。
HTK3.4中读取HTKhdr的函数:
/* EXPORT ReadHTKHeader: get header from HTK file, return false not HTK */
Boolean ReadHTKHeader(FILE *f, long *nSamp, long *sampP, short *sampS,
short *kind, Boolean *bSwap)
{
HTKhdr hdr;
int n = sizeof hdr; //n=12
if (fread(&hdr, 1, n, f) != n)
return FALSE;
if (!natReadOrder && vaxOrder){
*bSwap = TRUE;
}else{
*bSwap=MustSwap(UNKNOWNSO);
}
if (*bSwap){
SwapInt32(&hdr.nSamples); //将颠倒的byte倒回来,下同
SwapInt32(&hdr.sampPeriod); //…
SwapShort(&hdr.sampSize); //…
SwapShort(&hdr.sampKind); //…
}
//这个if纯属检查参数,同样的检查在HTK3.4中还有N多
if (hdr.sampSize <= 0 || hdr.sampSize > 5000 || hdr.nSamples <= 0 ||
hdr.sampPeriod <= 0 || hdr.sampPeriod > 1000000)
return FALSE;
*nSamp = hdr.nSamples; *sampP = hdr.sampPeriod;
*sampS = hdr.sampSize; *kind = hdr.sampKind;
return TRUE;
}
例如w2.wav头部
00 00 99 2000 00 02 71 00 02 00 00 00 9A 01 24 00 E6 01 12 01 3C 01 47 01 B0 01 67 01 3B 01 4D
W2.wav头部:
nSamples(4字节) 00 00 99 20 | sampPeriod 00 00 02 71(4字节) | sampSize 00 02(2字节) | sampKind 00 00(2字节) |
颠倒回来:20 99 00 00 样本数=0x9920 = 39200 文件大小= 39200*2+12字节 =78412字节 和文件属性中的大小相同 | 颠倒回来:71 02 00 00 =0x0271 = 625 一个样本持续的时间= 1/16000 * 107= 625(百纳秒) | 颠倒回来:02 00 每个样本的字节数=0x00 02 =2 | 种类=0 种类参照下表。 |
HTK代码中支持的语音种类编号:(WAVEFORM=0,其他依次类推)
enum _BaseParmKind{
WAVEFORM, /* Raw speech waveform (handled by HWave) */
LPC,LPREFC,LPCEPSTRA,LPDELCEP, /* LP-based Coefficients */
IREFC, /* Ref Coef in 16 bit form */
MFCC, /* Mel-Freq Cepstra */
FBANK, /* Log Filter Bank */
MELSPEC, /* Mel-Freq Spectrum (Linear) */
USER, /* Arbitrary user specified data */
DISCRETE, /* Discrete VQ symbols (shorts) */
PLP, /* Standard PLP coefficients */
ANON};
HTK中Wave结构的信息:
typedef struct _Wave{ /* Internal wave file representation */
MemHeap *mem; /* memory heap for this wave rec */
FileFormat fmt; /* Format of associated source file */
Boolean isPipe; /* Source is a pipe */
HTime sampPeriod; /* Sample period in 100ns units */
int hdrSize; /* Header size in bytes */
long nSamples; /* No of samples in data */
long nAvail; /* Num samples allocated for data */
short *data; /* Actual data (always short once loaded) */
int frSize; /* Num samples per frame */
int frRate; /* Frame rate */
int frIdx; /* Start of next frame */
}WaveRec;
HTK中默认一个窗=250000百纳秒=25000微秒=25毫秒。
每一个窗口包含的样本数 =窗大小/每个样本持续的时间 = 250000/625 = 400个样本
w->frSize = (int) (winDur / w->sampPeriod);
Wav头部也有2种,44字节和58字节。其中44字节头文件的wav文件格式:
WAV文件头(共占用44Bytes):
偏移地址 | 数据类型 | 字节数 | 内容 | 例值(16进制) |
00H | char | 4 | “RIFF”标志 | 52 49 46 46 |
04H | long int | 4 | 波形数据块大小=文件大小-8=数据大小+44-8 | 例如:04 7F 02 00(逆向) 长度=00h*2^24 +02h*2^16+7fh*2^8+04h |
08H | char | 4 | “WAVE”标志 | 57 41 56 45 |
0CH | char | 4 | “fmt”标志 | 66 6D 74 20 |
10H | char | 4 | 格式数据块的大小 | 10 00 00 00 |
14H | int | 2 | 格式类别 wFormatTag=WAVE_FORMAT_PCM=1 | 01 00 |
16H | int | 2 | 通道数:单声道为1,双声道为2 nChannels | 01 00 |
18H | int | 4 | 采样率:表示每秒采集到的样本数 nSamplesPerSec | 22 56 00 00(倒序) nSamplesPerSec=(56)*2^8+22 |
1CH | long int | 4 | 比特率 nAvgBytesPerSec=采样率*声道数*采样大小/8 | 44 AC 00 00(倒序) |
20H | int | 2 | 每个样本的字节数(byte) nBlockAlign =声道数*采样大小/8 | 02 00 |
22H | int | 2 | 每样本的数据位数(bit) wBitsPerSample = 声道数*采样大小 | 10 00 |
24H | char | 4 | 数据标记符”data” | 64 61 74 61 |
28H | long int | 4 | 波形数据大小=文件大小-44(字节) | 如果文件大小=22950字节 那么数据大小=22906字节 该值=0x7A 59 00 00 0x597A==22906 |