那里能下载到直接用声卡录的音转换为WAV的函数。(利用内存录音并在内存中转换)(100分)

  • 主题发起人 主题发起人 wgd2001
  • 开始时间 开始时间
W

wgd2001

Unregistered / Unconfirmed
GUEST, unregistred user!
那里能下载到直接用声卡录的音转换为WAV的函数。(利用内存录音并在内存中转换)。
 
不用控件呀,直接用API就可以了,给你的个录制WAVE的函数:

//***********************************************************************//
// //
// 开始录音 //
// 参数: 无 //
// 返回值: 无 //
// //
//***********************************************************************//

procedure TCMRecordWave.Start;
var
RecordWaveBuf: PChar;
// 音频数据保存的缓存
RecordHDr: TWAVEHDR;
// 音频信息头
tm: TMMTime;
// 已录音多长时间
Diff: Longint;
// 音频数据的长度
TempFile: Integer;
// 临时文件句柄
// Flag: Integer;
// 波形显示周期
begin

if not ((Self.NowRecord = CRNONE) or (Self.NowRecord = CRSTOPING)) then

Exit;
Self.FNowRecord := CRRECORDING;
// 正在录音
TempFile := FileCreate(Self.TempFileName);
// 创建一个临时文件用于保存录音数据

//设置音频文件头
Self.TRecordHdr.wFormatTag := WAVE_FORM_FORMAT_TAG;
// 格式类型
Self.TRecordHdr.nChannels := WAVE_FORM_CHANNELS;
// 声道数据
Self.TRecordHdr.nSamplesPerSec := WAVE_FORM_SAMPLES_PER_SEC;
// 采样频率
Self.TRecordHdr.nAvgBytesPerSec := WAVE_FORM_AVG_BYTE_PER_SEC;
// 平均数据传输率
Self.TRecordHdr.wBitsPerSample := WAVE_FORM_BITS_PER_SAMPLE;
// 采样数据的大小
Self.TRecordHdr.nBlockAlign := WAVE_FORM_BLOCK_ALIGN;
// 块对齐方式
Self.TRecordHdr.cbSize := WAVE_FORM_CBSIZE;
// 加在本结构后的格式数据的大小

//打开音频输入设备
WaveInOpen(@Self.hwi, WAVE_MAPPER, @Self.TRecordHdr, 0, 0, CALLBACK_NULL);
// 定义要录制的格式
try
//开辟内存
RecordWaveBuf := PChar(GlobalAllocPtr(GMEM_MOVEABLE or GMEM_SHARE,
WAVE_REC_BUFFER_LENGTH));

try // 设置信息头
RecordHDr.lpData := RecordWaveBuf;
RecordHDr.dwBufferLength := WAVE_REC_BUFFER_LENGTH;
RecordHDr.dwFlags := 0;
// 生成信息头(prepares a buffer for waveform-audio input)
WaveInPrepareHeader(Self.hwi, @RecordHDr, SizeOf(TWAVEHDR));
// 增加数据缓冲(sends an input buffer to the given waveform-audio input device)
WaveInAddBuffer(Self.hwi, @RecordHDr, SizeOf(TWAVEHDR));

WaveInStart(Self.hwi);
// 开始录音
Self.FileSize := 0;
// 音频数据长度
while Self.NowRecord <> CRSTOPINGdo

begin
// 没有停止
Application.ProcessMessages;
// 处理消息
if ((RecordHDr.dwFlags and WHDR_DONE) <> 0) then
// 数据缓冲已填满
begin

tm.wType := TIME_BYTES;
WaveInGetPosition(Self.hwi, @tm, SizeOf(TMMTime));
// 取当前播放位置
Diff := Longint(tm.cb) - Self.FileSize;
// 数据长度
Self.FileSize := Longint(tm.cb);
{ Flag := Diff div 2 div Self.FDrawWave.ClientWidth + 1;
// 波形显示周期
if Flag <= 0 then

Flag := 1;
if (Self.DrawWave <> nil) and (Self.DesBMP <> nil) then
// 画波形
DrawPartWave(Flag, RecordWaveBuf, Diff, Self.FDrawWave.Canvas,
Self.FDrawWave.ClientHeight, Self.FDrawWave.ClientWidth,
Self.FDesBMP, Self.FDrawLineColor, Self.FDrawBackColor);
} FileWrite(TempFile, RecordWaveBuf^, Diff);
// 写入临时文件中
waveInAddBuffer(Self.hwi, @RecordHDr, SizeOf(TWAVEHDR));
// 增加一 数据缓冲区
end;

end;

// 再次保存数据
tm.wType := TIME_BYTES;
WaveInGetPosition(Self.hwi, @tm, SizeOf(TMMTime));
// 取当前播放位置
Diff := Longint(tm.cb) - Self.FileSize;
// 数据长度
Self.FileSize := Longint(tm.cb);
FileWrite(TempFile, RecordWaveBuf^, Diff);
// 写入临时文件中
// waveInAddBuffer(Self.hwi, @RecordHDr, SizeOf(TWAVEHDR));
// 增加一 数据缓冲区

WaveInReset(Self.hwi);
// 停止录音
WaveInUnPrepareHeader(Self.hwi, @RecordHDr, SizeOf(TWAVEHDR));
// 清除信息头
finally
GloBalFreePtr(RecordWaveBuf);
// 释放内存
FileClose(TempFile);
// 关闭文件
end;

finally
WaveInClose(Self.hwi);
// 关闭音频输入设备
Self.FNowRecord := CRSTOPING;
end;


if FileExists(Self.FWaveFileName) then

DeleteFile(Self.FWaveFileName);
// 删除临时音频文件

// 保存为音频文件
if Self.FSaveFileName = '' then

Wave_SaveFile(Self.FWaveFileName, Self.TempFileName, Self.FileSize,
Self.TRecordHdr, 0, CS_SAVE_RECORD)
else

Wave_SaveFile(Self.FSaveFileName, Self.TempFileName, Self.FileSize,
Self.TRecordHdr, 0, CS_SAVE_RECORD);
Self.FNowRecord := CRNONE;
end;
 
高手。。。学习中。。。

用控件的话 用的DelphiX
在DelphiX/Samples/Sound/HDRecorder有例程
可以从很多Source录音...


 
谢谢qince,我试一下啊。
 
着重看看函数中的几个API,你就明白怎么录音了。
 
Wave_SaveFile
函数在哪里?
请大家帮忙找找
 
找到 Wave_SaveFile 函数立即分分。
 
//***********************************************************************//
// //
// 保存音频文件 //
// 参数: //
// FileName : 要保存的文件名 //
// TempFileName : 源文件名 ( 在录音状态下保存文件有效 ) //
// DataLength : 音频数据的长度 //
// WaveFmt : 波形格式 //
// Dhio : 源音频文件名柄 ( 在放音状态下保存文件有效 ) //
// tSave : 在何种状态下保存文件 //
// StartPoi : 要保存的音频数据的起始位置 //
// SaveLength : 要保存的音频数据的长度( 如果为 0 则全部保存 ) //
// 说明: //
// StartPoi , SaveLength 只在放音状态下保存时有效 //
// 返回值: 无 //
// //
//***********************************************************************//

procedure Wave_SaveFile(const FileName, TempFileName: string;
DataLength:
LongInt;
WaveFmt: TWAVEFORMATEX;
Dhio: HMMIO;
tSave: TSave_Type;
const StartPoi: LongInt = 0;
const SaveLength: LongInt = 0);
var
hio: HMMIO;
//音频文件句柄
Buf: PChar;
//用于读取数据的缓冲区
ck: TMMCKINFO;
//音频信息结构
SaveLoop: LongInt;
//循环读取数据的次数
Length: LongInt;
//要保存数据的长度
i: LongInt;
MODSaveSize: LongInt;
//最后一次数据的长度
SaveSize: LongInt;
//要写入文件的数据的长度
TempFile: Integer;
//临时文件句柄 ( 在录音状态下时有效 )
SaveStartPoi: LongInt;
//保存数据在文件中的开始处
begin

Application.ProcessMessages;
//处理 Windows 消息

TempFile := 0;

if (tSave = CS_SAVE_PLAY) and (SaveLength > 0) and (StartPoi < DataLength)
and (StartPoi > 0) and ((StartPoi + SaveLength) <= DataLength) and (StartPoi
< DataLength) then

begin

Length := SaveLength;
SaveStartPoi := StartPoi;
end
else

begin

Length := DataLength;
SaveStartPoi := 0;
end;

SaveLoop := Length div LoadMemSize;
MODSaveSize := 0;
if (Length mod LoadMemSize) <> 0 then

begin

SaveLoop := SaveLoop + 1;
MODSaveSize := Length mod LoadMemSize;
end;


if tSave <> CS_SAVE_NEW then

SendMessage(Application.MainForm.Handle, CM_begin
SAVE, SaveLoop, 0);

if FileExists(FileName) then
//删除已有的目标文件
DeleteFile(FileName);

//创建成一个新的音频文件
hio := mmioOpen(PChar(FileName), nil, MMIO_CREATE + MMIO_READWRITE);
if hio = 0 then

raise EMMIO.Create('无法创建文件');
try
if WaveFmt.wFormatTag = WAVE_FORMAT_PCM then
//波形格式的大小
ck.cksize := Length + 4 + 8 + SizeOf(WaveFmt) - 2 + 8 // Length: 文件大小
else

ck.cksize := Length + 4 + 8 + SizeOf(WaveFmt) + WaveFmt.cbSize + 8;

ck.fccType := mmioStringToFOURCC('WAVE', 0);
//创建文件头
if 0 <> mmioCreateChunk(hio, @ck, MMIO_CREATERIFF) then

raise EMMIO.Create('建立文件头错误');
// 创建fmt chunks
ck.ckid := mmioStringToFOURCC('fmt', 0);
//创建 fmt 块
if WaveFmt.wFormatTag = WAVE_FORMAT_PCM then

ck.cksize := SizeOf(WaveFmt) - 2 //fmt 块的大小
else

ck.cksize := SizeOf(WaveFmt) + WaveFmt.cbSize;

if 0 <> mmioCreateChunk(hio, @ck, 0) then

raise EMMIO.Create('建立 fmt 块错误');
mmioWrite(hio, PChar(@WaveFmt), ck.cksize);
// 创建data chunks
ck.ckid := mmioStringToFOURCC('data', 0);
//创建 data 数据块
ck.cksize := Length;
// Length: 文件大小
if 0 <> mmioCreateChunk(hio, @ck, 0) then

raise EMMIO.Create('建立 data 块错误');

if tSave = CS_SAVE_NEW then

begin

mmioClose(hio, 0);
//关闭目标音频文件
Exit;
end;


case tSave of //把文件指针移到指定位置
CS_SAVE_PLAY: mmioSeek(Dhio, DataLength - SaveStartPoi, SEEK_END);
CS_SAVE_RECORD:
begin

TempFile := FileOpen(TempFileName, fmOpenRead);
//以只读方式打开文件
if TempFile = 0 then

raise EMMIO.Create('数据读取错误');
end;

end;


for i := 1 to SaveLoopdo

begin

if (MODSaveSize <> 0) and (i = SaveLoop) then

begin

//开辟内存
Buf := PChar(GlobalAllocPtr(GMEM_MOVEABLE or GMEM_SHARE, MODSaveSize));
SaveSize := MODSaveSize;
//要播放的音频数据的长度
end
else

begin

Buf := PChar(GlobalAllocPtr(GMEM_MOVEABLE or GMEM_SHARE, LoadMemSize));
SaveSize := LoadMemSize;
end;

try
if Buf = nil then

raise EMMIO.Create('不能分配内存!');
try //读取与写音频数据
case tSave of
CS_SAVE_PLAY:
if mmioRead(Dhio, Buf, SaveSize) <> SaveSize then

raise EMMIO.Create('读取数据出错:可能文件已被破坏!');
CS_SAVE_RECORD:
begin

if FileRead(TempFile, Buf^, SaveSize) <> SaveSize then

raise EMMIO.Create('读取数据出错:可能文件已被破坏!');
end;

end;

if SaveSize <> mmioWrite(hio, Buf, SaveSize) then

raise EMMIO.Create('写语音数据错误');
finally
GloBalFreePtr(Buf);
//释放内存
SendMessage(Application.MainForm.Handle, CM_SAVEPOSI, i, 0);
end;

finally
end;

end;

finally
if tSave = CS_SAVE_RECORD then

FileClose(TempFile);
//关闭临时文件
mmioClose(hio, 0);
//关闭目标音频文件
end;

//发送保存完毕的消息
SendMessage(Application.MainForm.Handle, CM_ENDSAVE, 0, 0);
end;
 
接受答案了.
 
后退
顶部