📄 tcmwavetype.pas
字号:
//***********************************************************************//
// //
// 音频处理公用单元 //
// 单元名: TCMWaveType //
// 功能: 提供放音与录音的公共数据和函数 //
// 日期: 2003 年 1月 13日 //
// //
//***********************************************************************//
unit TCMWaveType;
interface
uses
Windows, SysUtils, Messages, Classes, Graphics, MMSystem, Forms, Dialogs;
//***********************************************************************//
// //
// 当前的播放状态 //
// //
//***********************************************************************//
Type
TCMPlaying = (CPNONE, //没有在任何状态下
CPPLAYING, //正处于播放状态中
CPSTOPING, //正处于停止状态中
CPPAUSEING //正处于暂停状态中
);
//***********************************************************************//
// //
// 当前的录音状态 //
// //
//***********************************************************************//
Type
TCMRecording = (CRNONE, //没有在任何状态下
CRRECORDING, //正处于录音状态中
CRSTOPING, //正处于停止状态中
CRPAUSEING //正处于暂停状态中
);
//***********************************************************************//
// //
// 文件是以何种方式打开 //
// //
//***********************************************************************//
Type
TSave_Type = (CS_SAVE_PLAY, //以播放方式
CS_SAVE_RECORD, //以录音方式
CS_SAVE_NEW //以新建方式
);
//***********************************************************************//
// //
// 播放模式 //
// //
//***********************************************************************//
Type
TPlay_Type = (PLAY_ALL, //播放全部
PLAY_AREA //区域播放
);
//***********************************************************************//
// //
// 音频数据编辑方式 //
// //
//***********************************************************************//
Type
TWaveEdit_Type = (CM_WE_COPY, //复制音频数据
CM_WE_CUT, //剪切音频数据
CM_WE_DEL, //删除音频数据
CM_WE_PASTE //粘贴音频数据
);
//***********************************************************************//
// //
// 音频时间格式 //
// //
//***********************************************************************//
Type
TCM_Wave_Time = Record
Hour: DWORD; //小时
Minute: DWORD; //分钟
Second: DWORD; //秒
Heroism: DWORD; //豪秒
end;
//***********************************************************************//
// //
// 波形显示数据记录 //
// //
//***********************************************************************//
Type
TDrawWave_Type = Record
FileType: TSave_Type; //文件打开的方式
hio: HMMIO; //音频文件名柄( 以播放方式打开时有效 )
Flag: Integer; //波形显示周期
FileName: String; //文件名( 以录音方式打开时有效 )
Length: LongInt; //音频数据的长度
DesCanvas: TCanvas; //要显示波形的目标画布
DH: SmallInt; //目标画布的工作区域的高度
DW: SmallInt; //目标画布的工作区域的宽度
DesBitMap: TBitMap; //画波形时用的非可视源位图对像
end;
//***********************************************************************//
// //
// 音频类回调过程处理状态 //
// //
//***********************************************************************//
Type
TWaveLoopEventType = (WA_EN_NONE, //没有任何状态
WA_EN_OPENFILE //打开文件状态
);
//***********************************************************************//
// //
// 音频类回调过程处理过程 //
// //
//***********************************************************************//
Type
TWaveLoopNotifyEvent = procedure(WaveEvent: TWaveLoopEventType; Max, Min,
Position: DWORD) of object;
Type
PCMInt = ^SmallInt; //短整型指针
PCMlong = ^LongInt; //长整型指针
EMMIO = class(Exception); //多媒体异常类
Const
LoadMemSize = 1024 * 5000;//0;//15000; //数据播放的长度( 要开辟的内存大小 必须是 32 的倍数)
CM_PLAYBEGIN = WM_user + $A1; //开始播放
CM_PLAYEND = WM_user + $A2; //播放完毕
CM_PLAYPAUSE = WM_user + $A3; //暂停播放
CM_PLAYREST = WM_user + $A4; //恢复播放
CM_BEGINSAVE = WM_user + $A5; //开始保存消息
CM_SAVEPOSI = WM_user + $A6; //当前保存位置消息( wParam : 当前位置 )
CM_ENDSAVE = WM_user + $A7; //保存完消息
CM_BEGINDRAW = WM_user + $A8; //开始画波形消息
CM_DRAWPOSI = WM_user + $A9; //当前画到的位置消息( wParam : 当前位置 )
CM_ENDDRAW = WM_user + $AA; //波形画完消息
CM_BEGINCOPY = WM_user + $AB; //开始复制数据
CM_BEGINCUT = WM_user + $AC; //开始剪切数据
CM_BEGINPASTE = WM_user + $AD; //开始粘贴数据
CM_BEGINDEL = WM_user + $AE; //开始删除数据
CM_BEGINUNDO = WM_user + $AF; //开始撤消数据
CM_EDIEND = WM_user + $B0; //数据编辑完毕
CM_EDITPOI = WM_user + $B1; //数据编辑进度( wParam : 当前位置. 当 wParam 为 0 时, lParam : 在以前进度的基础上加的长度 )
CM_EDITLENGTH = WM_user + $B2; //数据处理的长度( wParam : 数据长度 )
procedure Wave_SaveFile(const FileName, TempFileName: String; DataLength: LongInt;
WaveFmt: TWAVEFORMATEX; Dhio: HMMIO; tSave: TSave_Type;
const StartPoi: LongInt = 0; const SaveLength: LongInt = 0);
function Wave_Save_ConvertFile(const NewFileName: String; DataLength: LongInt;
NewWaveFmt, OldWaveFmt: TWAVEFORMATEX; Dhio: HMMIO; ShowPoi: TWaveLoopNotifyEvent): LongInt;
procedure DrawPartWave(const Flag: Integer; Buf: PChar; Length: LongInt;
DesCanvas: TCanvas; DH, DW: SmallInt; DesBitMap: TBitMap;
DrawLineColor, DrawBackColor: TColor; Draw: Boolean = True);
procedure HawDrawWave(Buf: PChar; Length: LongInt; DesCanvas: TCanvas;
DH, DW: SmallInt; Min, Max: LongInt; DrawLineColor, DrawBackColor: TColor;
StartPoi: LongInt = 0; DrawLength: LongInt = 0);
procedure DrawAllWave(Dw_Type: TDrawWave_Type; var WaveMin, WaveMax: LongInt;
DrawLineColor, DrawBackColor: TColor; Draw: Boolean = True);
function ConvertWave(OldBuf: PChar; OldLen: Integer; const OldFmt: TWAVEFORMATEX;
var NewBuf: PChar; const Newfmt: TWAVEFORMATEX): LongInt;
implementation
//***********************************************************************//
// //
// 16 位数据转换成 8 位数 //
// //
//***********************************************************************//
function Bits16To8(Src: WORD): Byte;
begin
Result := Byte((Src shr 8) xor $80);
end;
//***********************************************************************//
// //
// 8 位数据转换成 16 位数 //
// //
//***********************************************************************//
function Bits8To16(Src: Byte): WORD;
begin
Result := WORD((Src xor $80) shl 8 );
end;
//***********************************************************************//
// //
// 本单元公用变量声明 //
// //
//***********************************************************************//
var
DrawMin: Integer; //波形的最小值
DrawMax: Integer; //波形的最大值
//***********************************************************************//
// //
// 保存音频文件 //
// 参数: //
// 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_BEGINSAVE, 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
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('建立文件头错误');
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);
ck.ckid := mmioStringToFOURCC('data', 0); //创建 data 数据块
ck.cksize := 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 SaveLoop do
begin
if (MODSaveSize <> 0) AND (i = SaveLoop) then
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -