📄 tcmwavetype.pas
字号:
//开辟内存
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:
if FileRead(TempFile, Buf^, SaveSize) <> SaveSize then
raise EMMIO.Create('读取数据出错:可能文件已被破坏!');
end;
if SaveSize <> mmioWrite(hio, Buf, SaveSize) then
raise EMMIO.Create('写语音数据错误');
Finally
GloBalFreePtr(Buf); //释放内存
SendMessage(Application.MainForm.Handle, CM_SAVEPOSI, i, 0);
end;
Finally
FileClose(TempFile); //关闭临时文件
end;
end;
Finally
mmioClose(hio, 0); //关闭目标音频文件
end;
//发送保存完毕的消息
SendMessage(Application.MainForm.Handle, CM_ENDSAVE, 0, 0);
end;
//***********************************************************************//
// //
// 转换音频数据到文件 //
// 参数: //
// NewFileName : 要保存的文件名 //
// DataLength : 转换前的音频数据的长度 //
// NewWaveFmt : 新的波形格式 //
// OldWaveFmt : 旧的波形格式 //
// Dhio : 源音频文件名柄 ( 在放音状态下保存文件有效 ) //
// ShowPoi : 回调过程 //
// 返回值: //
// 新的音频长度 //
// //
//***********************************************************************//
function Wave_Save_ConvertFile(const NewFileName: String; DataLength: LongInt;
NewWaveFmt, OldWaveFmt: TWAVEFORMATEX; Dhio: HMMIO; ShowPoi: TWaveLoopNotifyEvent): LongInt;
var
hio: HMMIO; //音频文件句柄
Buf: PChar; //用于读取数据的缓冲区
SaveBuf: PChar;
ck: TMMCKINFO; //音频信息结构
SaveLoop: LongInt; //循环读取数据的次数
Length: LongInt; //要保存数据的长度
NewLength: LongInt;
i, j: LongInt;
MODSaveSize: LongInt; //最后一次数据的长度
SaveSize: LongInt; //要写入文件的数据的长度
begin
i := DataLength div OldWaveFmt.nBlockAlign; //音频块对齐方式
//转换比例
j := Trunc(NewWaveFmt.nSamplesPerSec / OldWaveFmt.nSamplesPerSec * i);
Length := NewWaveFmt.nBlockAlign * j; //新的音频数据的长度
SaveLoop := DataLength DIV LoadMemSize;
MODSaveSize := 0;
if (DataLength MOD LoadMemSize) <> 0 then
begin
SaveLoop := SaveLoop + 1;
MODSaveSize := DataLength MOD LoadMemSize;
end;
if FileExists(NewFileName) then //删除已有的目标文件
DeleteFile(NewFileName);
//创建成一个新的音频文件 创建 可读写
hio := mmioOpen(PChar(NewFileName), NIL, MMIO_CREATE + MMIO_READWRITE);
if hio = 0 then
raise EMMIO.Create('无法创建文件');
Try //WAVE_FORMAT_PCM 自定义音频格式
if NewWaveFmt.wFormatTag = WAVE_FORMAT_PCM then //波形格式的大小
ck.cksize := Length + 4 + 8 + SizeOf(NewWaveFmt) - 2 + 8
else
ck.cksize := Length + 4 + 8 + SizeOf(NewWaveFmt) + NewWaveFmt.cbSize + 8;
ck.fccType := mmioStringToFOURCC('WAVE', 0); //创建文件头
if 0 <> mmioCreateChunk(hio, @ck, MMIO_CREATERIFF) then
raise EMMIO.Create('建立文件头错误');
ck.ckid := mmioStringToFOURCC('fmt', 0); //创建 fmt 块
if NewWaveFmt.wFormatTag = WAVE_FORMAT_PCM then
ck.cksize := SizeOf(NewWaveFmt) - 2 //fmt 块的大小
else
ck.cksize := SizeOf(NewWaveFmt) + NewWaveFmt.cbSize;
if 0 <> mmioCreateChunk(hio, @ck, 0) then
raise EMMIO.Create('建立 fmt 块错误');
mmioWrite(hio, PChar(@NewWaveFmt), ck.cksize);
ck.ckid := mmioStringToFOURCC('data', 0); //创建 data 数据块
ck.cksize := Length;
if 0 <> mmioCreateChunk(hio, @ck, 0) then
raise EMMIO.Create('建立 data 块错误');
for i := 1 to SaveLoop do
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 //读取与写音频数据
if mmioRead(Dhio, Buf, SaveSize) <> SaveSize then
raise EMMIO.Create('读取数据出错:可能文件已被破坏!');
SaveBuf := NIL;
//转换数据
NewLength := ConvertWave(Buf, SaveSize, OldWaveFmt, SaveBuf, NewWaveFmt);
if NewLength <= 0 then
raise EMMIO.Create('语音格式转换错误');
if NewLength <> mmioWrite(hio, SaveBuf, NewLength) then
raise EMMIO.Create('写语音数据错误');
Finally
// GloBalFreePtr(SaveBuf); //释放空间
if Assigned(ShowPoi) then //显示进度
ShowPoi(WA_EN_OPENFILE, 100, 0, (70 DIV SaveLoop) * i + 20);
ReallocMem(SaveBuf, 0); //清除内存
GloBalFreePtr(Buf); //释放内存
// Buf := NIL;
end;
Finally
end;
end;
Finally
mmioClose(hio, 0); //关闭目标音频文件
end;
Result := Length;
end;
//***********************************************************************//
// //
// 画局部音频数据的波形 //
// 参数: //
// Flag : 波形显示周期 //
// Buf : 音频数据 //
// Length : 音频数据的长度 //
// DesCanvas : 要显示波形的目标画布 //
// DH, DW : 目标画布的工作区域的高度与宽度 //
// DesBitMap : 画波形时用的非可视源位图对像 //
// DrawLineColor : 画波形的颜色 //
// DrawBackColor : 画波形的背景颜色 //
// Draw : 是否画波形 //
// 返回值: 无 //
// //
//***********************************************************************//
procedure DrawPartWave(const Flag: Integer; Buf: PChar; Length: LongInt;
DesCanvas: TCanvas; DH, DW: SmallInt; DesBitMap: TBitMap;
DrawLineColor, DrawBackColor: TColor; Draw: Boolean = True);
var
i, j, k, lmax, lmin: LongInt;
Max, Min: LongInt;
X, Y: SmallInt;
begin
with DesBitMap do //初始化图像参数
begin
Width := DW;
Height := DH;
Canvas.Brush.Color := DrawBackColor;
Canvas.Brush.Style := bsSolid;
Canvas.Pen.Color := DrawLineColor;
Canvas.Pen.Mode := pmCopy;
Canvas.FillRect(Rect(0, 0, DW, DH));
end;
if ((Length = 0) Or (Buf = NIL)) then
begin //清除
BitBlt(DesCanvas.Handle, 0, 0, DW, DH, DesBitMap.Canvas.Handle, 0, 0, SRCCOPY);
Exit;
end;
Max := -32768;
Min := 32767;
for i := 0 to (Length div 2 -1 ) do //取到最小值与最大值
begin
j := PCMInt(PChar(Buf) + i * 2)^;
if j > Max then Max := j;
if j < Min then Min := j;
end;
DrawMin := Min;
DrawMax := Max;
if Not Draw then
begin
Exit;
end;
Max := Max - Min; //最大振幅
DesBitMap.Canvas.MoveTo(0, DH div 2);
j := 0;
X := 0;
lmax := 0;
lmin := 32767;
for i := 0 to ((Length) div 2 -1) do
begin
if j < (Flag - 1) then //如果是在一个周期内
begin
INC(j);
end
else begin
j := 0;
X := X + 1;
lmax := 0;
lmin := 32767;
end;
if Max <> 0 then //取音频数据转换在整数
Y := Abs(PCMInt(PChar(buf) + i * 2)^ - Min) * DH div Max
else
Y := DH div 2;
k := 0;
if Y > lmax then
begin
lmax := Y;
k := 1;
end;
if Y < lmin then
begin
lmin := Y;
k := 1;
end;
if k = 1 then
DesBitMap.Canvas.LineTo(X, Y); //画线
if X > DW then break;
end;
//图像复制 拷贝
BitBlt(DesCanvas.Handle, 0, 0, DW, DH, DesBitMap.Canvas.Handle, 0, 0, SRCCOPY);
end;
//***********************************************************************//
// //
// 画全部音频数据的波形 //
// 参数: //
// Dw_Type : 波形显示数据记录 //
// WaveMin : 波形数据的最小值 //
// WaveMax : 波形数据的最大值 //
// DrawLineColor : 画波形的颜色 //
// DrawBackColor : 画波形的背景颜色 //
// Draw : 是否画波形 //
// 返回值: 无 //
// //
//***********************************************************************//
procedure DrawAllWave(Dw_Type: TDrawWave_Type; var WaveMin, WaveMax: LongInt;
DrawLineColor, DrawBackColor: TColor; Draw: Boolean = True);
var
Buf: PChar;
i, Loop, j, k, lmax, lmin: LongInt;
Max, Min: LongInt;
X, Y: SmallInt;
DrawLoop: LongInt;
MODDrawSize: LongInt;
LoadSize: LongInt;
hFile: Integer;
begin
Application.ProcessMessages;
hFile := 0;
DrawLoop := Dw_Type.Length DIV LoadMemSize;
MODDrawSize := 0;
if (Dw_Type.Length MOD LoadMemSize) <> 0 then
begin
DrawLoop := DrawLoop + 1;
MODDrawSize := Dw_Type.Length MOD LoadMemSize;
end;
SendMessage(Application.MainForm.Handle, CM_BEGINDRAW, DrawLoop * 3, 0);
with Dw_Type.DesBitMap do
begin
Width := Dw_Type.DW;
Height := Dw_Type.DH;
Canvas.Brush.Color := DrawBackColor;
Canvas.Brush.Style := bsSolid;
Canvas.Pen.Color := DrawLineColor;
Canvas.Pen.Mode := pmCopy;
Canvas.FillRect(Rect(0, 0, Dw_Type.DW, Dw_Type.DH));
end;
if Dw_Type.Length = 0 then
begin
BitBlt(Dw_Type.DesCanvas.Handle, 0, 0, Dw_Type.DW, Dw_Type.DH,
Dw_Type.DesBitMap.Canvas.Handle, 0, 0, SRCCOPY);
Exit;
end;
case Dw_Type.FileType of //不同的方式,打开不同的文件
//移到文件音频数据开始处
CS_SAVE_PLAY: mmioSeek(Dw_Type.hio, Dw_Type.Length, SEEK_END); //播方方式
CS_SAVE_RECORD: hFile := FileOpen(Dw_Type.FileName, fmOpenRead); //录音方式
end;
Max := -32768;
Min := 32767;
Try
for Loop := 1 to DrawLoop do
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -