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

📄 mmringbf.pas

📁 一套及时通讯的原码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
         begin
            FStarted := True;
            {$IFDEF _MMDEBUG}
            DebugStr(0,'Duplex mode now started...')
            {$ENDIF};
         end;
         LeaveCritical;
         exit;
      end
      else LeaveCritical;

      if not Empty then
      begin
         { returns the next buffer from the queue }
         Size := Min(FBufferPool^[FOutIndex]^.dwSize,dwSize);
         GlobalMoveMem(FBufferPool^[FOutIndex]^.lpData^,lpData^,Size);
         dwSize := Size;
         dwUser := FBufferPool^[FOutIndex]^.dwUser;
         dwFlags:= FBufferPool^[FOutIndex]^.dwFlags;

         EnterCritical;
         try
            if (dwSize < FBufferPool^[FOutIndex]^.dwSize) then
            begin
               dec(FBufferPool^[FOutIndex]^.dwSize,Size);
               GlobalMoveMem(PChar(FBufferPool^[FOutIndex]^.lpData+Size)^,
                             FBufferPool^[FOutIndex]^.lpData^,
                             FBufferPool^[FOutIndex]^.dwSize);
            end
            else
            begin
               FLastIndex := FOutIndex;
               FOutIndex := (FOutIndex+1)mod FNumBuffers;
               dec(FQueueCount);
            end;
            dec(FBytesQueued,Size);

         finally
            LeaveCritical;
         end;

         {$IFDEF _MMDEBUG}
         DebugStr(2,'Buffer '+IntToStr(dwUser)+' removed from queue')
         {$ENDIF};
      end
      else
      begin
         {$IFDEF _MMDEBUG}
         DebugStr(2,'Queue is empty, loop last buffer...')
         {$ENDIF};

         { notify the user }
         DoEmpty;

         { buffer is empty }
         if FLoopIfEmpty or ((PWaveFormat <> nil) and (PWaveFormat^.wFormatTag <> WAVE_FORMAT_PCM)) then
         begin
            { return the last buffer (loop) }
            Size := Min(FBufferPool^[FLastIndex]^.dwSize,dwSize);
            GlobalMoveMem(FBufferPool^[FLastIndex]^.lpData^,lpData^,Size);
            dwSize := Size;
            dwUser := FBufferPool^[FLastIndex]^.dwUser;
            dwFlags:= FBufferPool^[FLastIndex]^.dwFlags;
         end
         else
         begin
            { simply fill the buffer }
            if (PWaveFormat <> nil) and (PWaveFormat^.wBitsPerSample = 8) then
               GlobalFillMem(lpData^,dwSize,128)
            else
               GlobalFillMem(lpData^,dwSize,0);

            dwUser := 0;
            dwFlags:= 0;
         end;
      end;
   end
   else dwSize := 0;
end;

{-- TMMRingBuffer --------------------------------------------------------}
function TMMRingBuffer.PutBlock(lpData: PChar; dwSize,dwFlags: DWORD): DWORD;
var
   Size,Flags: DWORD;

begin
   { puts a block of data with "dwSize" in the queue }
   Result := 0;
   Flags  := 0;
   while (dwSize > 0) do
   begin
      if Full then break;
      Size := Min(dwSize,BufferSize);
      { is this the last buffer ? if so then save the loop field }
      if (dwSize-Size <= 0) then Flags := dwFlags;
      PutBuffer(lpData,Size,0,Flags);
      dec(dwSize,Size);
      inc(lpData,Size);
      inc(Result,Size);
   end
end;

{-- TMMRingBuffer --------------------------------------------------------}
function TMMRingBuffer.GetBlock(lpData: PChar; dwSize: DWORD): DWORD;
var
   Size,Dummy: DWORD;

begin
   { returns a block of data with "dwSize" from the queue }
   Result := 0;
   while (dwSize > 0) do
   begin
      if Empty then break;
      Size := dwSize;
      GetBuffer(lpData,Size,Dummy,Dummy);
      if (Size > 0) then
      begin
         dec(dwSize,Size);
         inc(lpData,Size);
         inc(Result,Size);
      end
      else break;
   end;
end;

{-- TMMRingBuffer --------------------------------------------------------}
procedure TMMRingBuffer.Opened;
begin
   inherited Opened;

   Open;
end;

{-- TMMRingBuffer --------------------------------------------------------}
procedure TMMRingBuffer.Closed;
begin
   {$IFDEF _MMDEBUG}
   DebugStr(0,'Close received...');
   {$ENDIF}

   Close;

   inherited Closed;
end;

{-- TMMRingBuffer --------------------------------------------------------}
procedure TMMRingBuffer.Started;
begin
   FStopping := False;

   {$IFDEF _MMDEBUG}
   DebugStr(0,'Queue started...');
   {$ENDIF}

   inherited Started;
end;

{-- TMMRingBuffer --------------------------------------------------------}
procedure TMMRingBuffer.Stopped;
begin
   {$IFDEF _MMDEBUG}
   DebugStr(0,'Try to stop Queue...');
   {$ENDIF}

   FStarted := False;
   FStopping := True;
   FLoopRec.dwLoop := False;

   { make sure the queue is flushed in write mode }
   Flush;

   {$IFDEF _MMDEBUG}
   DebugStr(0,'Queue stopped...');
   {$ENDIF}

   inherited Stopped;
end;

{-- TMMRingBuffer --------------------------------------------------------}
procedure TMMRingBuffer.Reseting;
begin
   FStarted := False;
   FStopping := True;
   FLoopRec.dwLoop := False;

   { make sure the queue is flushed in write mode }
   Flush;

   Clear;

   FStopping := False;
   
   inherited Reseting;
end;

{-- TMMRingBuffer --------------------------------------------------------}
procedure TMMRingBuffer.BufferReady(lpwh: PWaveHdr);
begin
   if (FQueueMode in [qmWrite,qmDuplex]) then
   begin
      { the input has some data so put in the queue }
      PutBuffer(lpwh^.lpData,lpwh^.dwBytesRecorded,lpwh^.dwUser,0);
   end
   else inherited BufferReady(lpwh)
end;

{-- TMMRingBuffer --------------------------------------------------------}
procedure TMMRingBuffer.BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean);
var
   Flags: DWORD;
begin
   { the Output needs some data, try to get it }
   if (FQueueMode in [qmRead,qmDuplex]) then
   begin
      if FOpen then
      begin
         with PMMWaveHdr(lpwh)^ do
         begin
            if FEnabled or (BytesQueued > 0) or (FQueueMode in [qmDuplex]) then
            begin
               { setup the loop handling }
               if FLoopRec.dwLoop <> LoopRec.dwLoop then
               begin
                  FLoopRec.dwLoop := LoopRec.dwLoop;
                  if FLoopRec.dwLoop then
                  begin
                     FLoopRec.dwLoopCnt    := LoopRec.dwLoopCnt;
                     FLoopRec.dwLoopTmpCnt := LoopRec.dwLoopTmpCnt;
                     FLoopRec.dwLooping    := False;
                  end;
               end;

               wh.dwBytesRecorded := wh.dwBufferLength;
               GetBuffer(wh.lpData,wh.dwBytesRecorded,wh.dwUser,Flags);

               { is looped ? }
               LoopRec.dwLooping := (Flags and HDR_LOOP = HDR_LOOP);

               if (FQueueMode = qmDuplex) then
                   MoreBuffers := True
               else                    { last Block ? }
                   MoreBuffers := not (Flags and HDR_END = HDR_END);
            end
            else inherited BufferLoad(lpwh,MoreBuffers);
         end;
      end;
   end
   else inherited BufferLoad(lpwh,MoreBuffers);
end;

{-- TMMRingBuffer --------------------------------------------------------}
procedure TMMRingBuffer.FillQueue;
var
   MoreBuffers: Boolean;
   Flags: DWORD;

begin
   StartDSPMeter;
   try
      if FOpen and (BytesFree > 0) then
      begin
         DoFillQueue;

         while (BytesFree > 0) and not FStopping do
         begin
            with FTempBuffer^ do
            begin
               dwBufferLength := Min(BytesFree,FReadSize);
               dwBytesRecorded := 0;

               PMMWaveHdr(FTempBuffer)^.LoopRec := FLoopRec;

               MoreBuffers := False;
               inherited BufferLoad(FTempBuffer, MoreBuffers);

               { let other threads have some time }
               Sleep(SLEEPTIME);

               if (dwBytesRecorded <= 0) then
               begin
                  { mark the previous buffer as last and exit }
                  EnterCritical;
                  with FBufferPool^[FLastIndex]^ do dwFlags := dwFlags or HDR_END;
                  LeaveCritical;
                  break;
               end;

               FLoopRec := PMMWaveHdr(FTempBuffer)^.LoopRec;

               Flags := 0;
               if not MoreBuffers then Flags := Flags or HDR_END;
               if FloopRec.dwLooping then Flags := Flags or HDR_LOOP;

               PutBlock(lpData,dwBytesRecorded,FLags);
               FLoopRec.dwLooping    := False;

               if not MoreBuffers or FStopping then break;
            end;
            { let other threads have some time }
            Sleep(SLEEPTIME);
         end;

         DoFillQueueEnd;
      end;

   finally
      ResetEvent(FQueueEvent);
      SetEvent(FDoneEvent);
      StopDSPMeter;
   end;
end;

{-- TMMRingBuffer --------------------------------------------------------}
procedure TMMRingBuffer.FlushQueue;
var
   Size: Longint;
begin
   StartDSPMeter;
   try
      if FOpen and (BytesQueued > 0) then
      begin
         DoFlushQueue;

         while (BytesQueued > 0) do
         begin
            Size := Min(BytesQueued,FWriteSize);
            Size := GetBlock(FTempBuffer^.lpData,Size);

            if (Size <= 0) then break;

            FTempBuffer^.dwBytesRecorded := Size;
            FTempBuffer^.dwBufferLength  := FWriteSize;

            inherited BufferReady(FTempBuffer);

            { let other threads have some time }
            Sleep(SLEEPTIME);
         end;

         DoFlushQueueEnd;
      end;

   finally
      ResetEvent(FQueueEvent);
      SetEvent(FDoneEvent);
      StopDSPMeter;
   end;
end;

{-------------------------------------------------------------------------}
procedure TMMQueueThread.Execute;
var
   Res    : DWORD;
   Handles: array[0..1] of THandle;
   {$IFDEF _MMDEBUG}
   Error  : Longint;
   {$ENDIF}

begin
   with TMMRingBuffer(Owner) do
   try
      Priority := CACHE_PRIORITY;

      { Ready to go, set the general event }
      SetEvent(FGeneralEvent);

      Handles[0] := FCloseEvent;
      Handles[1] := FQueueEvent;

      { Repeat until closed }
      while not Terminated do
      try
         Res := WaitForMultipleObjects(2, @Handles, False, INFINITE);
         case Res of
            WAIT_FAILED:       { Wait failed.  Shouldn't happen. }
            begin
               {$IFDEF _MMDEBUG}
               Error := GetLastError;
               DebugStr(0,'Wait Failed... Error: '+SysErrorMessage(Error));
               {$ENDIF}
            end;
            WAIT_OBJECT_0:     { CloseEvent signaled!            }
            begin
               { Finished here, okay to close device }
               {$IFDEF _MMDEBUG}
               DebugStr(0,'CloseEvent signaled...');
               {$ENDIF}
               exit;
            end;
            WAIT_OBJECT_0+1:    { queue event received.          }
            begin
               if (FQueueMode = qmRead) then
               begin
                  {$IFDEF _MMDEBUG}
                  DebugStr(1,'ReadEvent received...');
                  {$ENDIF}

                  FillQueue;

                  {$IFDEF _MMDEBUG}
                  DebugStr(1,'Reading done...');
                  {$ENDIF}
               end
               else
               begin
                  {$IFDEF _MMDEBUG}
                  DebugStr(1,'WriteEvent received...');
                  {$ENDIF}

                  FlushQueue;

                  {$IFDEF _MMDEBUG}
                  DebugStr(1,'Writing done...');
                  {$ENDIF}
               end;
            end;
         end;

      except
         PulseEvent(FDoneEvent);
         Close;
         FThreadError := True;
         Application.HandleException(nil);
         exit;
      end;

   finally
     SetEvent(FGeneralEvent);

     {$IFDEF _MMDEBUG}
     DebugStr(0,'Exit Thread-Proc');
     {$ENDIF}
   end;
end;

initialization
{$IFDEF _MMDEBUG}
   DB_Level(DEBUGLEVEl);
{$ENDIF}
end.

⌨️ 快捷键说明

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