我需要能够为医疗应用程序提供一个独立的系统,该系统将免费分发给血压计的家庭用户,它被设计为通过记忆棒运行并带到医生、药剂师、医院、我想要一个数据库文件,其中包含用于不懂计算机的数据输入字段的语音指令。
该系统正在开发中,以捕获用户在家中观察到的大量症状数据,然后将其交给医生在系统中打开并查看当时的观察数据以进行实际检查和诊断,它适用于那些有兴趣帮助自己的人,让他们的医生或任何其他健康从业者了解患者在疼痛、感觉和医生可能依赖的其他重要信息中所经历的情况。
目前我有
String file = frmMDI->dlg->InitialDir + "\\sounds\\" + "ObservationDateTimeField.wav";
speech->Send(file);
它的作用是在收到焦点时说出现场预期的指令,它按原样工作正常,但希望从数据库获取 wav,因此通过 USB 分发的文件最少。
在 OnEnter 方法中,语音是一个自定义控件,用于管理我的需求,只是 .wav 文件的 PlaySound(...) 要求,其他控件决定如何以及何时发送指令。
编辑: 添加观察窗口的屏幕截图
我希望将其开源,但我不知道如何实现它,这是跨越 20 年的思想发展,我的代码可能有缺陷,但它一切正常,并且已经这样做了很长时间。
如果可以的话,我该怎么做?
我没有时间尝试太多的事情,例如发送流而不是文件,从 .wav 声音文件播放声音效果很好
PlaySound()
无法播放流中的音频。它可以从文件、内存块或 EXE/DLL 资源播放。
我不建议将 WAV 音频存储在数据库 blob 中。请改用文件或资源。但是,如果您必须使用数据库,则可以使用
TDataSet::CreateBlobStream()
方法获取只读 TStream
来访问 blob 数据,然后您可以 Read()
将该数据放入已分配的内存缓冲区中,或者 CopyFrom()
将其放入 TMemoryStream
,然后您可以从该缓冲区/流的内存中进行 PlaySound()
播放。
waveOutOpen()
/waveOutPrepareHeader()
/waveOutWrite()
,或者使用更现代的 API,如 DirectSound 或 XAudio2。
根据我的经验,WAVEIN/WAVEOUT 是 win 上用于此目的的最佳声音 api...DirectSound 是有问题且延迟非常大,所以我几年前就停止使用它了...
这里是我最初为我的示波器、频谱分析仪、信号发生器应用程序编写的古老 C++ 库,但在任何地方甚至在我的 ZXSpectrum 模拟器中都使用它:
waveout.h:
//---------------------------------------------------------------------------
//--- WAVE IN/OUT class ver: 4.02 -------------------------------------------
//---------------------------------------------------------------------------
#ifndef _waveout_h
#define _waveout_h
//---------------------------------------------------------------------------
#include <mmsystem.h>
#include "fifo.h"
#include "lock.h"
//---------------------------------------------------------------------------
void CALLBACK wave_in_event(HWAVEIN hw,UINT msg,DWORD inst,DWORD p1,DWORD p2);
void CALLBACK wave_out_event(HWAVEOUT hw,UINT msg,DWORD inst,DWORD p1,DWORD p2);
//---------------------------------------------------------------------------
class wave_in
{
public:
bool _init,_fifo;
FIFO<BYTE> fifo;
WAVEHDR *hdr;
HWAVEIN hw;
WAVEFORMATEX buff_format;
DWORD buff_size;
DWORD freq; WORD chanels,bits,samples,buffers;
BYTE **buff;
int adr,num;
void CALLBACK (*event)(HWAVEIN hw,UINT msg,DWORD inst,DWORD p1,DWORD p2);
// void (*onreceive)(wave_in *wi,BYTE *data,int size);
void (__closure *onreceive)(wave_in *wi,BYTE *data,int size);
wave_in()
{
hdr=NULL;
buff=NULL;
buffers=0;
buff_size=0;
_init=false;
adr=0;
num=0;
event=wave_in_event;
onreceive=NULL;
}
~wave_in()
{
_free();
}
wave_in(wave_in& a) { *this=a; }
wave_in* operator = (const wave_in *a) { *this=*a; return this; }
//wave_in* operator = (const wave_in &a) { ...copy... return this; }
void _free()
{
adr=0;
num=0;
if (_init) { waveInClose(hw); _init=false; }
#ifdef _mmap_h
if (buff) for (int i=0;i<buffers;i++) if (buff[i]) mmap_del(buff[i]);
if (buff) mmap_del(buff);
if (hdr ) mmap_del(hdr );
#endif
if (buff)
{
for (int i=0;i<buffers;i++) if (buff[i]) delete[] buff[i];
delete[] buff;
buff=NULL;
}
if (hdr) { delete[] hdr; hdr=NULL; }
}
void init(DWORD _freq,WORD _chanels,WORD _bits,WORD _samples,WORD _buffers=5)
{
int i,ret;
_free();
buffers=_buffers;
if (buffers<1) buffers=1;
hdr=new WAVEHDR[buffers];
buff=new BYTE*[buffers];
#ifdef _mmap_h
if (hdr ) mmap_new(hdr ,buffers*sizeof(WAVEHDR));
if (buff) mmap_new(buff,buffers*sizeof(BYTE*));
#endif
freq =_freq;
chanels =_chanels;
bits =_bits;
samples =_samples;
buff_size=(chanels*bits*samples)>>3;
samples=(buff_size<<3)/(chanels*bits);
for (i=0;i<buffers;i++) buff[i]=new BYTE[buff_size];
#ifdef _mmap_h
for (i=0;i<buffers;i++) if (buff[i]) mmap_new(buff[i],buff_size);
#endif
buff_format.wFormatTag =WAVE_FORMAT_PCM; // set buffer format
buff_format.nChannels =chanels;
buff_format.nSamplesPerSec =freq;
buff_format.wBitsPerSample =bits;
buff_format.cbSize =0;
buff_format.nAvgBytesPerSec =(freq*chanels*bits)>>3;
buff_format.nBlockAlign =(chanels*bits)>>3;
if (event) ret=waveInOpen(&hw,WAVE_MAPPER,&buff_format,(DWORD_PTR)event,(DWORD_PTR)this,CALLBACK_FUNCTION);
else ret=waveInOpen(&hw,WAVE_MAPPER,&buff_format,0,0,CALLBACK_NULL);
if (ret!=MMSYSERR_NOERROR)
{
// waveInGetErrorText(ret,err,255);
return;
}
WAVEHDR hdr0;
hdr0.dwBufferLength=buff_size;
hdr0.dwUser=0;
hdr0.dwFlags=0;
hdr0.dwLoops=0;
hdr0.lpNext=NULL;
for (i=0;i<buffers;i++)
{
hdr[i]=hdr0;
hdr[i].lpData=buff[i];
}
_init=true;
}
void add()
{
if (!_init) return;
int i,ret;
BYTE *p;
p=buff[adr];
ret=waveInPrepareHeader(hw,&hdr[adr],sizeof(WAVEHDR));
if (ret!=MMSYSERR_NOERROR)
{
// waveInGetErrorText(ret,err,255);
return;
}
waveInAddBuffer(hw,&hdr[adr],sizeof(WAVEHDR));
if (ret!=MMSYSERR_NOERROR)
{
// waveInGetErrorText(ret,err,255);
return;
}
adr++;
if (adr>=buffers) adr=0;
num++;
}
void start()
{
if (!_init) return;
while (num<buffers) add();
waveInStart(hw);
}
void stop()
{
if (!_init) return;
waveInStop(hw);
}
};
//---------------------------------------------------------------------------
class wave_out:public multi_lock
{
public:
bool _init,_fifo;
FIFO<BYTE> fifo;
WAVEHDR *hdr;
HWAVEOUT hw;
WAVEFORMATEX buff_format;
DWORD buff_size;
DWORD freq; WORD chanels,bits,samples,buffers;
BYTE **buff;
int adr,num,err;
void CALLBACK (*event)(HWAVEOUT hw,UINT msg,DWORD inst,DWORD p1,DWORD p2);
wave_out()
{
hdr=NULL;
buff=NULL;
buffers=0;
buff_size=0;
_init=false;
adr=0;
num=0;
err=0;
event=wave_out_event;
}
~wave_out()
{
_free();
}
wave_out(wave_out& a) { *this=a; }
wave_out* operator = (const wave_out *a) { *this=*a; return this; }
//wave_out* operator = (const wave_out &a) { ...copy... return this; }
void _free()
{
adr=0;
num=0;
if (_init) { waveOutClose(hw); _init=false; }
#ifdef _mmap_h
if (buff) for (int i=0;i<buffers;i++) if (buff[i]) mmap_del(buff[i]);
if (buff) mmap_del(buff);
if (hdr ) mmap_del(hdr );
#endif
if (buff)
{
for (int i=0;i<buffers;i++) if (buff[i]) delete[] buff[i];
delete[] buff;
buff=NULL;
}
if (hdr) { delete[] hdr; hdr=NULL; }
}
void init(DWORD _freq,WORD _chanels,WORD _bits,WORD _samples,WORD _buffers=10)
{
int i,ret;
_free();
buffers=_buffers;
if (buffers<1) buffers=1;
hdr=new WAVEHDR[buffers];
buff=new BYTE*[buffers];
#ifdef _mmap_h
if (hdr ) mmap_new(hdr ,buffers*sizeof(WAVEHDR));
if (buff) mmap_new(buff,buffers*sizeof(BYTE*));
#endif
freq =_freq;
chanels =_chanels;
bits =_bits;
samples =_samples;
buff_size=(chanels*bits*samples)>>3;
samples=(buff_size<<3)/(chanels*bits);
for (i=0;i<buffers;i++) buff[i]=new BYTE[buff_size];
#ifdef _mmap_h
for (i=0;i<buffers;i++) if (buff[i]) mmap_new(buff[i],buff_size);
#endif
buff_format.wFormatTag =WAVE_FORMAT_PCM; // set buffer format
buff_format.nChannels =chanels;
buff_format.nSamplesPerSec =freq;
buff_format.wBitsPerSample =bits;
buff_format.cbSize =0;
buff_format.nAvgBytesPerSec =(freq*chanels*bits)>>3;
buff_format.nBlockAlign =(chanels*bits)>>3;
if (event) ret=waveOutOpen(&hw,WAVE_MAPPER,&buff_format,(DWORD_PTR)event,(DWORD_PTR)this,CALLBACK_FUNCTION);
else ret=waveOutOpen(&hw,WAVE_MAPPER,&buff_format,0,0,CALLBACK_NULL);
if (ret!=MMSYSERR_NOERROR)
{
// waveOutGetErrorText(ret,err,255);
return;
}
WAVEHDR hdr0;
hdr0.dwBufferLength=buff_size;
hdr0.dwUser=0;
hdr0.dwFlags=WHDR_INQUEUE;
hdr0.dwLoops=0;
hdr0.lpNext=NULL;
for (i=0;i<buffers;i++)
{
hdr[i]=hdr0;
hdr[i].lpData=buff[i];
}
_init=true;
}
void send(BYTE *data)
{
if (!_init) return;
lock();
if (num>buffers)
{
err++;
adr=0;
num=0;
}
DWORD i;
int ret;
BYTE *p;
p=buff[adr];
for (i=0;i<buff_size;i++) p[i]=data[i];
ret=waveOutPrepareHeader(hw,&hdr[adr],sizeof(WAVEHDR));
if (ret!=MMSYSERR_NOERROR)
{
// waveOutGetErrorText(ret,err,255);
unlock();
return;
}
waveOutWrite(hw,&hdr[adr],sizeof(WAVEHDR));
if (ret!=MMSYSERR_NOERROR)
{
// waveOutGetErrorText(ret,err,255);
unlock();
return;
}
adr++;
if (adr>=buffers) adr=0;
num++;
unlock();
}
void stop()
{
waveOutReset(hw);
}
};
//---------------------------------------------------------------------------
void CALLBACK wave_in_event(HWAVEIN hw,UINT msg,DWORD inst,DWORD p1,DWORD p2)
{
wave_in *w=(wave_in*)(void*)(DWORD_PTR)inst;
if (w==NULL) return;
if (msg==WIM_OPEN); // open wave HW
if (msg==WIM_DATA) // wave data send done
{
int adr0=w->adr-w->num;
while (adr0>=w->buffers) adr0-=w->buffers;
while (adr0< 0) adr0+=w->buffers;
if (w->onreceive) w->onreceive(w,w->buff[adr0],w->buff_size);
w->num--;
}
if (msg==WIM_CLOSE); // close wave HW
}
//---------------------------------------------------------------------------
void CALLBACK wave_out_event(HWAVEOUT hw,UINT msg,DWORD inst,DWORD p1,DWORD p2)
{
wave_out *w=(wave_out*)(void*)(DWORD_PTR)inst;
if (w==NULL) return;
w->lock();
if (msg==WOM_OPEN); // open wave HW
if (msg==WOM_DONE) w->num--; // wave data send done
if (msg==WOM_CLOSE); // close wave HW
w->unlock();
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
支持文件lock.h:
//---------------------------------------------------------------------------
//--- Multithread lock class ver 1.00 ---------------------------------------
//---------------------------------------------------------------------------
#ifndef _lock_h
#define _lock_h
//---------------------------------------------------------------------------
class single_lock
{
public:
CRITICAL_SECTION hnd;
single_lock() { InitializeCriticalSectionAndSpinCount(&hnd,0x00000400); }
~single_lock() { DeleteCriticalSection(&hnd); }
single_lock(single_lock& a) { *this=a; }
single_lock* operator = (const single_lock *a) { *this=*a; return this; }
// single_lock* operator = (const single_lock &a) { **** }
// thread safe functions
inline void lock() { EnterCriticalSection(&hnd); }
inline void unlock() { LeaveCriticalSection(&hnd); }
};
//---------------------------------------------------------------------------
const int _multi_lock_size=16; // max number of simultanious access
class multi_lock
{
public:
CRITICAL_SECTION hnd;
CRITICAL_SECTION dat[_multi_lock_size];
DWORD adr0,adr1,siz;
multi_lock() { InitializeCriticalSectionAndSpinCount(&hnd,0x00000400); for(int i=0;i<_multi_lock_size;i++) InitializeCriticalSectionAndSpinCount(&dat[i],0x00000400); adr0=0; adr1=0; siz=0; }
~multi_lock() { DeleteCriticalSection(&hnd); for(int i=0;i<_multi_lock_size;i++) DeleteCriticalSection(&dat[i]); }
multi_lock(multi_lock& a) { *this=a; }
multi_lock* operator = (const multi_lock *a) { *this=*a; return this; }
// multi_lock* operator = (const multi_lock &a) { **** }
// thread safe functions
inline void lock()
{
EnterCriticalSection(&hnd);
if (siz<_multi_lock_size)
{
siz++;
EnterCriticalSection(&dat[adr1]);
adr1++; if (adr1>=_multi_lock_size) adr1=0;
}
// else error();
LeaveCriticalSection(&hnd);
}
inline void unlock()
{
EnterCriticalSection(&hnd);
if (siz>0)
{
siz--;
LeaveCriticalSection(&dat[adr0]);
adr0++; if (adr0>=_multi_lock_size) adr0=0;
}
// else error();
LeaveCriticalSection(&hnd);
}
};
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
支持文件FIFO.h:
//---------------------------------------------------------------------------
//--- FIFO template class ver 2.08 ------------------------------------------
//---------------------------------------------------------------------------
#ifndef _fifo_h
#define _fifo_h
//---------------------------------------------------------------------------
//static bool _enable_fifo_debug=false;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
template <class T> class FIFO
{
public:
T *dat;
int adr0,adr1,size;
CRITICAL_SECTION lock;
FIFO() { dat=NULL; InitializeCriticalSectionAndSpinCount(&lock,0x00000400); alloc(16); }
~FIFO() { _free(); DeleteCriticalSection(&lock); }
FIFO(FIFO& a) { *this=a; }
FIFO* operator = (const FIFO *a){ *this=*a; return this; }
FIFO* operator = (const FIFO &a){ EnterCriticalSection(&a.lock); EnterCriticalSection(&lock); _alloc(a.size); adr0=a.adr0; adr1=a.adr1; for (int i=0;i<size;i++) dat[i]=a.dat[i]; LeaveCriticalSection(&lock); LeaveCriticalSection(&a.lock); return this; }
// already locked functions
inline int _adr_inc(int a) volatile { a++; if (a>=size) a=0; return a; }
inline int _adr_dec(int a) volatile { if (a!=adr0) a--; if (a<0) a=size-1; return a; }
inline void _alloc(int _size)volatile { if (dat) delete[] dat; dat=NULL; size=_size; adr0=0; adr1=0; dat=new T[size]; if (dat==NULL) size=0; _reset(); }
inline void _free() volatile { if (dat) delete[] dat; dat=NULL; size= 0; adr0=0; adr1=0; }
inline void _reset() volatile { adr0=0; adr1=0; }
inline void _in(T x) volatile { if (_is_full()) return; dat[adr1]=x; adr1=_adr_inc(adr1); }
inline T _out() volatile { if (_is_empty()){ T null; return null; } T x=dat[adr0]; adr0=_adr_inc(adr0); return x; }
inline T _peek_first() volatile { if (_is_empty()){ T null; return null; } T x=dat[adr0]; return x; }
inline T _peek_last() volatile { if (_is_empty()){ T null; return null; } int a=_adr_dec(adr1); T x=dat[a]; return x; }
inline bool _is_empty() volatile { bool ret=(adr0==adr1); return ret; }
inline bool _is_full() volatile { int a=_adr_inc(adr1); bool ret=(a==adr0); return ret; }
inline int _get_size() volatile { if (_is_empty()) return 0; if (_is_full()) return size; if (adr0<adr1) return adr1-adr0; else return size+adr1-adr0; }
// thread safe functions
void _lock() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); }
void _unlock() volatile { LeaveCriticalSection((CRITICAL_SECTION*)&lock); }
void alloc(int _size) volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); _alloc(_size); LeaveCriticalSection((CRITICAL_SECTION*)&lock); }
void reset() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); _reset(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); }
void in(T x) volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); _in(x); LeaveCriticalSection((CRITICAL_SECTION*)&lock); }
T out() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); T x=_out(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
T peek_first() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); T x=_peek_first(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
T peek_last() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); T x=_peek_last(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
bool is_empty() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); bool x=_is_empty(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
bool is_full() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); bool x=_is_full(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
int get_size() volatile { EnterCriticalSection((CRITICAL_SECTION*)&lock); int x=_get_size(); LeaveCriticalSection((CRITICAL_SECTION*)&lock); return x; }
};
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
这里有简单的用法(从我的生成器中提取,希望我没有忘记任何东西):
// globals and init
const int _size=20*1024;
wave_out wo;
WORD buffer[_size]; // your PCM sound data matching the init operands
wo.init(44100,2,16,_size,10); // sampling_freq,channels,bits,buffer size,buffers
// this in some timer or thread (fast enbough)
while (wo.num<4)
{
// here prepare buff[] data
wo.send((BYTE*)buff);
}
// force to stop on app exit or when needed
wo.stop();
这些内容是在 BDS2006 C++ Builder 上编译的,因此如果您使用较新的编译器,您可能需要调整一些内容...还没有时间将其移植到新编译器,因此如果情况请参阅this。
wave_out
用于声音播放,wave_in
用于录音,两者都使用在 Windows 控制面板中选择的首选 Windows 声音设备。为了实现流畅播放,只需确保声音队列中至少填充了 4 个缓冲区while (wo.num<4)
...否则可能会出现声音故障
您可能还需要解码 WAV 文件,所以这里是我的另一个古老的库RIFF.h:
//---------------------------------------------------------------------------
//--- RIFF WAVE format: 1.01 ------------------------------------------------
//---------------------------------------------------------------------------
#ifndef _RIFF_h
#define _RIFF_h
//---------------------------------------------------------------------------
// 8bit PCM is unsigned
// 16bit PCM is signed 2'os complement little endian (big endian is RIFX)
//---------------------------------------------------------------------------
struct _wave_chunk
{
DWORD ids;
DWORD len;
_wave_chunk(){ ids=' '; len=0; }
_wave_chunk(_wave_chunk& a){ *this=a; }; ~_wave_chunk(){}; _wave_chunk* operator = (const _wave_chunk *a) { *this=*a; return this; }; /*_wave_chunk* operator = (const _wave_chunk &a) { ...copy... return this; };*/
};
struct _wave_hdr
{
DWORD ids; // "RIFF"
DWORD len;
DWORD tps; // "WAVE"
_wave_hdr(){ ids='FFIR'; len=0; tps='EVAW'; }
_wave_hdr(_wave_hdr& a){ *this=a; }; ~_wave_hdr(){}; _wave_hdr* operator = (const _wave_hdr *a) { *this=*a; return this; }; /*_wave_hdr* operator = (const _wave_hdr &a) { ...copy... return this; };*/
};
struct _wave_fmt
{
DWORD ids; // "fmt "
DWORD len; // 16,18,40
WORD format; // 1 = PCM linear quantization
/* 0x0001 WAVE_FORMAT_PCM PCM
0x0003 WAVE_FORMAT_IEEE_FLOAT IEEE float
0x0006 WAVE_FORMAT_ALAW 8-bit ITU-T G.711 A-law
0x0007 WAVE_FORMAT_MULAW 8-bit ITU-T G.711 µ-law
0xFFFE WAVE_FORMAT_EXTENSIBLE Determined by SubFormat */
WORD chanels;
DWORD samplerate;
DWORD byterate;
WORD blockalign;
WORD bits;
WORD ext_len; // extension length 0,22
WORD ext_validbits;
DWORD ext_channelmask;
BYTE ext_subformat[16];
_wave_fmt(){ ids=' tmf'; len=16; format=1; chanels=1; samplerate=44100; bits=8; ext_len=0; ext_validbits=0; ext_channelmask=0; for (int i=0;i<16;i++) ext_subformat[i]=0; compute(); }
_wave_fmt(_wave_fmt& a){ *this=a; }; ~_wave_fmt(){}; _wave_fmt* operator = (const _wave_fmt *a) { *this=*a; return this; }; /*_wave_fmt* operator = (const _wave_fmt &a) { ...copy... return this; };*/
void compute()
{
byterate=(chanels*samplerate*bits)/8;
blockalign=(chanels*bits)/8;
}
};
struct _wave_dat
{
DWORD ids; // "data"
DWORD len;
_wave_dat(){ ids='atad'; len=0; }
_wave_dat(_wave_dat& a){ *this=a; }; ~_wave_dat(){}; _wave_dat* operator = (const _wave_dat *a) { *this=*a; return this; }; /*_wave_dat* operator = (const _wave_dat &a) { ...copy... return this; };*/
};
//---------------------------------------------------------------------------
class wave
{
public:
AnsiString name;
int hnd;
bool readonly;
_wave_hdr hdr;
_wave_fmt fmt;
_wave_dat dat;
wave();
~wave();
void create(AnsiString _name);
void write(BYTE *data,DWORD size);
bool open(AnsiString _name);
DWORD read(BYTE *data,DWORD size);
void close();
};
//---------------------------------------------------------------------------
wave::wave()
{
name=0;
hnd=-1;
readonly=true;
}
//---------------------------------------------------------------------------
wave::~wave()
{
close();
}
//---------------------------------------------------------------------------
void wave::create(AnsiString _name)
{
close();
readonly=true;
// hdr=_wave_hdr();
// fmt=_wave_fmt();
// dat=_wave_dat();
hdr.len=sizeof(hdr)-8;
dat.len=0;
fmt.compute();
name=_name;
hnd=FileCreate(name);
if (hnd<0) return;
FileWrite(hnd,&hdr,sizeof(hdr));
FileWrite(hnd,&fmt,fmt.len+8);
FileWrite(hnd,&dat,sizeof(dat));
readonly=false;
}
//---------------------------------------------------------------------------
bool wave::open(AnsiString _name)
{
close();
readonly=true;
name=_name;
hnd=FileOpen(name,fmOpenRead);
if (hnd<0) return false;
if (FileRead(hnd,&hdr,sizeof(hdr))<sizeof(hdr)){ close(); return false; }
if (hdr.ids!='FFIR') return false;
if (hdr.tps!='EVAW') return false;
_wave_chunk chk;
DWORD sz=sizeof(chk),l;
for(;;)
{
if (FileRead(hnd,&chk,sz)<sz){ close(); return false; }
if (chk.ids==' tmf')
{
fmt.ids=chk.ids;
fmt.len=chk.len;
if (FileRead(hnd,((BYTE*)&fmt)+sz,chk.len)<chk.len){ close(); return false; }
}
else if (chk.ids=='atad')
{
dat.ids=chk.ids;
dat.len=chk.len;
return true;
}
else FileSeek(hnd,int(chk.len),1);
}
}
//---------------------------------------------------------------------------
void wave::write(BYTE *data,DWORD size)
{
if (hnd<0) return;
hdr.len+=size;
dat.len+=size;
if (!readonly) FileWrite(hnd,data,size);
}
//---------------------------------------------------------------------------
DWORD wave::read(BYTE *data,DWORD size)
{
if (hnd<0) return 0;
return FileRead(hnd,data,size);
}
//---------------------------------------------------------------------------
void wave::close()
{
name="";
if (hnd<0) return;
FileSeek(hnd,0,0);
if (!readonly) FileWrite(hnd,&hdr,sizeof(hdr));
FileClose(hnd);
hnd=-1;
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
及用法:
// globals
wave wav;
wave_out wo;
BYTE *buff;
// init
wav.open("tetris2.wav"); // any file ...
wo.init(wav.fmt.samplerate,wav.fmt.chanels,wav.fmt.bits,dt*wav.fmt.samplerate/1000,10);
buff=new BYTE[wo.buff_size];
// timer 20ms ...
while (wo.num<4)
{
wav.read(buff,wo.buff_size);
wo.send(buff);
}
// exit
wo.stop();
wav.close();
delete[] buff;
wav.read(...)
返回读取的字节数,因此一旦它小于缓冲区大小甚至等于零,则意味着您已经处于波形文件末尾...现在,由于您将在内存中拥有wav,因此只需重写对内存的文件访问即可访问...