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

📄 mmtrigg.pas

📁 一套及时通讯的原码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{========================================================================}
{=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
{========================================================================}
{=                          All Rights Reserved                         =}
{========================================================================}
{=  D 01099 Dresden             = Fax.: +49 (0)351-8037944              =}
{=  Loewenstr.7a                = info@swiftsoft.de                     =}
{========================================================================}
{=  Actual versions on http://www.swiftsoft.de/mmtools.html             =}
{========================================================================}
{=  This code is for reference purposes only and may not be copied or   =}
{=  distributed in any format electronic or otherwise except one copy   =}
{=  for backup purposes.                                                =}
{=                                                                      =}
{=  No Delphi Component Kit or Component individually or in a collection=}
{=  subclassed or otherwise from the code in this unit, or associated   =}
{=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
{=  without express permission from SwiftSoft.                          =}
{=                                                                      =}
{=  For more licence informations please refer to the associated        =}
{=  HelpFile.                                                           =}
{========================================================================}
{=  $Date: 06.03.98 - 15:58:36 $                                        =}
{========================================================================}
unit MMTrigg;

{$C FIXED PRELOAD PERMANENT}

{$I COMPILER.INC}

{.$DEFINE _MMDEBUG}

interface

uses
{$IFDEF WIN32}
  Windows,
{$ELSE}
  WinTypes,
  WinProcs,
{$ENDIF}
  SysUtils,
  Messages,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  MMSystem,
  MMUtils,
  MMString,
  MMObj,
  MMDSPObj,
  MMRegs,
  MMPCMSup,
  MMAlloc,
  MMWaveIO
  {$IFDEF _MMDEBUG}
  ,MMDebug
  {$ENDIF}
  ;

{$IFDEF _MMDEBUG}
const
  DEBUGLEVEL       = 2; { 0,1,2 }
{$ENDIF}

const
  {$IFDEF WIN32}
  TRIGGER_PRIORITY : TThreadPriority = tpNormal;
  {$ENDIF}
  MINBUFFERSIZE    = 32;

type
  TMMTriggerStates = (trClose, trOpen, trPlay, trPause);
  TMMTriggerState  = set of TMMTriggerStates;

  EMMTriggerError  = class(Exception);

  TMMErrorEvent    = procedure (Sender: TObject; var Handled: Boolean) of object;

  {$IFDEF WIN32}
  TMMTrigger       = class;

  {-- TMMTriggerThread --------------------------------------------------}
  TMMTriggerThread = class(TMMDSPThread)
  private
     procedure Execute; override;
  end;
  {$ENDIF}

  {-- TMMTrigger ---------------------------------------------------------}
  TMMTrigger = class(TMMCustomSoundComponent)
  private
    FHandle        : THandle;        { handle used for callback window    }
    FState         : TMMTriggerState;{ Current device state               }
    FWaveHdr       : PWaveHdr;       { Wave Headers and Buffer            }
    FInHandler     : integer;        { marks that we in any event handler }
    FThreadError   : Boolean;        { Error in Thread Handler            }
    FStarted       : Boolean;        { device is now started              }
    FStopIt        : Boolean;        { we should stop playing if possible }
    FCloseIt       : Boolean;        { we should close device if possible }
    FStopping      : Boolean;        { we actually stop the device        }
    FClosing       : Boolean;        { we actually close the device       }
    FBytesPlayed   : Longint;        { total bytes we have realy played   }
    FMoreBuffers   : Boolean;        { more buffers to write ?            }
    FTimeFormat    : TMMTimeFormats; { the actual time format for Position}
    FInterval      : integer;        { trigger interval in ms             }
    FAllocator     : TMMAllocator;

    {$IFDEF WIN32}
    FTriggerThread : TMMTriggerThread;{ Trigger Thread for callback handling}
    DataSection    : TRtlCriticalSection;{ CriticalSection Object         }
    DataSectionOK  : Boolean;        { CriticalSection is prepared        }
    FGeneralEvent  : THandle;        { event object for general purpose   }
    FTriggerEvent  : THandle;        { event object for notify handling   }
    FCloseEvent    : THandle;        { event object to close the device   }
    {$ENDIF}

    FHandled       : Boolean;

    { Events }
    FOnError       : TNotifyEvent;   { There was an error                 }
    FOnErrorEx     : TMMErrorEvent;  { There was an error                 }
    FOnBufferFilled: TMMBufferEvent; { Wave buffer filled event           }
    FOnOpen        : TNotifyEvent;   { Wave Device succ. opened           }
    FOnStart       : TNotifyEvent;   { Wave Device succ. started          }
    FOnPause       : TNotifyEvent;   { Wave Device succ. paused           }
    FOnRestart     : TNotifyEvent;   { Wave Device succ. restarted        }
    FOnStop        : TNotifyEvent;   { Wave Device succ. stopped          }
    FOnClose       : TNotifyEvent;   { Wave Device succ. closed           }

    procedure SetTimeFormat(aValue: TMMTimeFormats);
    procedure SetInterval(aValue: integer);
    function  GetPosition: Longint;
    procedure TriggerHandler(var Msg: TMessage);
    procedure AllocWaveHeader(var lpWaveHdr: PWaveHdr);
    procedure FreeWaveHeader;
    function  LoadWaveHeader(lpWaveHdr: PWaveHdr): Longint;
    procedure QueueWaveHeader(lpWaveHdr: PWaveHdr);
    procedure ProcessWaveHeader(lpWaveHdr: PWaveHdr);

    {$IFDEF WIN32}
    procedure InitThread;
    procedure DoneThread;
    procedure CloseEvents;
    {$ENDIF}

    procedure InitCritical;
    procedure EnterCritical;
    procedure LeaveCritical;
    procedure DoneCritical;

    procedure DoOpened;
    procedure DoClosed;
    procedure DoStarted;
    procedure DoPaused;
    procedure DoRestarted;
    procedure DoStopped;
    procedure DoBufferFilled(lpwh: PWaveHdr);
    procedure DoBufferReady(lpwh: PWaveHdr);

  protected

    procedure SetPWaveFormat(aValue: PWaveFormatEx); override;
    procedure SetBufferSize(aValue: Longint); override;
    function  GetBufferSize: Longint; override;

    procedure Error(Msg: string); virtual;
    procedure Opened; override;
    procedure Closed; override;
    procedure Started; override;
    procedure Paused; override;
    procedure Restarted; override;
    procedure Stopped; override;
    procedure BufferReady(lpwh: PWaveHdr); override;
    procedure BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean); override;

  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure Open; virtual;
    procedure Close; virtual;
    procedure Start; virtual;
    procedure Pause; virtual;
    procedure Restart; virtual;
    procedure Stop; virtual;

    {$IFDEF WIN32}
    procedure SynchronizeVCL(VCLProc: TThreadMethod);
    {$ENDIF}

    property State: TMMTriggerState read FState;
    property Position: Longint read GetPosition;

  published
    { Events }
    property OnError: TNotifyEvent read FOnError write FOnError;
    property OnErrorEx: TMMErrorEvent read FOnErrorEx write FOnErrorEx;
    property OnOpen: TNotifyEvent read FOnOpen write FOnOpen;
    property OnStart: TNotifyEvent read FOnStart write FOnStart;
    property OnPause: TNotifyEvent read FOnPause write FOnPause;
    property OnRestart: TNotifyEvent read FOnRestart write FOnRestart;
    property OnStop: TNotifyEvent read FOnStop write FOnStop;
    property OnClose: TNotifyEvent read FOnClose write FOnClose;
    property OnBufferFilled: TMMBufferEvent read FOnBufferFilled write FOnBufferFilled;
    property OnBufferReady;
    property OnBufferLoad;

    property Input;
    property Output;
    property BufferSize;
    property Interval: integer read FInterval write SetInterval default 0;
    property TimeFormat: TMMTimeFormats read FTimeFormat write SetTimeFormat default tfByte;
  end;

implementation

uses consts;

const
     MM_WOM_STOP  = MM_USER+1;

{-------------------------------------------------------------------------}
procedure DebugStr(Level: integer; s: String);
begin
{$IFDEF _MMDEBUG}
   if (s <> ' ') then s := 'Trigger: '+s;
   DB_WriteStrLn(Level,s);
{$ENDIF}
end;

{== TMMTrigger ===========================================================}
constructor TMMTrigger.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);

   { Set defaults }
   FState        := [trClose];
   FBytesPlayed  := 0;
   FTimeFormat   := tfByte;
   FMoreBuffers  := False;
   FClosing      := False;
   FStopping     := False;
   FInterval     := 0;

   FAllocator    := TMMAllocator.Create;

   {$IFDEF WIN32}
   DataSectionOK := False;
   {$ENDIF}

   ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
   if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
end;

{-- TMMTrigger -----------------------------------------------------------}
destructor TMMTrigger.Destroy;
begin
   { Close the device if it's open }
   Close;

   { Destroy the window for callback notification }
   if (FHandle <> 0) then DeallocateHwnd(FHandle);

   if assigned(FAllocator) then FAllocator.Free;

   inherited Destroy;
end;

{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.Error(Msg: string);
begin
   if assigned(FOnError) then FOnError(Self);

   raise EMMTriggerError.Create(Msg);
end;

{-- TMMTrigger -----------------------------------------------------------}
{ Allocate memory for the Trigger header and buffer }
procedure TMMTrigger.AllocWaveHeader(var lpWaveHdr: PWaveHdr);
begin
   if (lpWaveHdr = Nil) then
   begin
      { set up a wave header for playing and lock. }
      lpWaveHdr := FAllocator.AllocBuffer(GHND,SizeOf(TMMWaveHdr) + BufferSize);
      if lpWaveHdr = NIL then
         Error(LoadResStr(IDS_HEADERMEMERROR));

      { Data occurs directly after the header }
      lpWaveHdr^.lpData         := PChar(lpWaveHdr) + sizeOf(TMMWaveHdr);
      lpWaveHdr^.dwBufferLength := BufferSize;
      lpWaveHdr^.dwBytesRecorded:= 0;
      lpWaveHdr^.dwFlags        := 0;
      lpWaveHdr^.dwLoops        := 0;
      lpWaveHdr^.dwUser         := 0;
      lpWaveHdr^.lpNext         := nil;
   end;
end;

{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.FreeWaveHeader;
begin
   { unlock and free memory for TriggerHdr }
   if FWaveHdr <> nil then
   begin
      FAllocator.FreeBuffer(Pointer(FWaveHdr));
      FWaveHdr := Nil;
   end;
end;

{-- TMMTrigger ------------------------------------------------------------}
procedure TMMTrigger.SetInterval(aValue: integer);
begin
   if (aValue <> FInterval) then
   begin
      FInterval := Max(aValue,0);
   end;
end;

{-- TMMTrigger ------------------------------------------------------------}
procedure TMMTrigger.SetTimeFormat(aValue: TMMTimeFormats);
begin
   if (aValue <> FTimeFormat) then
   begin
      FTimeFormat := aValue;
   end;
end;

{-- TMMTrigger ------------------------------------------------------------}
function TMMTrigger.GetPosition: Longint;
Var
   Bytes: Longint;

begin
   Result := 0;

   if (trOpen in FState) and (PWaveFormat <> Nil) and not FClosing then
   begin
      EnterCritical;
      try
         Bytes := FBytesPlayed;

         case FTimeFormat of
           tfMilliSecond: Result := wioBytesToTime(PWaveFormat,Bytes);
           tfByte       : Result := Bytes;
           tfSample     : Result := wioBytesToSamples(PWaveFormat,Bytes);
         end;

      finally
         LeaveCritical;
      end;
   end;
end;

{-- TMMTrigger -----------------------------------------------------------}
Procedure TMMTrigger.SetPWaveFormat(aValue: PWaveFormatEx);
begin
   { stop and close the device }
   Close;
   inherited SetPWaveFormat(aValue);
end;

{-- TMMTrigger -----------------------------------------------------------}
Procedure TMMTrigger.SetBufferSize(aValue: Longint);
begin
   if (aValue <> inherited GetBufferSize) then
   begin
      if (trOpen in FState) then
          Error(LoadResStr(IDS_PROPERTYOPEN));

      if assigned(FAllocator) then
         FAllocator.Discard;

      inherited SetBufferSize(Max(aValue,MINBUFFERSIZE));
   end;
end;

{-- TMMTrigger -----------------------------------------------------------}
function TMMTrigger.GetBufferSize: Longint;
begin
   Result := inherited GetBufferSize;
end;

{-- TMMTrigger -----------------------------------------------------------}
function TMMTrigger.LoadWaveHeader(lpWaveHdr: PWaveHdr): Longint;
begin
   FMoreBuffers := False;

   BufferLoad(lpWaveHdr, FMoreBuffers);

   Result := lpWaveHdr^.dwBytesRecorded;
   if Result <= 0 then FMoreBuffers := False;
end;

{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.QueueWaveHeader(lpWaveHdr: PWaveHdr);
begin
   { this is the chance to modify the data in the buffer !!! }
   DoBufferFilled(lpWaveHdr);
end;

{$IFDEF WIN32}
{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.SynchronizeVCL(VCLProc: TThreadMethod);
begin
   if (FGeneralEvent <> 0) then
   begin
      FTriggerThread.Synchronize(VCLProc);
   end
   else VCLProc;
end;

{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.InitThread;
begin
   EnterCritical;
   try
      FThreadError := False;

      { create event objects }
      FGeneralEvent:= CreateEvent(nil, False, False, nil);
      FTriggerEvent:= CreateEvent(nil, False, False, nil);
      FCloseEvent  := CreateEvent(nil, False, False, nil);

      { create the output thread }
      FTriggerThread := TMMTriggerThread.CreateSuspended(Self);
      if (FTriggerThread = nil) then
          Error('Trigger:'#10#13+LoadResStr(IDS_THREADERROR));

      FTriggerThread.FreeOnTerminate := True;
      FTriggerThread.Resume;

      {$IFDEF _MMDEBUG}
      DebugStr(0,'Wait for Thread start...');
      {$ENDIF}

      { Wait for it to start... }
      if WaitForSingleObject(FGeneralEvent, 5000) <> WAIT_OBJECT_0 then
         Error('Trigger:'#10#13+LoadResStr(IDS_THREADERROR));

      {$IFDEF _MMDEBUG}
      DebugStr(0,'Thread Started');
      {$ENDIF}

   finally
      LeaveCritical;
   end;
end;

{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.DoneThread;
begin
   if (FGeneralEvent <> 0) and not FThreadError then
   begin
      while FTriggerThread.Suspended do FTriggerThread.Resume;

      { Force the trigger thread to close... }
      SetEvent(FCloseEvent);

      { ...and wait for it to die }
      WaitForSingleObject(FGeneralEvent, 5000);

      { close all events and remove critical section }
      CloseEvents;

      {$IFDEF _MMDEBUG}
      DebugStr(0,'Thread Terminated');
      {$ENDIF}
   end;
end;

{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.CloseEvents;
begin
   if (FGeneralEvent <> 0) then
   begin
      { release events }
      CloseHandle(FGeneralEvent);
      CloseHandle(FTriggerEvent);
      CloseHandle(FCloseEvent);
      FGeneralEvent := 0;
      FTriggerEvent := 0;
      FCloseEvent   := 0;

      { Free the critical section }
      DoneCritical;
   end;
end;
{$ENDIF}

{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.InitCritical;
begin
   {$IFDEF WIN32}
   { create critical section object }
   FillChar(DataSection, SizeOf(DataSection), 0);
   InitializeCriticalSection(DataSection);
   DataSectionOK := True;
   {$ENDIF}
end;

{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.EnterCritical;
begin
   {$IFDEF WIN32}
   if DataSectionOK then
      EnterCriticalSection(DataSection);
   {$ENDIF}
end;

{-- TMMTrigger -----------------------------------------------------------}
procedure TMMTrigger.LeaveCritical;
begin
   {$IFDEF WIN32}
   if DataSectionOK then
      LeaveCriticalSection(DataSection);
   {$ENDIF}
end;

{-- TMMTrigger -----------------------------------------------------------}

⌨️ 快捷键说明

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