MMTrigg.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:29k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Fax.: +49 (0)351-8037944              =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/mmtools.html             =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 06.03.98 - 15:58:36 $                                        =}
  24. {========================================================================}
  25. unit MMTrigg;
  26. {$C FIXED PRELOAD PERMANENT}
  27. {$I COMPILER.INC}
  28. {.$DEFINE _MMDEBUG}
  29. interface
  30. uses
  31. {$IFDEF WIN32}
  32.   Windows,
  33. {$ELSE}
  34.   WinTypes,
  35.   WinProcs,
  36. {$ENDIF}
  37.   SysUtils,
  38.   Messages,
  39.   Classes,
  40.   Graphics,
  41.   Controls,
  42.   Forms,
  43.   Dialogs,
  44.   MMSystem,
  45.   MMUtils,
  46.   MMString,
  47.   MMObj,
  48.   MMDSPObj,
  49.   MMRegs,
  50.   MMPCMSup,
  51.   MMAlloc,
  52.   MMWaveIO
  53.   {$IFDEF _MMDEBUG}
  54.   ,MMDebug
  55.   {$ENDIF}
  56.   ;
  57. {$IFDEF _MMDEBUG}
  58. const
  59.   DEBUGLEVEL       = 2; { 0,1,2 }
  60. {$ENDIF}
  61. const
  62.   {$IFDEF WIN32}
  63.   TRIGGER_PRIORITY : TThreadPriority = tpNormal;
  64.   {$ENDIF}
  65.   MINBUFFERSIZE    = 32;
  66. type
  67.   TMMTriggerStates = (trClose, trOpen, trPlay, trPause);
  68.   TMMTriggerState  = set of TMMTriggerStates;
  69.   EMMTriggerError  = class(Exception);
  70.   TMMErrorEvent    = procedure (Sender: TObject; var Handled: Boolean) of object;
  71.   {$IFDEF WIN32}
  72.   TMMTrigger       = class;
  73.   {-- TMMTriggerThread --------------------------------------------------}
  74.   TMMTriggerThread = class(TMMDSPThread)
  75.   private
  76.      procedure Execute; override;
  77.   end;
  78.   {$ENDIF}
  79.   {-- TMMTrigger ---------------------------------------------------------}
  80.   TMMTrigger = class(TMMCustomSoundComponent)
  81.   private
  82.     FHandle        : THandle;        { handle used for callback window    }
  83.     FState         : TMMTriggerState;{ Current device state               }
  84.     FWaveHdr       : PWaveHdr;       { Wave Headers and Buffer            }
  85.     FInHandler     : integer;        { marks that we in any event handler }
  86.     FThreadError   : Boolean;        { Error in Thread Handler            }
  87.     FStarted       : Boolean;        { device is now started              }
  88.     FStopIt        : Boolean;        { we should stop playing if possible }
  89.     FCloseIt       : Boolean;        { we should close device if possible }
  90.     FStopping      : Boolean;        { we actually stop the device        }
  91.     FClosing       : Boolean;        { we actually close the device       }
  92.     FBytesPlayed   : Longint;        { total bytes we have realy played   }
  93.     FMoreBuffers   : Boolean;        { more buffers to write ?            }
  94.     FTimeFormat    : TMMTimeFormats; { the actual time format for Position}
  95.     FInterval      : integer;        { trigger interval in ms             }
  96.     FAllocator     : TMMAllocator;
  97.     {$IFDEF WIN32}
  98.     FTriggerThread : TMMTriggerThread;{ Trigger Thread for callback handling}
  99.     DataSection    : TRtlCriticalSection;{ CriticalSection Object         }
  100.     DataSectionOK  : Boolean;        { CriticalSection is prepared        }
  101.     FGeneralEvent  : THandle;        { event object for general purpose   }
  102.     FTriggerEvent  : THandle;        { event object for notify handling   }
  103.     FCloseEvent    : THandle;        { event object to close the device   }
  104.     {$ENDIF}
  105.     FHandled       : Boolean;
  106.     { Events }
  107.     FOnError       : TNotifyEvent;   { There was an error                 }
  108.     FOnErrorEx     : TMMErrorEvent;  { There was an error                 }
  109.     FOnBufferFilled: TMMBufferEvent; { Wave buffer filled event           }
  110.     FOnOpen        : TNotifyEvent;   { Wave Device succ. opened           }
  111.     FOnStart       : TNotifyEvent;   { Wave Device succ. started          }
  112.     FOnPause       : TNotifyEvent;   { Wave Device succ. paused           }
  113.     FOnRestart     : TNotifyEvent;   { Wave Device succ. restarted        }
  114.     FOnStop        : TNotifyEvent;   { Wave Device succ. stopped          }
  115.     FOnClose       : TNotifyEvent;   { Wave Device succ. closed           }
  116.     procedure SetTimeFormat(aValue: TMMTimeFormats);
  117.     procedure SetInterval(aValue: integer);
  118.     function  GetPosition: Longint;
  119.     procedure TriggerHandler(var Msg: TMessage);
  120.     procedure AllocWaveHeader(var lpWaveHdr: PWaveHdr);
  121.     procedure FreeWaveHeader;
  122.     function  LoadWaveHeader(lpWaveHdr: PWaveHdr): Longint;
  123.     procedure QueueWaveHeader(lpWaveHdr: PWaveHdr);
  124.     procedure ProcessWaveHeader(lpWaveHdr: PWaveHdr);
  125.     {$IFDEF WIN32}
  126.     procedure InitThread;
  127.     procedure DoneThread;
  128.     procedure CloseEvents;
  129.     {$ENDIF}
  130.     procedure InitCritical;
  131.     procedure EnterCritical;
  132.     procedure LeaveCritical;
  133.     procedure DoneCritical;
  134.     procedure DoOpened;
  135.     procedure DoClosed;
  136.     procedure DoStarted;
  137.     procedure DoPaused;
  138.     procedure DoRestarted;
  139.     procedure DoStopped;
  140.     procedure DoBufferFilled(lpwh: PWaveHdr);
  141.     procedure DoBufferReady(lpwh: PWaveHdr);
  142.   protected
  143.     procedure SetPWaveFormat(aValue: PWaveFormatEx); override;
  144.     procedure SetBufferSize(aValue: Longint); override;
  145.     function  GetBufferSize: Longint; override;
  146.     procedure Error(Msg: string); virtual;
  147.     procedure Opened; override;
  148.     procedure Closed; override;
  149.     procedure Started; override;
  150.     procedure Paused; override;
  151.     procedure Restarted; override;
  152.     procedure Stopped; override;
  153.     procedure BufferReady(lpwh: PWaveHdr); override;
  154.     procedure BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean); override;
  155.   public
  156.     constructor Create(AOwner: TComponent); override;
  157.     destructor Destroy; override;
  158.     procedure Open; virtual;
  159.     procedure Close; virtual;
  160.     procedure Start; virtual;
  161.     procedure Pause; virtual;
  162.     procedure Restart; virtual;
  163.     procedure Stop; virtual;
  164.     {$IFDEF WIN32}
  165.     procedure SynchronizeVCL(VCLProc: TThreadMethod);
  166.     {$ENDIF}
  167.     property State: TMMTriggerState read FState;
  168.     property Position: Longint read GetPosition;
  169.   published
  170.     { Events }
  171.     property OnError: TNotifyEvent read FOnError write FOnError;
  172.     property OnErrorEx: TMMErrorEvent read FOnErrorEx write FOnErrorEx;
  173.     property OnOpen: TNotifyEvent read FOnOpen write FOnOpen;
  174.     property OnStart: TNotifyEvent read FOnStart write FOnStart;
  175.     property OnPause: TNotifyEvent read FOnPause write FOnPause;
  176.     property OnRestart: TNotifyEvent read FOnRestart write FOnRestart;
  177.     property OnStop: TNotifyEvent read FOnStop write FOnStop;
  178.     property OnClose: TNotifyEvent read FOnClose write FOnClose;
  179.     property OnBufferFilled: TMMBufferEvent read FOnBufferFilled write FOnBufferFilled;
  180.     property OnBufferReady;
  181.     property OnBufferLoad;
  182.     property Input;
  183.     property Output;
  184.     property BufferSize;
  185.     property Interval: integer read FInterval write SetInterval default 0;
  186.     property TimeFormat: TMMTimeFormats read FTimeFormat write SetTimeFormat default tfByte;
  187.   end;
  188. implementation
  189. uses consts;
  190. const
  191.      MM_WOM_STOP  = MM_USER+1;
  192. {-------------------------------------------------------------------------}
  193. procedure DebugStr(Level: integer; s: String);
  194. begin
  195. {$IFDEF _MMDEBUG}
  196.    if (s <> ' ') then s := 'Trigger: '+s;
  197.    DB_WriteStrLn(Level,s);
  198. {$ENDIF}
  199. end;
  200. {== TMMTrigger ===========================================================}
  201. constructor TMMTrigger.Create(AOwner: TComponent);
  202. begin
  203.    inherited Create(AOwner);
  204.    { Set defaults }
  205.    FState        := [trClose];
  206.    FBytesPlayed  := 0;
  207.    FTimeFormat   := tfByte;
  208.    FMoreBuffers  := False;
  209.    FClosing      := False;
  210.    FStopping     := False;
  211.    FInterval     := 0;
  212.    FAllocator    := TMMAllocator.Create;
  213.    {$IFDEF WIN32}
  214.    DataSectionOK := False;
  215.    {$ENDIF}
  216.    ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
  217.    if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
  218. end;
  219. {-- TMMTrigger -----------------------------------------------------------}
  220. destructor TMMTrigger.Destroy;
  221. begin
  222.    { Close the device if it's open }
  223.    Close;
  224.    { Destroy the window for callback notification }
  225.    if (FHandle <> 0) then DeallocateHwnd(FHandle);
  226.    if assigned(FAllocator) then FAllocator.Free;
  227.    inherited Destroy;
  228. end;
  229. {-- TMMTrigger -----------------------------------------------------------}
  230. procedure TMMTrigger.Error(Msg: string);
  231. begin
  232.    if assigned(FOnError) then FOnError(Self);
  233.    raise EMMTriggerError.Create(Msg);
  234. end;
  235. {-- TMMTrigger -----------------------------------------------------------}
  236. { Allocate memory for the Trigger header and buffer }
  237. procedure TMMTrigger.AllocWaveHeader(var lpWaveHdr: PWaveHdr);
  238. begin
  239.    if (lpWaveHdr = Nil) then
  240.    begin
  241.       { set up a wave header for playing and lock. }
  242.       lpWaveHdr := FAllocator.AllocBuffer(GHND,SizeOf(TMMWaveHdr) + BufferSize);
  243.       if lpWaveHdr = NIL then
  244.          Error(LoadResStr(IDS_HEADERMEMERROR));
  245.       { Data occurs directly after the header }
  246.       lpWaveHdr^.lpData         := PChar(lpWaveHdr) + sizeOf(TMMWaveHdr);
  247.       lpWaveHdr^.dwBufferLength := BufferSize;
  248.       lpWaveHdr^.dwBytesRecorded:= 0;
  249.       lpWaveHdr^.dwFlags        := 0;
  250.       lpWaveHdr^.dwLoops        := 0;
  251.       lpWaveHdr^.dwUser         := 0;
  252.       lpWaveHdr^.lpNext         := nil;
  253.    end;
  254. end;
  255. {-- TMMTrigger -----------------------------------------------------------}
  256. procedure TMMTrigger.FreeWaveHeader;
  257. begin
  258.    { unlock and free memory for TriggerHdr }
  259.    if FWaveHdr <> nil then
  260.    begin
  261.       FAllocator.FreeBuffer(Pointer(FWaveHdr));
  262.       FWaveHdr := Nil;
  263.    end;
  264. end;
  265. {-- TMMTrigger ------------------------------------------------------------}
  266. procedure TMMTrigger.SetInterval(aValue: integer);
  267. begin
  268.    if (aValue <> FInterval) then
  269.    begin
  270.       FInterval := Max(aValue,0);
  271.    end;
  272. end;
  273. {-- TMMTrigger ------------------------------------------------------------}
  274. procedure TMMTrigger.SetTimeFormat(aValue: TMMTimeFormats);
  275. begin
  276.    if (aValue <> FTimeFormat) then
  277.    begin
  278.       FTimeFormat := aValue;
  279.    end;
  280. end;
  281. {-- TMMTrigger ------------------------------------------------------------}
  282. function TMMTrigger.GetPosition: Longint;
  283. Var
  284.    Bytes: Longint;
  285. begin
  286.    Result := 0;
  287.    if (trOpen in FState) and (PWaveFormat <> Nil) and not FClosing then
  288.    begin
  289.       EnterCritical;
  290.       try
  291.          Bytes := FBytesPlayed;
  292.          case FTimeFormat of
  293.            tfMilliSecond: Result := wioBytesToTime(PWaveFormat,Bytes);
  294.            tfByte       : Result := Bytes;
  295.            tfSample     : Result := wioBytesToSamples(PWaveFormat,Bytes);
  296.          end;
  297.       finally
  298.          LeaveCritical;
  299.       end;
  300.    end;
  301. end;
  302. {-- TMMTrigger -----------------------------------------------------------}
  303. Procedure TMMTrigger.SetPWaveFormat(aValue: PWaveFormatEx);
  304. begin
  305.    { stop and close the device }
  306.    Close;
  307.    inherited SetPWaveFormat(aValue);
  308. end;
  309. {-- TMMTrigger -----------------------------------------------------------}
  310. Procedure TMMTrigger.SetBufferSize(aValue: Longint);
  311. begin
  312.    if (aValue <> inherited GetBufferSize) then
  313.    begin
  314.       if (trOpen in FState) then
  315.           Error(LoadResStr(IDS_PROPERTYOPEN));
  316.       if assigned(FAllocator) then
  317.          FAllocator.Discard;
  318.       inherited SetBufferSize(Max(aValue,MINBUFFERSIZE));
  319.    end;
  320. end;
  321. {-- TMMTrigger -----------------------------------------------------------}
  322. function TMMTrigger.GetBufferSize: Longint;
  323. begin
  324.    Result := inherited GetBufferSize;
  325. end;
  326. {-- TMMTrigger -----------------------------------------------------------}
  327. function TMMTrigger.LoadWaveHeader(lpWaveHdr: PWaveHdr): Longint;
  328. begin
  329.    FMoreBuffers := False;
  330.    BufferLoad(lpWaveHdr, FMoreBuffers);
  331.    Result := lpWaveHdr^.dwBytesRecorded;
  332.    if Result <= 0 then FMoreBuffers := False;
  333. end;
  334. {-- TMMTrigger -----------------------------------------------------------}
  335. procedure TMMTrigger.QueueWaveHeader(lpWaveHdr: PWaveHdr);
  336. begin
  337.    { this is the chance to modify the data in the buffer !!! }
  338.    DoBufferFilled(lpWaveHdr);
  339. end;
  340. {$IFDEF WIN32}
  341. {-- TMMTrigger -----------------------------------------------------------}
  342. procedure TMMTrigger.SynchronizeVCL(VCLProc: TThreadMethod);
  343. begin
  344.    if (FGeneralEvent <> 0) then
  345.    begin
  346.       FTriggerThread.Synchronize(VCLProc);
  347.    end
  348.    else VCLProc;
  349. end;
  350. {-- TMMTrigger -----------------------------------------------------------}
  351. procedure TMMTrigger.InitThread;
  352. begin
  353.    EnterCritical;
  354.    try
  355.       FThreadError := False;
  356.       { create event objects }
  357.       FGeneralEvent:= CreateEvent(nil, False, False, nil);
  358.       FTriggerEvent:= CreateEvent(nil, False, False, nil);
  359.       FCloseEvent  := CreateEvent(nil, False, False, nil);
  360.       { create the output thread }
  361.       FTriggerThread := TMMTriggerThread.CreateSuspended(Self);
  362.       if (FTriggerThread = nil) then
  363.           Error('Trigger:'#10#13+LoadResStr(IDS_THREADERROR));
  364.       FTriggerThread.FreeOnTerminate := True;
  365.       FTriggerThread.Resume;
  366.       {$IFDEF _MMDEBUG}
  367.       DebugStr(0,'Wait for Thread start...');
  368.       {$ENDIF}
  369.       { Wait for it to start... }
  370.       if WaitForSingleObject(FGeneralEvent, 5000) <> WAIT_OBJECT_0 then
  371.          Error('Trigger:'#10#13+LoadResStr(IDS_THREADERROR));
  372.       {$IFDEF _MMDEBUG}
  373.       DebugStr(0,'Thread Started');
  374.       {$ENDIF}
  375.    finally
  376.       LeaveCritical;
  377.    end;
  378. end;
  379. {-- TMMTrigger -----------------------------------------------------------}
  380. procedure TMMTrigger.DoneThread;
  381. begin
  382.    if (FGeneralEvent <> 0) and not FThreadError then
  383.    begin
  384.       while FTriggerThread.Suspended do FTriggerThread.Resume;
  385.       { Force the trigger thread to close... }
  386.       SetEvent(FCloseEvent);
  387.       { ...and wait for it to die }
  388.       WaitForSingleObject(FGeneralEvent, 5000);
  389.       { close all events and remove critical section }
  390.       CloseEvents;
  391.       {$IFDEF _MMDEBUG}
  392.       DebugStr(0,'Thread Terminated');
  393.       {$ENDIF}
  394.    end;
  395. end;
  396. {-- TMMTrigger -----------------------------------------------------------}
  397. procedure TMMTrigger.CloseEvents;
  398. begin
  399.    if (FGeneralEvent <> 0) then
  400.    begin
  401.       { release events }
  402.       CloseHandle(FGeneralEvent);
  403.       CloseHandle(FTriggerEvent);
  404.       CloseHandle(FCloseEvent);
  405.       FGeneralEvent := 0;
  406.       FTriggerEvent := 0;
  407.       FCloseEvent   := 0;
  408.       { Free the critical section }
  409.       DoneCritical;
  410.    end;
  411. end;
  412. {$ENDIF}
  413. {-- TMMTrigger -----------------------------------------------------------}
  414. procedure TMMTrigger.InitCritical;
  415. begin
  416.    {$IFDEF WIN32}
  417.    { create critical section object }
  418.    FillChar(DataSection, SizeOf(DataSection), 0);
  419.    InitializeCriticalSection(DataSection);
  420.    DataSectionOK := True;
  421.    {$ENDIF}
  422. end;
  423. {-- TMMTrigger -----------------------------------------------------------}
  424. procedure TMMTrigger.EnterCritical;
  425. begin
  426.    {$IFDEF WIN32}
  427.    if DataSectionOK then
  428.       EnterCriticalSection(DataSection);
  429.    {$ENDIF}
  430. end;
  431. {-- TMMTrigger -----------------------------------------------------------}
  432. procedure TMMTrigger.LeaveCritical;
  433. begin
  434.    {$IFDEF WIN32}
  435.    if DataSectionOK then
  436.       LeaveCriticalSection(DataSection);
  437.    {$ENDIF}
  438. end;
  439. {-- TMMTrigger -----------------------------------------------------------}
  440. procedure TMMTrigger.DoneCritical;
  441. begin
  442.    {$IFDEF WIN32}
  443.    if DataSectionOK then
  444.    begin
  445.       DataSectionOK := False;
  446.       DeleteCriticalSection(DataSection);
  447.    end;
  448.    {$ENDIF}
  449. end;
  450. {-- TMMTrigger -----------------------------------------------------------}
  451. Procedure TMMTrigger.Open;
  452. begin
  453.    if (PWaveFormat = Nil) then
  454.        Error('TriggerOpen:'#10#13+LoadResStr(IDS_NOFORMAT));
  455.    if (trOpen in FState) then Close;
  456.    if (Not(trOpen in FState)) and not FClosing then
  457.    begin
  458.       FClosing  := False;
  459.       FStopping := False;
  460.       try
  461.          FCloseIt := False;
  462.          { Create the window for callback notification }
  463.          if (FHandle = 0) then FHandle := AllocateHwnd(TriggerHandler);
  464.          inherited Opened;
  465.          { create critical section object }
  466.          InitCritical;
  467.          {$IFDEF WIN32}
  468.          InitThread;
  469.          {$ENDIF}
  470.          { create the Trigger header and buffer }
  471.          AllocWaveHeader(FWaveHdr);
  472.          FState := [trOpen];
  473.          DoOpened;
  474.       except
  475.          if assigned(FOnError) then FOnError(Self);
  476.          FState := [trOpen];
  477.          Close;
  478.          FState := [trClose];
  479.          raise;
  480.       end;
  481.    end;
  482. end;
  483. {-- TMMTrigger -----------------------------------------------------------}
  484. Procedure TMMTrigger.Close;
  485. begin
  486.    if (trOpen in FState) and (not FClosing or FCloseIt) then
  487.    try
  488.       FClosing := True;
  489.       { stop playing }
  490.       if (trPlay in FState) or (trPause in Fstate) then Stop;
  491.       { Close the device (finally!) }
  492.       if FStopIt then FCloseIt := True
  493.       else
  494.       begin
  495.          FCloseIt := False;
  496.          FState := [trClose];
  497.          { notify all other components }
  498.          inherited Closed;
  499.          { shot down the thread and remove critical section }
  500.          {$IFDEF WIN32}
  501.          DoneThread;
  502.          {$ENDIF}
  503.          { free header memory and remove }
  504.          FreeWaveHeader;
  505.          DoClosed;
  506.       end;
  507.    except
  508.       FClosing := False;
  509.    end;
  510. end;
  511. {-- TMMTrigger ------------------------------------------------------------}
  512. Procedure TMMTrigger.Start;
  513. begin
  514.    try
  515.       if not (trOpen in FState) then Open;
  516.       if (trOpen in FState) and not (trPlay in FState) then
  517.       begin
  518.          { setup for playing }
  519.          { reset the total bytes played counter }
  520.          FBytesPlayed := 0;
  521.          FInHandler := 0;
  522.          FStarted := False;
  523.          FStopIt := False;
  524.          FStopping := False;
  525.          { now notify all other components }
  526.          inherited Started;
  527.          FMoreBuffers := True;
  528.          FState := FState + [trPlay];
  529.          { fill the buffer }
  530.          if LoadWaveHeader(FWaveHdr) > 0 then
  531.             QueueWaveHeader(FWaveHdr);
  532.          DoStarted;
  533.       end;
  534.    except
  535.       if assigned(FOnError) then FOnError(Self);
  536.       Close;
  537.       FState := [trClose];
  538.       raise;
  539.    end;
  540. end;
  541. {-- TMMTrigger ------------------------------------------------------------}
  542. procedure TMMTrigger.Pause;
  543. begin
  544.    try
  545.       if not (trOpen in FState) then Open;
  546.       if (trOpen in FState) and (not (trPause in FState)) then
  547.       begin
  548.          if (trPlay in FState) then
  549.          try
  550.             EnterCritical;
  551.             {$IFDEF WIN32}
  552.             FTriggerThread.Suspend;
  553.             {$ENDIF}
  554.             FState := FState + [trPause];
  555.          finally
  556.             LeaveCritical;
  557.          end;
  558.          DoPaused;
  559.       end;
  560.    except
  561.       if assigned(FOnError) then FOnError(Self);
  562.       Close;
  563.       raise;
  564.    end;
  565. end;
  566. {-- TMMTrigger ------------------------------------------------------------}
  567. procedure TMMTrigger.Restart;
  568. begin
  569.    try
  570.       if (trPlay in FState) and (trPause in FState) then
  571.       begin
  572.          {$IFDEF WIN32}
  573.          FTriggerThread.Resume;
  574.          {$ENDIF}
  575.          DoRestarted;
  576.       end;
  577.    except
  578.       if assigned(FOnError) then FOnError(Self);
  579.       Close;
  580.       raise;
  581.    end;
  582. end;
  583. {-- TMMTrigger ------------------------------------------------------------}
  584. procedure TMMTrigger.Stop;
  585. begin
  586.    if (trPlay in FState) or (trPause in FState) then
  587.    begin
  588.       try
  589.          EnterCritical;
  590.          try
  591.             FStopping := True;
  592.          finally
  593.             LeaveCritical;
  594.          end;
  595.          DoStopped;
  596.       except
  597.         if assigned(FOnError) then FOnError(Self);
  598.         Close;
  599.         raise;
  600.       end;
  601.    end;
  602. end;
  603. {-- TMMTrigger -----------------------------------------------------------}
  604. procedure TMMTrigger.Opened;
  605. begin
  606.    Open;
  607. end;
  608. {-- TMMTrigger -----------------------------------------------------------}
  609. procedure TMMTrigger.Closed;
  610. begin
  611.    Close;
  612. end;
  613. {-- TMMTrigger -----------------------------------------------------------}
  614. procedure TMMTrigger.Started;
  615. begin
  616.    Start;
  617. end;
  618. {-- TMMTrigger -----------------------------------------------------------}
  619. procedure TMMTrigger.Paused;
  620. begin
  621.    Pause;
  622. end;
  623. {-- TMMTrigger -----------------------------------------------------------}
  624. procedure TMMTrigger.Restarted;
  625. begin
  626.    Restart;
  627. end;
  628. {-- TMMTrigger -----------------------------------------------------------}
  629. procedure TMMTrigger.Stopped;
  630. begin
  631.    Stop;
  632. end;
  633. {-- TMMTrigger -----------------------------------------------------------}
  634. procedure TMMTrigger.DoOpened;
  635. begin
  636.    if Assigned(FOnOpen) then FOnOpen(Self);
  637. end;
  638. {-- TMMTrigger -----------------------------------------------------------}
  639. procedure TMMTrigger.DoClosed;
  640. begin
  641.    FClosing := False;
  642.    if Assigned(FOnClose) then FOnClose(Self);
  643. end;
  644. {-- TMMTrigger -----------------------------------------------------------}
  645. procedure TMMTrigger.DoStarted;
  646. begin
  647.    if (FWaveHdr <> nil) and (FWaveHdr^.dwBytesRecorded > 0) then
  648.    begin
  649.       if not (trPause in FState) then
  650.       begin
  651.          { start the perpedum mobile :-) }
  652.          {$IFDEF WIN32}
  653.          SetEvent(FTriggerEvent);
  654.          {$ENDIF}
  655.       end;
  656.       if assigned(FOnStart) then FOnStart(Self);
  657.    end
  658.    else
  659.    try
  660.       inherited Stopped;
  661.       Error('TriggerStart:'#10#13+LoadResStr(IDS_STARTERROR));
  662.    finally
  663.       Close;
  664.    end;
  665. end;
  666. {-- TMMTrigger -----------------------------------------------------------}
  667. procedure TMMTrigger.DoPaused;
  668. begin
  669.    FState := FState + [trPause];
  670.    inherited Paused;
  671.    if assigned(FOnPause) then FOnPause(Self);
  672. end;
  673. {-- TMMTrigger -----------------------------------------------------------}
  674. procedure TMMTrigger.DoRestarted;
  675. begin
  676.    FState := FState - [trPause];
  677.    inherited Restarted;
  678.    if assigned(FOnRestart) then FOnRestart(Self);
  679. end;
  680. {-- TMMTrigger -----------------------------------------------------------}
  681. procedure TMMTrigger.DoStopped;
  682. begin
  683.    if (trPlay in FState) or (trPause in FState) then
  684.    begin
  685.       if (FInHandler > 0) then FStopIt := True
  686.       else
  687.       begin
  688.          FState := FState - [trPlay,trPause];
  689.          FStopIt := False;
  690.          { notify all other components }
  691.          inherited Stopped;
  692.          if assigned(FOnStop) then FOnStop(Self);
  693.          if FCloseIt then Close;
  694.       end;
  695.    end;
  696. end;
  697. {-- TMMTrigger -----------------------------------------------------------}
  698. procedure TMMTrigger.DoBufferFilled(lpwh: PWaveHdr);
  699. begin
  700.    if assigned(FOnBufferFilled) then FOnBufferFilled(Self, lpwh);
  701. end;
  702. {-- TMMTrigger -----------------------------------------------------------}
  703. procedure TMMTrigger.BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean);
  704. begin
  705.    with PMMWaveHdr(lpwh)^ do
  706.    begin
  707.       wh.dwBufferLength := BufferSize;
  708.       wh.dwBytesRecorded := 0;
  709.       LoopRec.dwLoop := False;
  710.       inherited BufferLoad(lpwh, MoreBuffers);
  711.       wh.dwBufferLength := wh.dwBytesRecorded;
  712.    end;
  713. end;
  714. {-- TMMTrigger -----------------------------------------------------------}
  715. procedure TMMTrigger.BufferReady(lpwh: PWaveHdr);
  716. begin
  717. end;
  718. {-- TMMTrigger -----------------------------------------------------------}
  719. procedure TMMTrigger.DoBufferReady(lpwh: PWaveHdr);
  720. begin
  721.    { buffer has returned from driver, notify the other components }
  722.    inherited BufferReady(lpwh);
  723. end;
  724. {-- TMMTrigger -----------------------------------------------------------}
  725. procedure TMMTrigger.ProcessWaveHeader(lpWaveHdr: PWaveHdr);
  726. begin
  727.    if (trPlay in FState) and not FStopping then
  728.    begin
  729.       inc(FInHandler);
  730.       try
  731.          EnterCritical;
  732.          try
  733.             inc(FBytesPlayed, lpWaveHdr^.dwBufferLength);
  734.          finally
  735.             LeaveCritical;
  736.          end;
  737.          try
  738.             DoBufferReady(lpWaveHdr);
  739.             {$IFDEF _MMDEBUG}
  740.             DebugStr(2,'DoBufferReady Done...');
  741.             {$ENDIF}
  742.             if FMoreBuffers and not FStopIt then
  743.             begin
  744.                { send the next buffer to the driver }
  745.                if LoadWaveHeader(lpWaveHdr) <= 0 then
  746.                   Error(LoadResStr(IDS_FILLERROR));
  747.                if not FStopIt then
  748.                begin
  749.                   QueueWaveHeader(lpWaveHdr);
  750.                   if not FMoreBuffers then DoBufferReady(lpWaveHdr);
  751.                end;
  752.             end;
  753.          except
  754.             FHandled := False;
  755.             if assigned(FOnError) then FOnError(Self);
  756.             if assigned(FOnErrorEx) then FOnErrorEx(Self,FHandled);
  757.             if not FHandled then
  758.                raise;
  759.          end;
  760.       finally
  761.          dec(FInHandler);
  762.          { can we stop it ? }
  763.          if (FInHandler = 0) then  { no more buffers, stop }
  764.              if FStopIt or not FMoreBuffers then
  765.              begin
  766.                 FStopping := True;
  767.                 PostMessage(FHandle,MM_WOM_STOP,0,0);
  768.              end;
  769.       end;
  770.    end;
  771. end;
  772. {-- TMMTrigger -----------------------------------------------------------}
  773. procedure TMMTrigger.TriggerHandler(Var Msg: TMessage );
  774. begin
  775.   with Msg do
  776.   try
  777.       case msg of
  778.          MM_WOM_STOP: begin
  779.                          { should stop the device }
  780.                          Stop;
  781.                          exit;
  782.                       end;
  783.       end;
  784.       Result := DefWindowProc(FHandle, Msg, wParam, lParam);
  785.   except
  786.      Close;
  787.      Application.HandleException(Self);
  788.   end;
  789. end;
  790. {$IFDEF WIN32}
  791. {-------------------------------------------------------------------------}
  792. procedure TMMTriggerThread.Execute;
  793. {- Wait for and process trigger messages }
  794. var
  795.    Res  : DWORD;
  796.    {$IFDEF _MMDEBUG}
  797.    Err: DWORD;
  798.    {$ENDIF}
  799.    Handles: array[0..1] of THandle;
  800. begin
  801.    with TMMTrigger(Owner) do
  802.    try
  803.       {$IFDEF _MMDEBUG}
  804.       DebugStr(0,'Setting Thread Priority');
  805.       {$ENDIF}
  806.       Priority := TRIGGER_PRIORITY;
  807.       Handles[0] := FCloseEvent;
  808.       Handles[1] := FTriggerEvent;
  809.       {$IFDEF _MMDEBUG}
  810.       DebugStr(0,'Setting TriggerEvent,ready to go !');
  811.       {$ENDIF}
  812.       { Ready to go, set the general event }
  813.       SetEvent(FGeneralEvent);
  814.       { Repeat until device is closed }
  815.       while not Terminated do
  816.       try
  817.          Res := WaitForMultipleObjects(2, @Handles, False, INFINITE);
  818.          case Res of
  819.               WAIT_FAILED:       { Wait failed.  Shouldn't happen. }
  820.               begin
  821.                  {$IFDEF _MMDEBUG}
  822.                  Err := GetLastError;
  823.                  DebugStr(0,'Wait Failed... Error: '+SysErrorMessage(Err));
  824.                  {$ENDIF}
  825.                  Continue;
  826.               end;
  827.               WAIT_OBJECT_0:     { CloseEvent signaled!            }
  828.               begin
  829.                  {$IFDEF _MMDEBUG}
  830.                  DebugStr(0,'CloseEvent signaled...');
  831.                  {$ENDIF}
  832.                  { Finished here, okay to close device }
  833.                  exit;
  834.               end;
  835.               WAIT_OBJECT_0+1:    { TriggerEvent received.         }
  836.               begin
  837.                  {$IFDEF _MMDEBUG}
  838.                  DebugStr(2,'Trigger message reveived...');
  839.                  {$ENDIF}
  840.                  if not FStopping then ProcessWaveHeader(FWaveHdr);
  841.                  if not FStopping then Sleep(Max(FInterval,1));
  842.                  if not FStopping then SetEvent(FTriggerEvent);
  843.                  if not FStopping then WinYield(Application.Handle);
  844.                  Continue;
  845.               end;
  846.          end;
  847.       except
  848.          FThreadError := True;
  849.          Application.HandleException(nil);
  850.          if trOpen in FState then Close;
  851.          CloseEvents;
  852.          exit;
  853.       end;
  854.    finally
  855.      if not FThreadError then SetEvent(FGeneralEvent);
  856.      {$IFDEF _MMDEBUG}
  857.      DebugStr(0,'Exit Thread-Proc');
  858.      {$ENDIF}
  859.    end;
  860. end;
  861. {$ENDIF}
  862. {$IFDEF _MMDEBUG}
  863. initialization
  864.    DB_Level(DEBUGLEVEl);
  865.    DB_Clear;
  866. {$ENDIF}
  867. end.