MMTrigg.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:29k
- {========================================================================}
- {= (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 -----------------------------------------------------------}
- procedure TMMTrigger.DoneCritical;
- begin
- {$IFDEF WIN32}
- if DataSectionOK then
- begin
- DataSectionOK := False;
- DeleteCriticalSection(DataSection);
- end;
- {$ENDIF}
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- Procedure TMMTrigger.Open;
- begin
- if (PWaveFormat = Nil) then
- Error('TriggerOpen:'#10#13+LoadResStr(IDS_NOFORMAT));
- if (trOpen in FState) then Close;
- if (Not(trOpen in FState)) and not FClosing then
- begin
- FClosing := False;
- FStopping := False;
- try
- FCloseIt := False;
- { Create the window for callback notification }
- if (FHandle = 0) then FHandle := AllocateHwnd(TriggerHandler);
- inherited Opened;
- { create critical section object }
- InitCritical;
- {$IFDEF WIN32}
- InitThread;
- {$ENDIF}
- { create the Trigger header and buffer }
- AllocWaveHeader(FWaveHdr);
- FState := [trOpen];
- DoOpened;
- except
- if assigned(FOnError) then FOnError(Self);
- FState := [trOpen];
- Close;
- FState := [trClose];
- raise;
- end;
- end;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- Procedure TMMTrigger.Close;
- begin
- if (trOpen in FState) and (not FClosing or FCloseIt) then
- try
- FClosing := True;
- { stop playing }
- if (trPlay in FState) or (trPause in Fstate) then Stop;
- { Close the device (finally!) }
- if FStopIt then FCloseIt := True
- else
- begin
- FCloseIt := False;
- FState := [trClose];
- { notify all other components }
- inherited Closed;
- { shot down the thread and remove critical section }
- {$IFDEF WIN32}
- DoneThread;
- {$ENDIF}
- { free header memory and remove }
- FreeWaveHeader;
- DoClosed;
- end;
- except
- FClosing := False;
- end;
- end;
- {-- TMMTrigger ------------------------------------------------------------}
- Procedure TMMTrigger.Start;
- begin
- try
- if not (trOpen in FState) then Open;
- if (trOpen in FState) and not (trPlay in FState) then
- begin
- { setup for playing }
- { reset the total bytes played counter }
- FBytesPlayed := 0;
- FInHandler := 0;
- FStarted := False;
- FStopIt := False;
- FStopping := False;
- { now notify all other components }
- inherited Started;
- FMoreBuffers := True;
- FState := FState + [trPlay];
- { fill the buffer }
- if LoadWaveHeader(FWaveHdr) > 0 then
- QueueWaveHeader(FWaveHdr);
- DoStarted;
- end;
- except
- if assigned(FOnError) then FOnError(Self);
- Close;
- FState := [trClose];
- raise;
- end;
- end;
- {-- TMMTrigger ------------------------------------------------------------}
- procedure TMMTrigger.Pause;
- begin
- try
- if not (trOpen in FState) then Open;
- if (trOpen in FState) and (not (trPause in FState)) then
- begin
- if (trPlay in FState) then
- try
- EnterCritical;
- {$IFDEF WIN32}
- FTriggerThread.Suspend;
- {$ENDIF}
- FState := FState + [trPause];
- finally
- LeaveCritical;
- end;
- DoPaused;
- end;
- except
- if assigned(FOnError) then FOnError(Self);
- Close;
- raise;
- end;
- end;
- {-- TMMTrigger ------------------------------------------------------------}
- procedure TMMTrigger.Restart;
- begin
- try
- if (trPlay in FState) and (trPause in FState) then
- begin
- {$IFDEF WIN32}
- FTriggerThread.Resume;
- {$ENDIF}
- DoRestarted;
- end;
- except
- if assigned(FOnError) then FOnError(Self);
- Close;
- raise;
- end;
- end;
- {-- TMMTrigger ------------------------------------------------------------}
- procedure TMMTrigger.Stop;
- begin
- if (trPlay in FState) or (trPause in FState) then
- begin
- try
- EnterCritical;
- try
- FStopping := True;
- finally
- LeaveCritical;
- end;
- DoStopped;
- except
- if assigned(FOnError) then FOnError(Self);
- Close;
- raise;
- end;
- end;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.Opened;
- begin
- Open;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.Closed;
- begin
- Close;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.Started;
- begin
- Start;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.Paused;
- begin
- Pause;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.Restarted;
- begin
- Restart;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.Stopped;
- begin
- Stop;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.DoOpened;
- begin
- if Assigned(FOnOpen) then FOnOpen(Self);
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.DoClosed;
- begin
- FClosing := False;
- if Assigned(FOnClose) then FOnClose(Self);
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.DoStarted;
- begin
- if (FWaveHdr <> nil) and (FWaveHdr^.dwBytesRecorded > 0) then
- begin
- if not (trPause in FState) then
- begin
- { start the perpedum mobile :-) }
- {$IFDEF WIN32}
- SetEvent(FTriggerEvent);
- {$ENDIF}
- end;
- if assigned(FOnStart) then FOnStart(Self);
- end
- else
- try
- inherited Stopped;
- Error('TriggerStart:'#10#13+LoadResStr(IDS_STARTERROR));
- finally
- Close;
- end;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.DoPaused;
- begin
- FState := FState + [trPause];
- inherited Paused;
- if assigned(FOnPause) then FOnPause(Self);
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.DoRestarted;
- begin
- FState := FState - [trPause];
- inherited Restarted;
- if assigned(FOnRestart) then FOnRestart(Self);
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.DoStopped;
- begin
- if (trPlay in FState) or (trPause in FState) then
- begin
- if (FInHandler > 0) then FStopIt := True
- else
- begin
- FState := FState - [trPlay,trPause];
- FStopIt := False;
- { notify all other components }
- inherited Stopped;
- if assigned(FOnStop) then FOnStop(Self);
- if FCloseIt then Close;
- end;
- end;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.DoBufferFilled(lpwh: PWaveHdr);
- begin
- if assigned(FOnBufferFilled) then FOnBufferFilled(Self, lpwh);
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean);
- begin
- with PMMWaveHdr(lpwh)^ do
- begin
- wh.dwBufferLength := BufferSize;
- wh.dwBytesRecorded := 0;
- LoopRec.dwLoop := False;
- inherited BufferLoad(lpwh, MoreBuffers);
- wh.dwBufferLength := wh.dwBytesRecorded;
- end;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.BufferReady(lpwh: PWaveHdr);
- begin
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.DoBufferReady(lpwh: PWaveHdr);
- begin
- { buffer has returned from driver, notify the other components }
- inherited BufferReady(lpwh);
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.ProcessWaveHeader(lpWaveHdr: PWaveHdr);
- begin
- if (trPlay in FState) and not FStopping then
- begin
- inc(FInHandler);
- try
- EnterCritical;
- try
- inc(FBytesPlayed, lpWaveHdr^.dwBufferLength);
- finally
- LeaveCritical;
- end;
- try
- DoBufferReady(lpWaveHdr);
- {$IFDEF _MMDEBUG}
- DebugStr(2,'DoBufferReady Done...');
- {$ENDIF}
- if FMoreBuffers and not FStopIt then
- begin
- { send the next buffer to the driver }
- if LoadWaveHeader(lpWaveHdr) <= 0 then
- Error(LoadResStr(IDS_FILLERROR));
- if not FStopIt then
- begin
- QueueWaveHeader(lpWaveHdr);
- if not FMoreBuffers then DoBufferReady(lpWaveHdr);
- end;
- end;
- except
- FHandled := False;
- if assigned(FOnError) then FOnError(Self);
- if assigned(FOnErrorEx) then FOnErrorEx(Self,FHandled);
- if not FHandled then
- raise;
- end;
- finally
- dec(FInHandler);
- { can we stop it ? }
- if (FInHandler = 0) then { no more buffers, stop }
- if FStopIt or not FMoreBuffers then
- begin
- FStopping := True;
- PostMessage(FHandle,MM_WOM_STOP,0,0);
- end;
- end;
- end;
- end;
- {-- TMMTrigger -----------------------------------------------------------}
- procedure TMMTrigger.TriggerHandler(Var Msg: TMessage );
- begin
- with Msg do
- try
- case msg of
- MM_WOM_STOP: begin
- { should stop the device }
- Stop;
- exit;
- end;
- end;
- Result := DefWindowProc(FHandle, Msg, wParam, lParam);
- except
- Close;
- Application.HandleException(Self);
- end;
- end;
- {$IFDEF WIN32}
- {-------------------------------------------------------------------------}
- procedure TMMTriggerThread.Execute;
- {- Wait for and process trigger messages }
- var
- Res : DWORD;
- {$IFDEF _MMDEBUG}
- Err: DWORD;
- {$ENDIF}
- Handles: array[0..1] of THandle;
- begin
- with TMMTrigger(Owner) do
- try
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Setting Thread Priority');
- {$ENDIF}
- Priority := TRIGGER_PRIORITY;
- Handles[0] := FCloseEvent;
- Handles[1] := FTriggerEvent;
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Setting TriggerEvent,ready to go !');
- {$ENDIF}
- { Ready to go, set the general event }
- SetEvent(FGeneralEvent);
- { Repeat until device is 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}
- Err := GetLastError;
- DebugStr(0,'Wait Failed... Error: '+SysErrorMessage(Err));
- {$ENDIF}
- Continue;
- end;
- WAIT_OBJECT_0: { CloseEvent signaled! }
- begin
- {$IFDEF _MMDEBUG}
- DebugStr(0,'CloseEvent signaled...');
- {$ENDIF}
- { Finished here, okay to close device }
- exit;
- end;
- WAIT_OBJECT_0+1: { TriggerEvent received. }
- begin
- {$IFDEF _MMDEBUG}
- DebugStr(2,'Trigger message reveived...');
- {$ENDIF}
- if not FStopping then ProcessWaveHeader(FWaveHdr);
- if not FStopping then Sleep(Max(FInterval,1));
- if not FStopping then SetEvent(FTriggerEvent);
- if not FStopping then WinYield(Application.Handle);
- Continue;
- end;
- end;
- except
- FThreadError := True;
- Application.HandleException(nil);
- if trOpen in FState then Close;
- CloseEvents;
- exit;
- end;
- finally
- if not FThreadError then SetEvent(FGeneralEvent);
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Exit Thread-Proc');
- {$ENDIF}
- end;
- end;
- {$ENDIF}
- {$IFDEF _MMDEBUG}
- initialization
- DB_Level(DEBUGLEVEl);
- DB_Clear;
- {$ENDIF}
- end.