📄 recwav.cpp
字号:
#include "stdafx.h"
#include "recwav.h"
#include "util.h"
#include <stdlib.h>
static HINSTANCE hInst; // Instance handle
static HWND hwndMain; //Main window handle
static HDC whdc;
static HMODULE hMod;
static HPEN hpenB,hpenG,hpenOld;
static HWAVEIN hwi;
static WAVEHDR *pwhi,whis[MAX_INQUEU];
static char waveBufferRecord[MAX_INQUEU][REC_BUFSIZE];
static DWORD currWavHdr=0,nextWavHdr;
static BOOL b_playing;
static int mic_status = MIC_OFF;
FILE *fp_wav = NULL;
// wave buffer
char wave_buf[MAX_WAVE_BUF_LEN];
int wave_buf_pos = 0;
int max_wave_buf_len = MAX_WAVE_BUF_LEN;
int waveInit(HWND hWnd,WORD FormatTag,WORD Channel,DWORD Samples,WORD Bits, char *file_wave)
{
WAVEFORMATEX wfx;
long k;
if( micIsOn() )
return 0;
wave_buf_pos = 0;
memset(wave_buf, 0, sizeof(char) * max_wave_buf_len);
fp_wav = fopen(file_wave, "wb");
if( !fp_wav )
{
AfxMessageBox(L"Error: Cannot write to wave file!");
return -1;
}
setMicOn();
memset(&wfx,0,sizeof(WAVEFORMATEX));
wfx.wFormatTag=WAVE_FORMAT_PCM;
wfx.nChannels=Channel;
wfx.wBitsPerSample=Bits;
wfx.nSamplesPerSec=Samples;
wfx.nBlockAlign=Bits*Channel/8;
wfx.nAvgBytesPerSec=Samples*Bits*Channel/8;
wfx.cbSize=0;
waveInOpen(&hwi,0,&wfx,(DWORD)hWnd,0,CALLBACK_WINDOW|WAVE_MAPPED);
for(k=0;k<MAX_INQUEU;k++)
{
pwhi=&whis[k];
pwhi->dwFlags=0;
pwhi->dwLoops=0;
pwhi->dwBytesRecorded=0;
pwhi->dwBufferLength=REC_BUFSIZE;
pwhi->lpData=waveBufferRecord[k];
}
for(k=0;k<MAX_INQUEU-1;k++)
{
pwhi=&whis[k];
waveInPrepareHeader(hwi,pwhi,sizeof(WAVEHDR));
waveInAddBuffer(hwi,pwhi,sizeof(WAVEHDR));
}
currWavHdr=0;
pwhi=&whis[currWavHdr];
b_playing=TRUE;
waveInStart(hwi);
return 0;
}
int waveProcBuf(WAVEHDR *whdr)
{
// write to wave file
//fwrite(whdr->lpData, 1, whdr->dwBytesRecorded, fp_wav);
if( wave_buf_pos + whdr->dwBytesRecorded < max_wave_buf_len )
{
memcpy(wave_buf + wave_buf_pos, whdr->lpData, whdr->dwBytesRecorded);
wave_buf_pos += whdr->dwBytesRecorded;
}
// prepare for next buf
waveInUnprepareHeader(hwi,LPWAVEHDR(pwhi),sizeof(WAVEHDR));
nextWavHdr=(currWavHdr-1+MAX_INQUEU)%MAX_INQUEU;
currWavHdr=(currWavHdr+1)%MAX_INQUEU;
if(b_playing)
{
pwhi=&whis[nextWavHdr];
pwhi->dwFlags=0;
pwhi->dwLoops=0;
waveInPrepareHeader(hwi,pwhi,sizeof(WAVEHDR));
waveInAddBuffer(hwi,pwhi,sizeof(WAVEHDR));
}
return 0;
}
int waveCloseBuf(void)
{
int i;
int ret;
if( micIsOff() )
return 0;
b_playing=FALSE;
waveInReset(hwi);
for(i=0;i<MAX_INQUEU;i++)
{
waveInUnprepareHeader(hwi,pwhi,sizeof(WAVEHDR));
}
waveInClose(hwi);
if( wave_buf_pos != fwrite(wave_buf, 1, wave_buf_pos, fp_wav) )
{
ret = -1;
}else{
ret = 0;
}
fclose(fp_wav);
wave_buf_pos = 0;
setMicOff();
return ret;
}
bool micIsOff(void)
{
return mic_status == MIC_OFF ? true : false;
}
bool micIsOn(void)
{
return mic_status == MIC_ON ? true : false;
}
void setMicOn(void)
{
mic_status = MIC_ON;
}
void setMicOff(void)
{
mic_status = MIC_OFF;
}
int displayResult(const char *file_result, CListBox *m_listbox)
{
char line[MAX_LINE_LEN];
TCHAR wc_buf[MAX_LINE_LEN];
if( !file_result)
return -1;
FILE *fp = fopen(file_result, "rt");
if( !fp )
{
return -1;
}
while(fgets(line, MAX_LINE_LEN, fp))
{
char2unicode(line, wc_buf, MAX_LINE_LEN);
m_listbox->InsertString(0, wc_buf);
}
fclose(fp);
return 0;
}
// convert char to unicode
int char2unicode(const char *result, TCHAR *wc_result, int max_wc_len)
{
memset(wc_result, 0, max_wc_len * sizeof(TCHAR));
//计算从Ansi转换到Unicode后需要的字节数
int widecharlen=MultiByteToWideChar(
CP_ACP,
MB_COMPOSITE,
(char*)result, //要转换的Ansi字符串
-1, //自动计算长度
0,
0
);
//从Ansi转换到Unicode字符
MultiByteToWideChar(
CP_ACP,
MB_COMPOSITE,
(char*)result,
-1,
wc_result, //转换到wc_buf
max_wc_len
//widecharlen //最多转换widecharlen个Unicode字符
);
// if input string too long, return -1, otherwise return 0
return ( widecharlen > max_wc_len ) ? -1 : 0;
}
// unicode to convert char
int unicode2char(const TCHAR *wc_result, int wc_len, char *result, int max_len)
{
memset(result, 0, sizeof(char)*max_len);
//计算从Unicode转换到Ansi后需要的字节数
int charlen = WideCharToMultiByte(
CP_ACP, //根据ANSI code page转换
WC_COMPOSITECHECK | WC_DEFAULTCHAR, //转换出错用缺省字符代替
wc_result, //要转换的字符串地址
wc_len, //要转换的个数
0, //转换后字符串放置的地址
0, //最多转换字符的个数,为0表示返回转换Unicode后需要多少个字节
0, //缺省的字符:"\0"
0 //缺省的设置
);
WideCharToMultiByte( //转换Unicode到Ansi
CP_ACP,
WC_COMPOSITECHECK | WC_DEFAULTCHAR,
wc_result,
wc_len,
(char *)result, //转换到缓冲区中
max_len, //最多128个字节
0,
0);
// if input string too long, return -1, otherwise return 0
return ( charlen > max_len ) ? -1 : 0;
}
// compute the percentage of energe
int compEnerge(const char *buf, int len)
{
int i;
int energe = 0;
int step = 10;
for(i = 0; i < len; i += step)
{
int a = (unsigned char)buf[i];
if( a < 128 )
energe += 128 - a;
else
energe += a - 128;
}
energe = (energe * 100 * 2 * step)/(128 * len);
return energe;
}
// detect a wave is sil or not
int isSilWav(const char *buf, int len)
{
return is_wav_sil(1, (const unsigned char*)buf, len);
}
/* filter the silence from wave file */
int filter_wav_sil(const char *file)
{
#define BEGIN 0
#define MIDDLE 1
#define END 2
unsigned char buf[2000];
unsigned char *tmp_buf;
int len;
FILE *fp;
FILE *fp_tmp;
int max_len;
char file_tmp[256];
_t_wavhead wavhead;
int write_len;
int total_len;
int tmp_len;
int write;
int status;
int sil_cnt ;
//#if 1
#ifdef _DEBUG
char file_tmp2[256];
sprintf(file_tmp2, "%s.orig.wav", file);
//copyfile(file, file_tmp2);
//dbgMsg("(file: %s) (orig len: %4.3f sec) (non-sil len: %4.3f sec)",
// file, (float)total_len/8000, (float)write_len/8000);
#endif
sprintf(file_tmp, "%s.tmp", file);
fp = fopen(file, "rb");
fp_tmp = fopen(file_tmp, "wb");
max_len = 1600;
write_len = 0;
if( !fp )
{
//errMsg("cannot open file %s", file);
return -1;
}
/* skip the head of wave file */
fseek(fp, 50, SEEK_SET);
/* write output wave head */
memset(&wavhead, 0, sizeof(wavhead));
memcpy(wavhead.riff,"RIFF",4); // RIFF format identifier
wavhead.size_8=36; // 36 - jsut size of header
memcpy(wavhead.wave,"WAVE",4); // WAVE format
memcpy(wavhead.fmt,"fmt ",4); // fmt
wavhead.pcm=16; // code for pcm
wavhead.unknown=1;
wavhead.channel=1; // number of channels
wavhead.rate=REC_WAVE_FREQ; // sample rate
wavhead.byteps=REC_WAVE_FREQ*REC_WAVE_BIT/8; // Bytes by second
wavhead.bytepe=1; // Bytes per sample
wavhead.quent=8; // Bits per sample
memcpy(wavhead.data,"data",4); // constant
wavhead.datasize=write_len; // no of bytes of wave data
//fwrite(&wavhead, sizeof(wavhead), 1, fp_tmp);
tmp_buf = (unsigned char*)malloc(10000);
if( !tmp_buf ) {
//errMsg("cannot alloc %d Bytes", 10000);
return -1;
}
write_len = 0;
total_len = 0;
tmp_len = 0;
write = 0;
sil_cnt = 0;
status = BEGIN;
while( len = fread(buf, 1, max_len, fp) )
{
switch (status)
{
case BEGIN:
if ( !is_wav_sil(1,buf,len) )
//if( 1 )
{
write = 1;
status = MIDDLE;
sil_cnt = 0;
}else{
memcpy(tmp_buf, buf, len);
tmp_len = len;
}
break;
case MIDDLE:
if( is_wav_sil(1, buf, len) )
{
sil_cnt ++;
write = 0;
if( sil_cnt < 2 )
{
write = 1;
}else if( sil_cnt < 5 ){
memcpy(tmp_buf , buf, len);
tmp_len = len;
write = 0;
}else{
/* too many silence, treat it as end of wave file */
write = 0; /* wirte a silence to end of file */
// if( tmp_len > 1600 ) tmp_len = 1600;
//len = 0;
//status = END;
}
}else{
sil_cnt = 0;
write = 1;
}
break;
default:
break;
}
#ifdef _DEBUG
//dbgMsg("(status:%d) (tmp_len:%d) (len:%d) (write:%d)",
// status, tmp_len, len, write);
#endif
if( write )
{
fwrite(tmp_buf, 1, tmp_len, fp_tmp);
write_len += tmp_len;
fwrite(buf, 1, len, fp_tmp);
write_len += len;
tmp_len = 0;
len = 0;
write = 0;
}
total_len += len;
if( END == status ) break;
}
if( 0 == write_len )
{
//if the file is all silence, we still need to
//write sth to output file to avoid mfcc fault
int sil_len= 800;
memset(buf, 0x80, sil_len);
fwrite(buf, 1,sil_len, fp_tmp);
write_len = sil_len;
}
fclose(fp);
free(tmp_buf);
fclose(fp_tmp);
wavhead.datasize = write_len; // no of bytes of wave data
//#if 1
#ifdef _DEBUG
// backup original wave file
rename(file, file_tmp2);
#endif
// write the new wave to file
fp = fopen(file, "wb");
if( !fp )
return -1;
fp_tmp = fopen(file_tmp, "rb");
if( !fp_tmp )
{
fclose(fp);
return -1;
}
fwrite(&wavhead, 1, sizeof(_t_wavhead), fp);
while( int n = fread(buf, 1, 1024, fp_tmp) )
{
fwrite(buf, 1, n, fp);
}
fclose(fp_tmp);
fclose(fp);
remove(file_tmp);
//#if 0
//#ifndef _DEBUG
//remove(file);
//#endif
return 0;
}
// is a piece of wave silence or not
int is_wav_sil(int multiplier,
const unsigned char* data, int len)
{
int winsize = 200;
int sample;
int s = 0;
int nMinCZR = winsize;
int nMaxCZR = 0;
double energy = 0.0;
int nCZR = 0;
float numerator;
int i;
if (multiplier < 1)
multiplier = 1;
int bIsSil = 1;
#ifdef WAVE_DETECT_ZERO_STATUS
int zero_cnt = 0;
int zero_status = 0;
int last_zero_status = 0;
#endif
for (i = 0; i < len - 1; i++) {
#ifdef WAVE_DETECT_ZERO_STATUS
if( data[i] > 127 )
{
zero_status = 0;
}else{
zero_status = 1;
}
if( zero_status != last_zero_status )
zero_cnt ++;
last_zero_status = zero_status;
#endif
if (s == winsize) {
nMinCZR = (nMinCZR > nCZR) ? nCZR : nMinCZR;
nMaxCZR = (nMaxCZR < nCZR) ? nCZR : nMaxCZR;
nCZR = 0;
s = 0;
}
if ( ( (data[i] ^ data[i+1]) & 0x80 ) != 0)
nCZR++;
sample = ((int)data[i] - 128) * multiplier;
sample = (sample > 127) ? 127 : (sample < -128 ? -128 : sample);
energy += sample * sample;
s++;
}
#ifdef WAVE_DETECT_ZERO_STATUS
// 如果过零率太小,认为是silence
if( MIN_ZERO_CNT > zero_cnt )
return bIsSil;
#endif
sample = ((int)data[i] - 128) * multiplier;
sample = (sample > 127) ? 127 : (sample < -128 ? -128 : sample);
energy += sample * sample;
numerator = (float)len;
energy /= numerator; // To be average for short block
numerator = (float) winsize;
{
float fltInitCZR = (float) nMaxCZR / numerator;
float fltFinalCZR = (float) nMinCZR / numerator;
if (energy >= 25)
bIsSil = 0;
else if (energy > 12.5
&& (fltInitCZR > 0.30f || fltFinalCZR < 0.125f))
bIsSil = 0;
else if (energy > 7.5 && ( fltInitCZR > 0.35f))
bIsSil = 0;
return bIsSil;
}
}
int remove(const char *file)
{
TCHAR pFile[MAX_FILE_LEN];
char2unicode(file, pFile, MAX_FILE_LEN);
CFile::Remove( pFile );
return 0;
}
int rename(const char *old_file, const char *new_file)
{
TCHAR pOldName[MAX_FILE_LEN];
TCHAR pNewName[MAX_FILE_LEN];
char2unicode(old_file, pOldName, MAX_FILE_LEN);
char2unicode(new_file, pNewName, MAX_FILE_LEN);
CFile::Rename( pOldName, pNewName );
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -