⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tplaywaveunit.~pas

📁 语音与识别技术包含很多C语言处理模块系统
💻 ~PAS
📖 第 1 页 / 共 5 页
字号:
     WaveFmt.nSamplesPerSec := 22050;   //采样频率为 22050 KHZ
     //8000;
     WaveFmt.nAvgBytesPerSec := 44100;  //平均数据传输率
     //00;
     WaveFmt.wBitsPerSample := 16;      //采样大小
     WaveFmt.nBlockAlign := 2;          //块对齐方式
     if not((Self.pFormat^.nChannels = WaveFmt.nChannels)
        and (Self.pFormat^.nSamplesPerSec = WaveFmt.nSamplesPerSec)
        and (Self.pFormat^.wBitsPerSample = WaveFmt.wBitsPerSample))  then
     begin
        //进行数据转换
        Wave_Save_ConvertFile(Self.BackFileName, Self.DataLength, Wavefmt,
                              Self.pFormat^, Self.hio, Self.ShowPoistrator);
        Self.CloseWaveFile;     //关闭打开的音频文件
     end  //文件复制
     else CopyFile(PChar(Value), PChar(Self.BackFileName), True);
     if Self.DataLength <= 0 then
     begin
        Self.FFileName := PChar('');
        Self.FNowPlay := CPNONE;   //没有任何状态
        Exit;
     end;
  end
  else begin
     Self.FFileName := PChar('');
     Self.FNowPlay := CPNONE;   //没有任何状态
     Exit;
  end;

  if Self.OpenFileName(PChar(Self.BackFileName)) then
  begin
     Self.FFileName := PChar(Value);
     Self.FNowPlay := CPSTOPING;        //当前为停止状态
  end
  else begin
     Self.FFileName := PChar('');
     Self.FNowPlay := CPNONE;
  end;

  //进度显示
  if Self.ShowMessageParBar <> NIL then
  begin
     Self.ShowMessageParBar.Position := 100;
  end;
  if Assigned(Self.WaveLoopEvent) then
     Self.WaveLoopEvent(WA_EN_OPENFILE, 100, 0, 100);
end;

//***********************************************************************//
//                                                                       //
//   控制画波形的时间周期                                                //
//   参数: 无                                                            //
//   返回值:  无                                                         //
//                                                                       //
//***********************************************************************//
procedure TCMPlayWave.SDTime(Sender: TObject);
begin
  TTimer(Sender).Enabled := False;
  TTimer(Sender).Tag := 1;              //可以画波形了
end;

//***********************************************************************//
//                                                                       //
//   音频播放子过程                                                      //
//   参数: 无                                                            //
//   返回值:  无                                                         //
//                                                                       //
//***********************************************************************//
procedure TCMPlayWave.PlayWave;
var
  i: Integer;
  lpWaveHdr: PWaveHdr;          //指向WAVEHDR结构的指针
  tm: TMMTime;
  SetDrawTime: TTimer;
  TempAv: LongInt;
begin
  SetDrawTime := TTimer.Create(Application);    //用于控制画波形的时间周期
  SetDrawTime.Enabled := False;
  SetDrawTime.Interval := 75;
  SetDrawTime.Tag := 1;
  SetDrawTime.OnTimer := Self.SDTime;

  Self.SetMemTime.Tag := 1;
  Self.PlayLoop := Self.PlayDataLength DIV LoadMemSize;
  Self.MODInt := Self.PlayDataLength MOD LoadMemSize;
  if Self.MODInt <> 0 then
     Self.PlayLoop := Self.PlayLoop + 1;

  Self.FNowPlay := CPPLAYING;                //正处于播放状态

  //发送开始播放的消息
  SendMessage(Application.MainForm.Handle, CM_PLAYBEGIN, 0, 0);

//  Self.FWavePlayKM := 40;
  TempAv := Self.pFormat.nSamplesPerSec;
  Try
//    if (Self.FWavePlayKM MOD 2) = 1 then
//       Self.FWavePlayKM := Self.FWavePlayKM + 1;
    if Self.FWavePlayKM <> 0 then
    begin
//       Self.pFormat.nAvgBytesPerSec := Self.pFormat.nAvgBytesPerSec * Self.FWavePlayKM DIV 100;
       Self.pFormat.nSamplesPerSec := Self.pFormat.nSamplesPerSec * Self.FWavePlayKM DIV 100;
//       Self.pFormat.nBlockAlign := Self.pFormat.nSamplesPerSec * Self.pFormat.nChannels DIV 8;
    end;

//    SetDrawTime.Interval := SetDrawTime.Interval * ABS(Self.WavePlayKM - 100);

    //打开音频设备
    if WaveOutOpen(@Self.hwo, WAVE_MAPPER, Self.pFormat, 0, 0, 0) <> 0 then
         raise EMMIO.Create('打开音频设备错!');

    //开辟内存
    lpWaveHdr := PWaveHdr(GlobalAllocPtr(GMEM_MOVEABLE OR GMEM_SHARE, DWORD(Sizeof(WAVEHDR))));
    if lpWaveHdr = NIL then
       raise EMMIO.Create('不能分配内存!');

    MMioSeek(Self.hio, Self.DataLength - Self.GotoPosition, SEEK_END);  //把文件指针移到音频数据的指定开始处

    Self.SetPlayMem(Self.SetMemTime);   //读取音频数据

    lpWaveHdr.lpData := Self.FirstData;              //音频数据
    lpWaveHdr.dwBufferLength := DWORD(Self.PlaySize);     //音频数据长度

    for i := 1 to Self.PlayLoop do           //双缓存交换播放
    begin
       if i > 1 then
       begin
          lpWaveHdr.lpData := NIL;
          if Self.SetMemTime.Tag MOD 2 = 0 then
             lpWaveHdr.lpData := Self.FirstData
          else
             lpWaveHdr.lpData := Self.NextData;
          lpWaveHdr.dwBufferLength := DWORD(Self.PlaySize);     //音频数据长度
       end;

       lpWaveHdr.dwFlags := 0;
       lpWaveHdr.dwLoops := 0;

       //生成音频信息头
       if WaveOutPrepareHeader(Self.hwo, lpWaveHdr, SizeOf(WAVEHDR)) <> 0 then
          raise EMMIO.Create('不能准备数据!');

       if Self.PlaySize > 1 then
          Self.SetMemTime.Enabled := True;                 //读取音频数据

       //向音频设备写音频数据
       if WaveOutWrite(Self.hwo, lpWaveHdr, SizeOf(WAVEHDR)) <> 0 then
          raise EMMIO.Create('写数据错!');

       SetDrawTime.Tag := 1;

       //数据是否已播放完
       while Boolean(NOT lpWaveHdr.dwFlags AND WHDR_DONE) do
       begin
          Application.ProcessMessages;       //处理 Windows 消息
          if (Self.FNowPlay = CPSTOPING) OR (Self.FNowPlay = CPNONE) then
             break;
          if Self.FNowPlay = CPPLAYING then
          begin
             tm.wType := TIME_BYTES;    //时间格式
             WaveOutGetPosition(hwo, @tm, SizeOf(TMMTime));
             Self.FPosition := tm.cb + GotoPosition;    //当前播放位置
             if SetDrawTime.Tag = 1 then
             begin
               Application.ProcessMessages;
               SetDrawTime.Tag := 0;
               if (Self.FDesBMP <> NIL) AND (Self.FDrawWave <> NIL) then
                  //画波形
{                  HawDrawWave(lpWaveHdr.lpData, lpWaveHdr.dwBufferLength, Self.FDrawWave.Canvas,
                         Self.FDrawWave.ClientHeight, Self.FDrawWave.ClientWidth,
                         Self.WaveMin, Self.WaveMax, Self.FDrawLineColor, Self.FDrawBackColor,
                         LongInt(tm.cb) - LoadMemSize * (i - 1), Self.FDrawWave.ClientWidth * 2);
 }              SetDrawTime.Enabled := True;
               Application.ProcessMessages;
             end;
          end;
       end;
       //释放音频信息头
       WaveOutUnPrepareHeader(Self.hwo, lpWaveHdr, SizeOf(WAVEHDR));

       if (Self.FNowPlay = CPSTOPING) OR (Self.FNowPlay = CPNONE) then
          break;
    end;
    if lpWaveHdr <> NIL then
       GlobalFreePtr(lpWaveHdr);        //释放内存

  Finally
    SetDrawTime.Enabled := False;
    SetDrawTime.Free;
    Self.SetMemTime.Enabled := False;
    if Self.FirstData <> NIL then
    begin
       GloBalFreePtr(Self.FirstData);   //释放内存
       Self.FirstData := NIL;
    end;
    if Self.NextData <> NIL then
    begin
       GloBalFreePtr(Self.NextData);    //释放内存
       Self.NextData := NIL;
    end;
    WaveOutClose(Self.hwo);             //关闭音频设备
    Self.GotoPosition := 0;

    Self.pFormat.nSamplesPerSec := TempAV;
  end;
end;

//***********************************************************************//
//                                                                       //
//   分配内存、读取音频数据                                              //
//   参数: 无                                                            //
//   返回值:  无                                                         //
//                                                                       //
//***********************************************************************//
procedure TCMPlayWave.SetPlayMem(Sender: TObject);
begin
  Self.SetMemTime.Enabled := False;

  //如果循环读取数据的总次数据大于要读取的次数
  if Self.SetMemTime.Tag > Self.PlayLoop then
     Exit;
  Try           //异常保护
    if (Self.SetMemTime.Tag MOD 2) = 1 then
    begin
       if Self.FirstData <> NIL then
          GloBalFreePtr(Self.FirstData);        //释放内存
 
       //是读取最后一段数据并且余下的数据长度不为 0
       if (Self.MODInt <> 0) AND (Self.SetMemTime.Tag = Self.PlayLoop) then
          Self.PlaySize := Self.MODInt           //要播放的音频数据的长度
       else
          Self.PlaySize := LoadMemSize;
       //开辟内存
       Self.FirstData := PChar(GlobalAllocPtr(GMEM_MOVEABLE or GMEM_SHARE, Self.PlaySize));

       if Self.FirstData = NIL then
          raise EMMIO.Create('不能分配内存!');
          
       if mmioRead(Self.hio, Self.FirstData, Self.PlaySize) <> Self.PlaySize then
          raise EMMIO.Create('读取数据出错:可能文件已被破坏!');
    end
    else begin
       if Self.NextData <> NIL then
          GloBalFreePtr(Self.NextData);
          
       if (Self.MODInt <> 0) AND (Self.SetMemTime.Tag = Self.PlayLoop) then
          Self.PlaySize := Self.MODInt
       else
          Self.PlaySize := LoadMemSize;

       Self.NextData := PChar(GlobalAllocPtr(GMEM_MOVEABLE or GMEM_SHARE, Self.PlaySize));

       if Self.NextData = NIL then
          raise EMMIO.Create('不能分配内存!');

       //从文件中读取指定长度的音频数据
       if mmioRead(Self.hio, Self.NextData, Self.PlaySize) <> Self.PlaySize then
          raise EMMIO.Create('读取数据出错:可能文件已被破坏!');
    end;
  Finally;
  end;
  Self.SetMemTime.Tag := Self.SetMemTime.Tag + 1;
end;

//***********************************************************************//
//                                                                       //
//   开始播放音频                                                        //
//   参数:                                                               //
//       Start          : 开始位置                                       //
//       Length         : 要播放的音频数据的长度                         //
//                        ( 0 表示播放所用的数据 )                       //
//   返回值:  无                                                         //
//                                                                       //
//***********************************************************************//
procedure TCMPlayWave.Play(const Start, Length: DWORD);
begin
  if Self.NowPlay <> CPSTOPING then     //不是在停止状态下
     Exit;
  if (Start < Self.DataLength) and (Self.GotoPosition = 0) then
     Self.GotoPosition := Start;        //确定起始位置

  Self.PlayDataLength := Length;        //要播放的音频数据的长度
  //确定要播放的音频数据的长度
  if (Self.PlayDataLength = 0) or ((Self.GotoPosition + Length) > Self.DataLength) then
     Self.PlayDataLength := Self.DataLength - Self.GotoPosition;
  Self.PlayWave;        //开始播放
  Self.FNowPlay := CPSTOPING;   //处于停止状态 ( 播放完毕 )
  //发送播放完毕的消息
  SendMessage(Application.MainForm.Handle, CM_PLAYEND, 0, 0);
end;

//***********************************************************************//
//                                                                       //
//   暂停播放                                                            //
//   参数: 无                                                            //
//   返回值:  无                                                         //
//                                                                       //
//***********************************************************************//
procedure TCMPlayWave.Pause;
begin
  if Self.NowPlay <> CPPLAYING then     //不是在播放状态下
     Exit;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -