MMWavIn.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:61k
- {========================================================================}
- {= (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/index.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: 25.11.98 - 13:23:40 $ =}
- {========================================================================}
- unit MMWavIn;
- {$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,
- MMObj,
- MMString,
- MMDSPObj,
- MMDSPMtr,
- MMRegs,
- MMPCMSup,
- MMAlloc,
- MMWaveIO
- {$IFDEF _MMDEBUG}
- ,MMDebug
- {$ENDIF};
- {$IFDEF _MMDEBUG}
- {$DEFINE NUMERATE}
- const
- DEBUGLEVEL = 0; { 0,1,2 }
- {$ENDIF}
- const
- {$IFDEF CBUILDER3} {$EXTERNALSYM MAXERRORLENGTH} {$ENDIF}
- MAXERRORLENGTH = 255;
- {$IFDEF CBUILDER3} {$EXTERNALSYM MAXINBUFFERS} {$ENDIF}
- MAXINBUFFERS = 500;
- {$IFDEF CBUILDER3} {$EXTERNALSYM MINBUFFERSIZE} {$ENDIF}
- MINBUFFERSIZE = 32;
- type
- EMMWaveInError = class(Exception);
- TMMWaveInStates = (wisClose, wisOpen, wisRecord,wisPause);
- TMMWaveInState = set of TMMWaveInStates;
- { Pointers to waveIn headers }
- TMMWaveInHdrs = array[0..MAXINBUFFERS-1] of PWaveHdr;
- TMMCustomWaveIn = class;
- {$IFDEF WIN32}
- {-- TMMWaveInThread ----------------------------------------------------}
- TMMWaveInThread = class(TMMDSPThread)
- private
- procedure Execute; override;
- end;
- {$ENDIF}
- {-- TMMCustomWaveIn ---------------------------------------------------------}
- TMMCustomWaveIn = class(TMMCustomSoundComponent)
- private
- FHandle : THandle; { handle used for callback window }
- FPriority : TThreadPriority;{ thread priority }
- FDeviceID : TMMDeviceID; { WAVEIN device ID }
- FHWaveIn : HWaveIn; { Handle to input device }
- FState : TMMWaveInState; { Current device state }
- FWaveInHdrs : TMMWaveInHdrs; { WaveIn Headers and Buffers }
- FBufferIndex : integer; { the current Header/BufferIndex }
- FCallbackMode : TMMCBMode; { use Window or Callback function }
- FError : integer; { Last WaveIn Error }
- FNumdevs : integer; { Num. of input devices on system }
- FWaveInCaps : TWaveInCaps; { Stuff from WAVEINCAPS }
- FProductName : String;
- FDriverVersion : integer; { Specifies the driver version }
- { high-order byte is major version }
- { low-order byte is minor version }
- FInHandler : integer; { marks that we in any event handler }
- 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 }
- FReseting : Boolean; { we actually resting the device }
- FPosted : Boolean;
- FBytesRecorded : Longint; { total bytes we have recorded }
- FLastPosition : Cardinal; { the last playback position }
- FWrapArrounds : Cardinal; { number of position wrap-arrounds }
- FWrapSize : Cardinal; { where has the position wrapped ? }
- FNumBuffers : integer; { number of buffers for queue }
- FBufferCounter : integer; { buffer counter for buffers in use }
- FTimeFormat : TMMTimeFormats; { the actual time format for Position}
- FWaveFormat : TWaveFormatEx; { internal WaveFormatEx }
- FMode : TMMMode; { Mono / Stereo }
- FBits : TMMBits; { 8 / 16 bits }
- FRate : Longint; { SampleRate }
- FMaxRecTime : Longint; { maximal recording time }
- FMaxRecBytes : Longint;
- FAllocator : TMMAllocator;
- {$IFDEF WIN32}
- FThreadError : Boolean; { Erro in Thread handler }
- FInThread : TMMWaveInThread;{ Input Thread for callback handling }
- DataSection : TRtlCriticalSection;{ CriticalSection Object }
- DataSEctionOK : Boolean; { CriticalSection prepared }
- FInEvent : THandle; { event object for notify handling }
- FCloseEvent : THandle; { event object to close the device }
- {$ENDIF}
- { Events }
- FOnError : TNotifyEvent; { Error occured }
- 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 }
- function WaveInErrorString(WError: integer): String;
- procedure SetPriority(aValue: TThreadPriority);
- procedure SetMode(aValue: TMMMode);
- procedure SetBits(aValue: TMMBits);
- procedure SetSampleRate(aValue: Longint);
- procedure SetTimeFormat(aValue: TMMTimeFormats);
- procedure SetMaxRecTime(aValue: Longint);
- procedure CalcMaxRecBytes;
- function GetSamplePosition: Cardinal;
- function GetInternalPosition: int64;
- function GetPosition: MM_int64;
- function GetPositionHigh: Cardinal;
- function GetPosition64: int64;
- procedure SetWaveParams;
- procedure WaveInHandler(VAR Msg: TMessage);
- procedure AllocWaveHeaders;
- procedure FreeWaveHeaders;
- procedure PrepareWaveHeaders;
- procedure UnPrepareWaveHeaders;
- procedure AddWaveHeader(lpWaveHdr: PWaveHdr);
- procedure ProcessWaveHeader(lpWaveHdr: PWaveHdr);
- {$IFDEF WIN32}
- procedure InitThread;
- procedure DoneThread;
- procedure CloseEvents;
- {$ENDIF}
- procedure InitCritical;
- procedure EnterCritical;
- procedure LeaveCritical;
- procedure DoneCritical;
- protected
- {-- Private Waveform API declarations to be overridden in descendants --}
- waveInGetNumDevs: function: UINT; stdcall;
- waveInGetDevCaps: function(hwin: HWAVEIN; lpCaps: PWaveInCaps; uSize: UINT): MMRESULT; stdcall;
- waveInGetErrorText: function(mmrError: MMRESULT; lpText: PChar; uSize: UINT): MMRESULT; stdcall;
- waveInOpen: function(lphWaveIn: PHWAVEIN; uDeviceID: UINT; lpFormatEx: PWaveFormatEx; dwCallback, dwInstance, dwFlags: DWORD): MMRESULT; stdcall;
- waveInClose: function(hWaveIn: HWAVEIN): MMRESULT; stdcall;
- waveInPrepareHeader: function(hWaveIn: HWAVEIN; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
- waveInUnprepareHeader: function(hWaveIn: HWAVEIN; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
- waveInAddBuffer: function(hWaveIn: HWAVEIN; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
- waveInStart: function(hWaveIn: HWAVEIN): MMRESULT; stdcall;
- waveInStop: function(hWaveIn: HWAVEIN): MMRESULT; stdcall;
- waveInReset: function(hWaveIn: HWAVEIN): MMRESULT; stdcall;
- waveInGetPosition: function(hWaveIn: HWAVEIN; lpInfo: PMMTime; uSize: UINT): MMRESULT; stdcall;
- waveInGetID: function(hWaveIn: HWAVEIN; lpuDeviceID: PUINT): MMRESULT; stdcall;
- { And set up all this stuff! }
- procedure SetupWaveEngine; virtual; abstract;
- procedure SetPWaveFormat(aValue: PWaveFormatEx); override;
- procedure SetBufferSize(aValue: Longint); override;
- function GetBufferSize: Longint; override;
- procedure SetNumBuffers(aValue: integer); override;
- function GetNumBuffers: integer; override;
- procedure SetDeviceID(aValue: TMMDeviceID); override;
- function GetDeviceID: TMMDeviceID; override;
- procedure SetProductName(aValue: string); override;
- function GetProductName: string; override;
- procedure SetCallBackMode(aValue: TMMCBMode); override;
- function GetCallBackMode: TMMCBMode; override;
- procedure Opened; override;
- procedure Started; override;
- procedure Paused; override;
- procedure Restarted; override;
- procedure Stopped; override;
- procedure Closed; override;
- procedure BufferReady(lpwh: PWaveHdr); override;
- procedure Error(Msg: string); virtual;
- 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;
- function QueryDevice(aDeviceID: TMMDeviceID; pwfx: PWaveFormatEx): Boolean;
- {$IFDEF WIN32}
- { maybe you must syncronize anything if UseThread = True ? }
- procedure SynchronizeVCL(VCLProc: TThreadMethod);
- {$ENDIF}
- property Handle: HWaveIn read FHWaveIn;
- property WaveInCaps: TWaveInCaps read FWaveInCaps;
- property Numdevs: integer read FNumdevs;
- property State: TMMWaveInState read FState;
- property DriverVersion: integer read FDriverVersion;
- property BytesRecorded: Longint read FBytesRecorded;
- property Position: MM_int64 read GetPosition;
- property PositionHigh: Cardinal read GetPositionHigh;
- property Position64: int64 read GetPosition64;
- property BufferIndex: integer read FBufferIndex;
- property PWaveFormat;
- {$IFNDEF CBUILDER3}
- property WaveHdrs: TMMWaveInHdrs read FWaveInHdrs;
- {$ENDIf}
- published
- { Events }
- property OnError: TNotifyEvent read FOnError write FOnError;
- 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 OnBufferReady;
- property Output;
- property BufferSize;
- property CallBackMode;
- property DeviceID;
- property NumBuffers;
- property ProductName;
- property Mode: TMMMode read FMode write SetMode default mMono;
- property BitLength: TMMBits read FBits write SetBits default b8Bit;
- property SampleRate: Longint read FRate write SetSampleRate default 11025;
- property TimeFormat: TMMTimeFormats read FTimeFormat write SetTimeFormat default tfByte;
- property MaxRecordTime: Longint read FMaxRecTime write SetMaxRecTime default -1;
- property Priority: TThreadPriority read FPriority write SetPriority default tpHigher;
- end;
- {-- TMMWaveIn ---------------------------------------------------------------}
- TMMWaveIn = class(TMMCustomWaveIn)
- protected
- procedure SetupWaveEngine; override;
- end;
- function WaveInGetDeviceName(DeviceID: TMMDeviceID): String;
- function WaveInReady(DeviceID: TMMDeviceID): Boolean;
- function DeviceFullDuplex(DeviceID: TMMDeviceID; pwfx: PWaveFormatEx): Boolean;
- var
- Devices: TStringList = nil;
-
- implementation
- uses consts;
- const
- MM_WIM_STOP = MM_USER+2;
- {$IFNDEF WIN32}
- { Bug fix for Error in Delphi 1.0 MMSystem declaration }
- function WaveInClose(hWaveIn: THandle): Word; far; external 'MMSYSTEM' index 505;
- {$ENDIF}
- procedure WaveInFunc(hWaveIn:HWaveIn;wMsg:UINT;dwInstance,dwParam1,dwParam2:Longint);
- export;{$IFDEF WIN32}stdcall;{$ENDIF}forward;
- {$IFDEF _MMDEBUG}
- {-------------------------------------------------------------------------}
- procedure DebugStr(Level: integer; s: String);
- begin
- if (s <> ' ') then s := 'WaveIn: '+s;
- DB_WriteStrLn(Level,s);
- end;
- {$ENDIF}
- {-------------------------------------------------------------------------}
- function DeviceFullDuplex(DeviceID: TMMDeviceID; pwfx: PWaveFormatEx): Boolean;
- var
- InHandle,OutHandle: HWAVEOUT;
- Error: MMRESULT;
- wfx: TWaveFormatEx;
- begin
- Result := False;
- if (DeviceID < waveOutGetNumDevs) and (DeviceID >= integer(WAVE_MAPPER)) then
- try
- OutHandle := 0;
- InHandle := 0;
- if (pwfx = nil) then
- begin
- pwfx := @wfx;
- pcmBuildWaveHeader(pwfx, 16, 2, 22050);
- end;
- {$IFDEF WIN32}
- Error := WaveInOpen(@InHandle, DeviceId, MMSystem.PWaveFormatEx(pwfx), 0, 0, CALLBACK_NULL);
- {$ELSE}
- Error := WaveInOpen(@InHandle, DeviceId, Pointer(pwfx), 0, 0, CALLBACK_NULL);
- {$ENDIF}
- if (Error = MMSYSERR_NOERROR) then
- begin
- {$IFDEF WIN32}
- Error := WaveOutOpen(@OutHandle, DeviceID, MMSystem.PWaveFormatEx(pwfx), 0, 0, CALLBACK_NULL);
- {$ELSE}
- Error := WaveOutOpen(@OutHandle, DeviceID, Pointer(pwfx), 0, 0, CALLBACK_NULL);
- {$ENDIF}
- if (Error = MMSYSERR_NOERROR) then Result := True;
- end;
- finally
- if (OutHandle <> 0) then WaveOutClose(OutHandle);
- if (InHandle <> 0) then WaveInClose(InHandle);
- end;
- end;
- {-------------------------------------------------------------------------}
- function WaveInReady(DeviceID: TMMDeviceID): Boolean;
- var
- InHandle: HWAVEOUT;
- Error: MMRESULT;
- wfx: TWaveFormatEx;
- begin
- Result := False;
- if (DeviceID < waveInGetNumDevs) and (DeviceID >= integer(WAVE_MAPPER)) then
- try
- InHandle := 0;
- pcmBuildWaveHeader(@wfx, 8, 1, 22050);
- {$IFDEF WIN32}
- Error := WaveInOpen(@InHandle, DeviceId, MMSystem.PWaveFormatEx(@wfx), 0, 0, CALLBACK_NULL);
- {$ELSE}
- Error := WaveInOpen(@InHandle, DeviceId, Pointer(@wfx), 0, 0, CALLBACK_NULL);
- {$ENDIF}
- if (Error = MMSYSERR_NOERROR) then
- begin
- Result := True;
- end;
- finally
- if (InHandle <> 0) then WaveInClose(InHandle);
- end;
- end;
- {-------------------------------------------------------------------------}
- function WaveInGetDeviceName(DeviceID: TMMDeviceID): String;
- var
- Caps : TWaveInCaps;
- begin
- Result := '';
- if (DeviceID < waveInGetNumDevs) and (DeviceID >= integer(WAVE_MAPPER)) then
- begin
- { Set the name and other WAVEOUTCAPS properties to match the ID }
- if waveInGetDevCaps(DeviceID, @Caps, sizeof(TWaveInCaps)) = 0 then
- Result := StrPas(Caps.szPname);
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- constructor TMMCustomWaveIn.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetupWaveEngine;
- { Set defaults }
- FHWaveIn := 0;
- FState := [wisClose];
- FError := 0;
- FNumBuffers := 10;
- FMode := mMono;
- FBits := b8Bit;
- FRate := 11025;
- FProductName := '';
- FDriverVersion := 0;
- FBytesRecorded := 0;
- FTimeFormat := tfByte;
- FCallBackMode := cmWindow;
- FStopping := False;
- FPosted := False;
- FClosing := False;
- FReseting := False;
- FMaxRecTime := -1;
- FMaxRecBytes := MaxLongint;
- FPriority := tpHigher;
- FAllocator := TMMAllocator.Create;
- FBufferIndex := 0;
- { clear all pointers to Nil }
- FillChar(FWaveInHdrs, sizeOf(TMMWaveInHdrs), 0);
- FNumDevs := waveInGetNumDevs;
- SetWaveParams;
- SetDeviceID(0);
- {$IFDEF WIN32}
- DataSectionOK := False;
- {$ENDIF}
- { Create the window for callback notification }
- if not (csDesigning in ComponentState) then
- FHandle := AllocateHwnd(WaveInHandler);
- ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
- if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- destructor TMMCustomWaveIn.Destroy;
- begin
- { Close the device if it's open }
- if (FHWaveIn <> 0) then Close;
- { Destroy the window for callback notification }
- if (FHandle <> 0) then DeallocateHwnd(FHandle);
- if (FAllocator <> nil) then FAllocator.Free;
- inherited Destroy;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.Error(Msg: string);
- begin
- if assigned(FOnError) then FOnError(Self);
- raise EMMWaveInError.Create(Msg);
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- { Allocate memory for the WaveIn header and buffers }
- procedure TMMCustomWaveIn.AllocWaveHeaders;
- Var
- i: integer;
- lpwh: PWaveHdr;
- begin
- if (BufferSize > 0) then
- begin
- for i := 0 to FNumBuffers-1 do
- begin
- if (FWaveInHdrs[i] = Nil) then
- begin
- { set up a wave header for recording and lock }
- lpwh := FAllocator.AllocBuffer(GPTR, SizeOf(TMMWaveHdr) + BufferSize);
- if lpwh = NIL then
- Error(LoadResStr(IDS_HEADERMEMERROR));
- { Data occurs directly after the header }
- lpwh^.lpData := PChar(lpwh) + sizeOf(TMMWaveHdr);
- lpwh^.dwBufferLength := BufferSize;
- lpwh^.dwBytesRecorded:= 0;
- lpwh^.dwFlags := 0;
- lpwh^.dwLoops := 0;
- lpwh^.dwUser := 0;
- lpwh^.lpNext := nil;
- FWaveInHdrs[i] := lpwh;
- end;
- end;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.FreeWaveHeaders;
- Var
- i: integer;
- begin
- for i := 0 to FNumBuffers-1 do
- begin
- { unlock and free memory for WaveInHdr }
- if FWaveInHdrs[i] <> NIL then
- begin
- FAllocator.FreeBuffer(Pointer(FWaveInHdrs[i]));
- FWaveInHdrs[i] := Nil;
- end;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- function TMMCustomWaveIn.WaveInErrorString(WError: integer): String;
- Var
- errorDesc: PChar;
- begin
- { convert the numeric return code from an MMSYSTEM function to a string }
- errorDesc := Nil;
- try
- errorDesc := StrAlloc(MAXERRORLENGTH);
- if waveInGetErrorText(WError, errorDesc, MAXERRORLENGTH) = 0 then
- Result := StrPas(errorDesc)
- else
- Result := LoadResStr(IDS_ERROROUTOFRANGE);
- finally
- StrDispose(errorDesc);
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.SetDeviceID(aValue: TMMDeviceID);
- begin
- if (wisOpen in FState) then
- Error(LoadResStr(IDS_PROPERTYOPEN));
- FProductName := LoadResStr(IDS_WINODEVICE);
- FDriverVersion := 0;
- if (FNumDevs > 0) and (aValue >= MapperId) and (aValue < FNumDevs) then
- begin
- { Set the name and other WAVEINCAPS properties to match the ID }
- FError := waveInGetDevCaps(aValue, @FWaveInCaps, sizeof(TWaveInCaps));
- if FError = 0 then
- with FWaveInCaps do
- begin
- FProductName := StrPas(szPname);
- FDriverVersion := vDriverVersion;
- end
- end;
- { set the new device }
- FDeviceID := aValue;
- if (aValue < MapperId) or (aValue >= FNumDevs) then
- FDeviceID := InvalidID;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- function TMMCustomWaveIn.GetDeviceID: TMMDeviceID;
- begin
- Result := FDeviceID;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.SetProductName(aValue: String);
- begin
- { dummy }
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- function TMMCustomWaveIn.GetProductName: String;
- begin
- Result := FProductName;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- function TMMCustomWaveIn.QueryDevice(aDeviceID: TMMDeviceID; pwfx: PWaveFormatEx): Boolean;
- Var
- aRate: Word;
- aMode: Word;
- aBits: Word;
- aWaveInCaps: TWaveInCaps;
- aHandle: HWaveIn;
- begin
- if (aDeviceID >= MapperId) and (aDeviceID < FNumDevs) and (pwfx <> nil) then
- begin
- { query the Wave input device. }
- Result := WaveInOpen(@aHandle,
- aDeviceId,
- Pointer(pwfx),
- 0, 0,
- WAVE_FORMAT_QUERY) = 0;
- if Result and (pwfx^.wFormatTag = WAVE_FORMAT_PCM) then
- begin
- Result := waveInGetDevCaps(aDeviceID,
- @aWaveInCaps,
- sizeof(TWaveInCaps)) = 0;
- if Result then
- with aWaveInCaps do
- begin
- aRate := pwfx^.nSamplesPerSec;
- aMode := pwfx^.nChannels;
- aBits := pwfx^.wBitsPerSample;
- case aRate of
- 8000..11025: case aMode of
- 1: case aBits of
- 8: Result := (dwFormats AND Wave_Format_1M08 <> 0);
- 16: Result := (dwFormats AND Wave_Format_1M16 <> 0);
- end;
- 2: case aBits of
- 8: Result := (dwFormats AND Wave_Format_1S08 <> 0);
- 16: Result := (dwFormats AND Wave_Format_1S16 <> 0);
- end;
- end;
- 11026..22050: case aMode of
- 1: case aBits of
- 8: Result := (dwFormats AND Wave_Format_2M08 <> 0);
- 16: Result := (dwFormats AND Wave_Format_2M16 <> 0);
- end;
- 2: case aBits of
- 8: Result := (dwFormats AND Wave_Format_2S08 <> 0);
- 16: Result := (dwFormats AND Wave_Format_2S16 <> 0);
- end;
- end;
- 22051..48000: case aMode of
- 1: case aBits of
- 8: Result := (dwFormats AND Wave_Format_4M08 <> 0);
- 16: Result := (dwFormats AND Wave_Format_4M16 <> 0);
- end;
- 2: case aBits of
- 8: Result := (dwFormats AND Wave_Format_4S08 <> 0);
- 16: Result := (dwFormats AND Wave_Format_4S16 <> 0);
- end;
- end;
- end;
- end;
- end;
- end
- else Result := False;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn -----------------------------------------------------------}
- procedure TMMCustomWaveIn.SetTimeFormat(aValue: TMMTimeFormats);
- begin
- if (aValue <> FTimeFormat) then
- begin
- FTimeFormat := aValue;
- if (FMaxRecTime >= 0) then
- begin
- case FTimeFormat of
- tfMillisecond: FMaxRecTime := wioBytesToTime(PWaveFormat,FMaxRecBytes);
- tfSample : FMaxRecTime := wioBytesToSamples(PWaveFormat,FMaxRecBytes);
- else FMaxRecTime:= FMaxRecBytes;
- end;
- end;
- end;
- end;
- {-- TMMCustomWaveIn -----------------------------------------------------------}
- procedure TMMCustomWaveIn.SetMaxRecTime(aValue: Longint);
- begin
- if (aValue <> FMaxRecTime) then
- begin
- FMaxRecTime := aValue;
- CalcMaxRecBytes;
- end;
- end;
- {-- TMMCustomWaveIn -----------------------------------------------------------}
- procedure TMMCustomWaveIn.CalcMaxRecBytes;
- begin
- if (FMaxRecTime >= 0) and (PWaveFormat <> nil) then
- begin
- try
- case FTimeFormat of
- tfMillisecond: FMaxRecBytes := wioTimeToBytes(PWaveFormat,FMaxRecTime);
- tfSample : FMaxRecBytes := wioSamplesToBytes(PWaveFormat,FMaxRecTime);
- else FMaxRecBytes := FMaxRecTime;
- end;
- except
- FMaxRecBytes := MaxLongint;
- end;
- end
- else FMaxRecBytes := MaxLongint;
- FMaxRecBytes := FMaxRecBytes-(FMaxRecBytes mod PWaveFormat^.nBlockAlign);
- end;
- {-- TMMCustomWaveIn -----------------------------------------------------------}
- procedure TMMCustomWaveIn.SetPriority(aValue: TThreadPriority);
- begin
- FPriority := aValue;
- if (FInThread <> nil) then
- FInThread.Priority := FPriority;
- end;
- {-- TMMCustomWaveIn -----------------------------------------------------------}
- function TMMCustomWaveIn.GetSamplePosition: Cardinal;
- Var
- MMTime: TMMTime;
- begin
- Result := 0;
- if (wisOpen in FState) and (PWaveFormat <> Nil) and not FClosing then
- begin
- MMTime.wType := Time_Samples;
- FError := WaveInGetPosition(FHWaveIn, @MMTime, SizeOf(TMMTime));
- if (FError <> 0) or (MMTime.wType <> Time_Samples) then
- begin
- MMTime.wType := Time_Bytes;
- FError := WaveInGetPosition(FHWaveIn, @MMTime, SizeOf(TMMTime));
- if (FError <> 0) then
- Error('WaveInGetPosition:'#10#13+WaveInErrorString(FError));
- MMTime.Sample := wioBytesToSamples(PWaveFormat,MMTime.cb);
- end;
- Result := MMTime.Sample;
- end;
- end;
- {-- TMMCustomWaveIn -----------------------------------------------------------}
- function TMMCustomWaveIn.GetInternalPosition: Int64;
- var
- Samples,Pos: int64;
- S: Cardinal;
- WrapSize: int64;
- begin
- Result := 0;
- if (wisOpen in FState) and (PWaveFormat <> Nil) and not FCloseIt then
- begin
- S := GetSamplePosition;
- {$IFDEF WIN32}
- asm
- mov eax, S
- mov dword ptr Pos[0], eax
- xor eax, eax
- mov dword ptr Pos[4], eax
- mov eax, Self
- mov eax, TMMWaveIn(eax).FWrapSize
- mov dword ptr WrapSize[0], eax
- xor eax, eax
- mov dword ptr WrapSize[4], eax
- end;
- Samples := (FWrapArrounds*WrapSize)+Pos;
- {$ELSE}
- Samples := S;
- {$ENDIF}
- case FTimeFormat of
- tfMilliSecond: Result := wioSamplesToTime64(PWaveFormat,Samples);
- tfByte : Result := wioSamplesToBytes64(PWaveFormat,Samples);
- tfSample : Result := Samples;
- end;
- if (FMaxRecTime > 0) and (Result >= FMaxRecTime) then
- Result := FMaxRecTime;
- end;
- end;
- {-- TMMCustomWaveIn -----------------------------------------------------------}
- function TMMCustomWaveIn.GetPosition: MM_int64;
- {$IFNDEF DELPHI4}
- var
- Temp: TLargeInteger;
- {$ENDIF}
- begin
- {$IFDEF DELPHI4}
- Result := GetInternalPosition;
- {$ELSE}
- Temp.QuadPart := GetInternalPosition;
- Result := Temp.LowPart;
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn -----------------------------------------------------------}
- function TMMCustomWaveIn.GetPositionHigh: Cardinal;
- {$IFNDEF DELPHI4}
- var
- Temp: TLargeInteger;
- {$ENDIF}
- begin
- {$IFDEF DELPHI4}
- Result := (GetInternalPosition shr 32);
- {$ELSE}
- Temp.QuadPart := GetInternalPosition;
- Result := Temp.HighPart;
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn -----------------------------------------------------------}
- function TMMCustomWaveIn.GetPosition64: int64;
- begin
- Result := GetInternalPosition;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.SetCallBackMode(aValue: TMMCBMode);
- begin
- if (wisOpen in FState) then
- Error(LoadResStr(IDS_PROPERTYOPEN));
- if (aValue <> FCallBackMode) then
- begin
- if (aValue = cmCallBack) then
- begin
- {$IFDEF WIN32}
- if not _Win95_ then
- {$ENDIF}
- begin
- Application.MessageBox('"CallBacks" are called at interrupt time !'#10#13+
- 'This is currently only supported under Windows 95',
- 'TMMWaveIn', MB_OK);
- exit;
- end;
- end;
- FCallBackMode := aValue;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK3}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- function TMMCustomWaveIn.GetCallBackMode: TMMCBMode;
- begin
- Result := FCallbackMode;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.SetPWaveFormat(aValue: PWaveFormatEx);
- begin
- { stop and close the device }
- Close;
- if (aValue <> nil) then
- begin
- if pcmIsValidFormat(aValue) then
- begin
- SampleRate := aValue^.nSamplesPerSec;
- BitLength := TMMBits(aValue^.wBitsPerSample div 8 - 1);
- Mode := TMMMode(aValue^.nChannels-1);
- end;
- end;
- inherited SetPWaveFormat(aValue);
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.SetWaveParams;
- begin
- pcmBuildWaveHeader(@FWaveFormat,(Ord(FBits)+1)*8,Ord(FMode)+1,FRate);
- PWaveFormat := @FWaveFormat;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.SetMode(aValue: TMMMode);
- begin
- if (FMode <> aValue) and (aValue in [mMono,mStereo]) then
- begin
- if (wisOpen in FState) then
- Error(LoadResStr(IDS_PROPERTYOPEN));
- FMode := aValue;
- SetWaveParams;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.SetSampleRate(aValue: Longint);
- begin
- if (FRate <> aValue) then
- begin
- if (wisOpen in FState) then
- Error(LoadResStr(IDS_PROPERTYOPEN));
- FRate := MinMax(aValue,8000,100000);
- SetWaveParams;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.SetBits(aValue: TMMBits);
- begin
- if (FBits <> aValue) then
- begin
- if (wisOpen in FState) then
- Error(LoadResStr(IDS_PROPERTYOPEN));
- FBits := aValue;
- SetWaveParams;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.SetNumBuffers(aValue: integer);
- begin
- if (aValue <> FNumBuffers) AND (aValue > 1) then
- begin
- if (wisOpen in FState) then
- Error(LoadResStr(IDS_PROPERTYOPEN));
- FNumBuffers := Min(aValue,MAXINBUFFERS);
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- function TMMCustomWaveIn.GetNumBuffers: integer;
- begin
- Result := FNumBuffers;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.SetBufferSize(aValue: Longint);
- begin
- if (aValue <> inherited GetBufferSize) then
- begin
- if (wisOpen in FState) then
- Error(LoadResStr(IDS_PROPERTYOPEN));
- if assigned(FAllocator) then
- FAllocator.Discard;
- inherited SetBufferSize(Max(aValue,MINBUFFERSIZE));
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- function TMMCustomWaveIn.GetBufferSize: Longint;
- begin
- Result := inherited GetBufferSize;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.PrepareWaveHeaders;
- Var
- i: integer;
- begin
- { Prepare waveform headers for recording }
- for i := 0 to FNumBuffers-1 do
- begin
- if FWaveInHdrs[i] <> Nil then
- begin
- FError := waveInPrepareHeader(FHWaveIn,
- FWaveInHdrs[i],
- sizeOf(TWaveHdr));
- if FError <> 0 then
- Error('WaveInPrepareHeader:'#10#13+WaveInErrorString(FError));
- end;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.UnPrepareWaveHeaders;
- Var
- i: integer;
- TimeOut: Longint;
- begin
- {$IFDEF _MMDEBUG}
- DebugStr(1,' ');
- {$ENDIF}
- for i := 0 to FNumBuffers-1 do
- begin
- if (FWaveInHdrs[i] <> Nil) then
- begin
- TimeOut := 65000;
- { wait until the buffer is marked as done }
- repeat
- dec(TimeOut);
- until (FWaveInHdrs[i]^.dwFlags and WHDR_DONE = WHDR_DONE) or (TimeOut = 0);
- { mark buffer as done }
- if (TimeOut = 0) then FWaveInHdrs[i]^.dwFlags := WHDR_DONE;
- { unprepare buffer }
- FError := WaveInUnprepareHeader(FHWaveIn,
- FWaveInHdrs[i],
- sizeOf(TWAVEHDR));
- if FError <> 0 then
- Error('WaveInUnprepareHeader:'#10#13+WaveInErrorString(FError));
- {$IFDEF _MMDEBUG}
- DebugStr(1,'UnprepareHeader '+IntToStr(i));
- {$ENDIF}
- end;
- end;
- {$IFDEF _MMDEBUG}
- DebugStr(1,' ');
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.AddWaveHeader(lpWaveHdr: PWaveHdr);
- begin
- { reset flags field (remove WHDR_DONE attribute) }
- lpWaveHdr^.dwFlags := lpWaveHdr^.dwFlags and not WHDR_DONE or WHDR_PREPARED;
- { queue the buffer for input... }
- FError := WaveInAddBuffer(FHWaveIn,
- lpWaveHdr,
- sizeof(TWAVEHDR));
- if FError <> 0 then
- Error('WaveInAddBuffer:'#10#13+WaveInErrorString(FError));
- inc(FBufferCounter);
- {$IFDEF _MMDEBUG}
- DebugStr(2,'Wave-Header '+IntToStr(lpWaveHdr^.dwUser)+' queued');
- {$ENDIF}
- end;
- {$IFDEF WIN32}
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.SynchronizeVCL(VCLProc: TThreadMethod);
- begin
- if (FCallBackMode = cmThread) and (FInEvent <> 0) then
- begin
- FInThread.Synchronize(VCLProc);
- end
- else VCLProc;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.InitThread;
- begin
- if (FCallBackMode = cmThread) then
- begin
- EnterCritical;
- try
- FThreadError := False;
- { create event objects }
- FInEvent := CreateEvent(nil, False, False, nil);
- FCloseEvent := CreateEvent(nil, False, False, nil);
- { create the output thread }
- FInThread := TMMWaveInThread.CreateSuspended(Self);
- if (FInThread = nil) then
- Error('WaveIn:'#10#13+LoadResStr(IDS_THREADERROR));
- FInThread.FreeOnTerminate := True;
- FInThread.Resume;
- { Wait for it to start... }
- if WaitForSingleObject(FInEvent, 5000) <> WAIT_OBJECT_0 then
- Error('WaveIn:'#10#13+LoadResStr(IDS_THREADERROR));
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Thread Started');
- {$ENDIF}
- finally
- LeaveCritical;
- end;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.DoneThread;
- begin
- if (FCallBackMode = cmThread) and not FThreadError then
- begin
- { Force the output thread to close... }
- SetEvent(FCloseEvent);
- { ...and wait for it to die }
- WaitForSingleObject(FInEvent, 5000);
- { close all events and remove critical section }
- CloseEvents;
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Thread Terminated');
- {$ENDIF}
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.CloseEvents;
- begin
- { release events }
- CloseHandle(FInEvent);
- CloseHandle(FCloseEvent);
- { Free the critical section }
- DoneCritical;
- end;
- {$ENDIF}
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.InitCritical;
- begin
- {$IFDEF WIN32}
- if (FCallBackMode <> cmWindow) then
- begin
- { create critical section object }
- FillChar(DataSection, SizeOf(DataSection), 0);
- InitializeCriticalSection(DataSection);
- DataSEctionOK := True;
- end;
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.EnterCritical;
- begin
- {$IFDEF WIN32}
- if (FCallBackMode <> cmWindow) and DataSectionOK then
- EnterCriticalSection(DataSection);
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.LeaveCritical;
- begin
- {$IFDEF WIN32}
- if (FCallBackMode <> cmWindow) and DataSectionOK then
- LeaveCriticalSection(DataSection);
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.DoneCritical;
- begin
- {$IFDEF WIN32}
- if (FCallBackMode <> cmWindow) and DataSectionOK then
- begin
- DataSectionOK := False;
- DeleteCriticalSection(DataSection);
- end;
- {$ENDIF}
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.Open;
- var
- TimeOut: integer;
- aState: TMMWaveInState;
- begin
- if (FNumDevs = 0) then
- Error(LoadResStr(IDS_WINODEVICE));
- if (FDeviceID = InvalidId) then
- Error(LoadResStr(IDS_INVALIDDEVICEID));
- if (PWaveFormat = nil) then
- Error(LoadResStr(IDS_NOFORMAT));
- if (wisOpen in FState) then Close;
- if (Not(wisOpen in FState)) and not FClosing then
- begin
- TimeOut := 100;
- FClosing := False;
- FReseting := False;
- FStopping := False;
- FPosted := False;
- try
- if not QueryDevice(FDeviceID, PWaveFormat) then
- Error('WaveInOpen:'#10#13+LoadResStr(IDS_CANTRECORD));
- { Create the window for callback notification }
- if (FHandle = 0) then FHandle := AllocateHwnd(WaveInHandler);
- FHWaveIn := 0;
- FCloseIt := False;
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Try to open device...');
- {$ENDIF}
- { some fullduplex drivers require that WaveIn is opened before WaveOut }
- { so we open the WaveIn device first and then open all other components }
- { create critical section object }
- InitCritical;
- {$IFDEF WIN32}
- if (FCallBackMode = cmThread) then InitThread;
- {$ENDIF}
- { now open Wave input device. }
- if _Win9x_ or _WinNT4_ then
- begin
- FError := WaveInOpen(@FHWaveIn,
- FDeviceId,
- Pointer(PWaveFormat),
- Longint(@WaveInFunc),
- Longint(Self),
- CALLBACK_FUNCTION);
- end
- else
- begin
- FError := WaveInOpen(@FHWaveIn,
- FDeviceId,
- Pointer(PWaveFormat),
- FHandle,
- 0,
- CALLBACK_WINDOW);
- end;
- if (FError <> 0) then
- begin
- Error('WaveInOpen:'#10#13+WaveInErrorString(FError));
- end;
- aState := FState;
- FState := [wisClose];
- inherited Opened;
- FState := aState;
- { wait until the device returns its status }
- repeat
- if _Win9x_ or _WinNT4_ then
- Delay(10,False)
- else
- Delay(10,True);
- dec(TimeOut);
- until (wisOpen in FState) or (TimeOut <= 0);
- if (TimeOut <= 0) then
- Error('WaveInOpen:'#10#13+LoadResStr(IDS_CANTOPENDEVICE));
- { create the waveIn headers and buffers }
- AllocWaveHeaders;
- { Prepare waveform headers for recording }
- PrepareWaveHeaders;
- Opened;
- except
- if assigned(FOnError) then FOnError(Self);
- FState := [wisOpen];
- Close;
- FState := [wisClose];
- raise;
- end;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.Close;
- var
- TimeOut: integer;
- begin
- if (wisOpen in FState) and (not FClosing or FCloseIt) then
- try
- FClosing := True;
- { stop recording }
- if (wisRecord in FState) OR (wisPause in FState) then Stop;
- TimeOut := 100;
- { Close the device (finally!) }
- if FStopIt then FCloseIt := True
- else
- begin
- FCloseIt := False;
- if (FHWaveIn <> 0) then
- begin
- WaveInStop(FHWaveIn);
- WaveInReset(FHWaveIn);
- { unprepare wave headers }
- UnPrepareWaveHeaders;
- {$IFDEF _MMDEBUG}
- if (FInHandler > 0) then
- DebugStr(0,'Try to close device (while in Handler)...')
- else
- DebugStr(0,'Try to close device...');
- {$ENDIF}
- FError := WaveInClose(FHWaveIn);
- if FError <> 0 then
- Error('WaveInClose:'#10#13+WaveInErrorString(FError));
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Waiting for state...');
- {$ENDIF}
- { wait until the device returns its status }
- repeat
- if _Win9x_ or _WinNT4_ then
- Delay(10,False)
- else
- Delay(10,True);
- dec(TimeOut);
- until (wisClose in FState) or (TimeOut <= 0);
- FWrapArrounds := 0;
- FWrapSize := 0;
- end
- else
- begin
- FState := [wisClose];
- end;
- { now notify all other components }
- inherited Closed;
- {$IFDEF WIN32}
- if (FCallBackMode = cmThread) then
- DoneThread
- else
- DoneCritical;
- {$ENDIF}
- Closed;
- if (TimeOut <= 0) then
- Error('WaveInOpen:'#10#13+LoadResStr(IDS_CANTCLOSEDEVICE));
- end;
- except
- FClosing := False;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.Start;
- Var
- i: integer;
- begin
- try
- if not (wisOpen in FState) then Open;
- if (wisOpen in FState) and (not (wisRecord in FState)) then
- begin
- { reset the total bytes recorded counter }
- FBytesRecorded := 0;
- FBufferIndex := 0;
- FInHandler := 0;
- FStopIt := False;
- FStopping := False;
- FReseting := False;
- FPosted := False;
- FBufferCounter := 0;
- FLastPosition := 0;
- FWrapArrounds := 0;
- FWrapSize := 0;
- CalcMaxRecBytes;
- { To start recording, send the buffers to driver }
- for i := 0 to FNumBuffers-1 do
- begin
- {$IFDEF NUMERATE}
- FWaveInHdrs[i]^.dwUser := i;
- {$ENDIF}
- AddWaveHeader(FWaveInHdrs[i]);
- end;
- Started;
- end;
- except
- if assigned(FOnError) then FOnError(Self);
- FState := FState + [wisRecord];
- Close;
- FState := [wisClose];
- raise;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.Pause;
- begin
- try
- if not (wisOpen in FState) then Open;
- if (wisOpen in FState) and (not (wisPause in FState)) then
- begin
- if (wisRecord in FState) then
- begin
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Try to pause device...');
- {$ENDIF}
- FError := WaveInStop(FHWaveIn);
- if FError <> 0 then
- Error('WaveInPause:'#10#13+WaveInErrorString(FError));
- end;
- Paused;
- end;
- except
- if assigned(FOnError) then FOnError(Self);
- Close;
- raise;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- Procedure TMMCustomWaveIn.Restart;
- begin
- try
- if (wisRecord in FState) and (wisPause in FState) then
- begin
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Try to restart device...');
- {$ENDIF}
- FError := WaveInStart(FHWaveIn);
- if FError <> 0 then
- Error('WaveInRestart:'#10#13+WaveInErrorString(FError));
- Restarted;
- end;
- except
- if assigned(FOnError) then FOnError(Self);
- Close;
- raise;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.Stop;
- var
- TimeOut: Longint;
- begin
- if (wisRecord in FState) or (wisPause in FState) then
- begin
- try
- EnterCritical;
- try
- FStopping := True;
- {$IFDEF _MMDEBUG}
- if (FInHandler > 0) then
- DebugStr(0,'Try to stop device (while in Handler)...')
- else
- DebugStr(0,'Try to stop device...');
- {$ENDIF}
- FError := WaveInStop(FHWaveIn);
- if FError <> 0 then
- Error('WaveInStop:'#10#13+WaveInErrorString(FError));
- {$IFDEF _MMDEBUG}
- DebugStr(0,'WaveInStop Done...');
- {$ENDIF}
- FWrapArrounds := 0;
- FWrapSize := 0;
- FReseting := True;
- FError := WaveInReset(FHWaveIn);
- if FError <> 0 then
- Error('WaveInReset:'#10#13+WaveInErrorString(FError));
- {$IFDEF _MMDEBUG}
- DebugStr(0,'WaveInReset Done...');
- {$ENDIF}
- finally
- LeaveCritical;
- end;
- if (FInHandler = 0) then
- begin
- TimeOut := 100;
- repeat
- if (FCallBackMode <> cmWindow) then
- Delay(10,False)
- else
- Delay(10,True);
- dec(TimeOut);
- until (FBufferCounter = 0) or (TimeOut <= 0);
- end;
- Stopped;
- except
- if assigned(FOnError) then FOnError(Self);
- Close;
- raise;
- end;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.Opened;
- begin
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Device is now open...');
- {$ENDIF}
- if Assigned(FOnOpen) then FOnOpen(Self);
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.Closed;
- begin
- FHWaveIn := 0;
- { free memory and remove }
- FreeWaveHeaders;
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Device is now closed...');
- {$ENDIF}
- FClosing := False;
- if not (csDestroying in ComponentState) then
- if Assigned(FOnClose) then FOnClose(Self);
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.Started;
- begin
- Include(FState, wisRecord);
- if not (wisPause in FState) then
- begin
- { start the buffers recording (unpause) }
- FError := WaveInStart(FHWaveIn);
- if FError <> 0 then
- Error('WaveInStart:'#10#13+WaveInErrorString(FError));
- end;
- { now notify all other components }
- inherited Started;
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Device is now started...');
- {$ENDIF}
- InitDSPMeter;
- if assigned(FOnStart) then FOnStart(Self);
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.Paused;
- begin
- Include(FState, wisPause);
- inherited Paused;
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Device is now paused...');
- {$ENDIF}
- if assigned(FOnPause) then FOnPause(Self);
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.Restarted;
- begin
- FState := FState - [wisPause];
- inherited Restarted;
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Device is now restarted...');
- {$ENDIF}
- if assigned(FOnRestart) then FOnRestart(Self);
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.Stopped;
- begin
- if (wisRecord in FState) or (wisPause in FState) then
- begin
- if (FInHandler > 0) then FStopIt := True
- else
- begin
- FState := FState - [wisRecord,wisPause];
- FBufferIndex := 0;
- FBufferCounter := 0;
- FStopIt := False;
- DoneDSPMeter;
- { notify all other components }
- inherited Stopped;
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Device is now stopped...');
- {$ENDIF}
- if not (csDestroying in ComponentState) then
- if assigned(FOnStop) then FOnStop(Self);
- if FCloseIt then Close;
- end;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.BufferReady(lpwh: PWaveHdr);
- var
- bStopIt: Boolean;
- begin
- StartDSPMeter;
- try
- { inc the bytes we have already recorded }
- inc(FBytesRecorded, lpwh^.dwBytesRecorded);
- if (FMaxRecTime > 0) and (FBytesRecorded >= FMaxRecBytes) then
- begin
- dec(lpwh^.dwBytesRecorded,FBytesRecorded-FMaxRecBytes);
- FBytesRecorded := FMaxRecBytes;
- bStopIt := True;
- end
- else bStopIt := False;
- inc(FBufferIndex);
- if FBufferIndex >= FNumBuffers then FBufferIndex := 0;
- inherited BufferReady(lpwh);
- if bStopIt then Stop;
- finally
- StopDSPMeter;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.ProcessWaveHeader(lpWaveHdr: PWaveHdr);
- var
- CurPos,LastPos: Cardinal;
- Wrapped: integer;
- begin
- if (wisRecord in FState) then
- begin
- if FReseting or FStopping then
- begin
- { Buffer has returned from driver but should not queued again }
- {$IFDEF _MMDEBUG}
- DebugStr(2,'Buffer '+IntToStr(lpWaveHdr^.dwUser)+' returned while reseting');
- {$ENDIF}
- if not FReseting and (lpWaveHdr^.dwBytesRecorded > 0) then
- BufferReady(lpWaveHdr);
- EnterCritical;
- dec(FBufferCounter);
- if (FBufferCounter = 0) then FReseting := False;
- LeaveCritical;
- if not FStopIt then exit;
- end;
- inc(FInHandler);
- try
- {$IFDEF _MMDEBUG}
- DebugStr(2,'Buffer '+IntToStr(lpWaveHdr^.dwUser)+' returned');
- {$ENDIF}
- EnterCritical;
- dec(FBufferCounter);
- LeaveCritical;
- try
- BufferReady(lpWaveHdr);
- if not FStopIt then
- begin
- {$IFDEF WIN32}
- { wrap arround handling }
- CurPos := GetSamplePosition;
- if (CurPos > 0) then
- begin
- LastPos:= FLastPosition;
- asm
- mov Wrapped, False
- mov eax, CurPos
- cmp eax, LastPos
- jnb @@exit
- mov eax, LastPos
- sub eax, CurPos
- cmp eax, $FFFF
- jb @@exit
- mov Wrapped, True
- @@exit:
- end;
- if (Wrapped = 1) then
- begin
- { every driver wraps at a different position }
- { here we try to detect where the position has wrapped }
- { hey, this looks realy cool }
- FWrapSize := (FLastPosition and $FFF00000) or $FFFFF;
- inc(FWrapArrounds);
- end;
- FLastPosition := CurPos;
- end;
- {$ENDIF}
- { Refresh the wave input device with new buffer. }
- AddWaveHeader(lpWaveHdr);
- end;
- except
- if assigned(FOnError) then FOnError(Self);
- raise;
- end;
- finally
- dec(FInHandler);
- if (FInHandler = 0) and FStopIt and not FPosted then
- begin
- FPosted := True;
- FStopping := True;
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Stop Message posted...');
- {$ENDIF}
- PostMessage(FHandle,MM_WIM_STOP,FHWaveIn,0);
- end;
- end;
- end;
- end;
- {-- TMMCustomWaveIn ------------------------------------------------------------}
- procedure TMMCustomWaveIn.WaveInHandler(Var Msg: TMessage );
- begin
- with Msg do
- try
- if wParam = FHWaveIn then
- case Msg of
- MM_WIM_OPEN :
- begin
- { device is now open }
- FState:= [wisOpen];
- end;
- MM_WIM_CLOSE:
- begin
- { device is now closed }
- FState:= [wisClose];
- end;
- MM_WIM_DATA:
- begin
- { buffer has been returned to app, so queue it.}
- ProcessWaveHeader(PWaveHdr(lparam));
- exit;
- end;
- MM_WIM_STOP:
- begin
- { should stop the device }
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Stop message received...');
- {$ENDIF}
- Stop;
- exit;
- end;
- end;
- Result := DefWindowProc(FHandle, Msg, wParam, lParam);
- except
- Close;
- Application.HandleException(Self);
- end;
- end;
- {== TMMWaveIn =================================================================}
- procedure TMMWaveIn.SetupWaveEngine;
- begin
- @waveInGetNumDevs := @MMSystem.waveInGetNumDevs;
- @waveInGetDevCaps := @MMSystem.waveInGetDevCaps;
- @waveInGetErrorText := @MMSystem.waveInGetErrorText;
- @waveInOpen := @MMSystem.waveInOpen;
- @waveInClose := @MMSystem.waveInClose;
- @waveInPrepareHeader := @MMSystem.waveInPrepareHeader;
- @waveInUnprepareHeader := @MMSystem.waveInUnprepareHeader;
- @waveInAddBuffer := @MMSystem.waveInAddBuffer;
- @waveInStart := @MMSystem.waveInStart;
- @waveInStop := @MMSystem.waveInStop;
- @waveInReset := @MMSystem.waveInReset;
- @waveInGetPosition := @MMSystem.waveInGetPosition;
- @waveInGetID := @MMSystem.waveInGetID;
- end;
- {-- WaveInFunc -----------------------------------------------------------}
- procedure WaveInFunc(hWaveIn:HWaveIn;wMsg:UINT;dwInstance,dwParam1,dwParam2:Longint);
- begin
- if (dwInstance <> 0) then
- with TMMCustomWaveIn(dwInstance) do
- {$IFDEF WIN32}
- try
- {$ELSE}
- begin
- {$ENDIF}
- case wMsg of
- WIM_OPEN :
- begin
- { device is now open }
- FState:= [wisOpen];
- end;
- WIM_CLOSE:
- begin
- { device is now closed }
- FState:= [wisClose];
- end;
- WIM_DATA :
- begin
- case FCallBackMode of
- cmWindow: PostMessage(FHandle,MM_WIM_DATA,hWaveIn,dwParam1);
- {$IFDEF WIN32}
- cmCallBack: ProcessWaveHeader(PWaveHdr(dwparam1));
- cmThread: PostThreadMessage(FInThread.ThreadID,MM_WIM_DATA,hWaveIn,dwParam1);
- {$ENDIF}
- end;
- end;
- end;
- {$IFDEF WIN32}
- except
- Close;
- Application.HandleException(TMMCustomWaveIn(dwInstance));
- {$ENDIF}
- end;
- end;
- {$IFDEF WIN32}
- {-------------------------------------------------------------------------}
- procedure TMMWaveInThread.Execute;
- {- Wait for and process input messages }
- var
- Res : DWORD;
- Msg : TMsg;
- {$IFDEF _MMDEBUG}
- _Error : Longint;
- {$ENDIF}
- begin
- with TMMCustomWaveIn(Owner) do
- try
- SetPriority(FPriority);
-
- { make sure we have a message queue... }
- PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
- { Ready to go, set the input event }
- SetEvent(FInEvent);
- { Repeat until device is closed }
- while not Terminated do
- try
- if not PeekMessage(msg, 0, 0, 0, PM_REMOVE) then
- begin
- Res := MsgWaitForMultipleObjects(1, FCloseEvent, False,
- INFINITE, QS_ALLEVENTS);
- case Res of
- WAIT_FAILED: { Wait failed. Shouldn't happen. }
- begin
- {$IFDEF _MMDEBUG}
- _Error := GetLastError;
- DebugStr(0,'Wait Failed... Error: '+SysErrorMessage(_Error));
- {$ENDIF}
- Continue;
- 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: { New message was received. }
- begin
- { Get the message that woke us up by looping again.}
- {$IFDEF _MMDEBUG}
- DebugStr(2,'WaveIn message reveived...');
- {$ENDIF}
- Continue;
- end;
- end;
- end;
- { Process the message. }
- with msg do
- begin
- if (wParam = FHWaveIn) and (message = MM_WIM_DATA) then
- begin { done playing queued wave buffer... }
- ProcessWaveHeader(PWaveHdr(lparam));
- end
- else
- begin
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Unknown message received...');
- {$ENDIF}
- TranslateMessage(Msg);
- DispatchMessage(msg);
- end;
- end;
- except
- FThreadError := True;
- if (FHWaveIn <> 0) then
- begin
- FClosing := True;
- Stop;
- UnPrepareWaveHeaders;
- WaveInClose(FHWaveIn);
- Closed;
- CloseEvents;
- end;
- Application.HandleException(nil);
- exit;
- end;
- finally
- SetEvent(FInEvent);
- {$IFDEF _MMDEBUG}
- DebugStr(0,'Exit Thread-Proc');
- {$ENDIF}
- end;
- end;
- {$ENDIF}
- procedure InitWaveInDevices;
- var
- i: integer;
- Name: string;
- function CheckDevice(DeviceID: integer; var Name: string): Boolean;
- var
- Res: integer;
- Caps: TWAVEINCAPS;
- begin
- Result := False;
- Name := '';
- Res := WaveInGetDevCaps(i,@Caps,sizeof(Caps));
- if (Res = 0) then
- begin
- Name := StrPas(Caps.szPname);
- Result := True;
- end;
- end;
- begin
- Devices := TStringList.Create;
- for i := 0 to WaveInGetNumDevs-1 do
- begin
- if CheckDevice(i,Name) then
- Devices.AddObject(Name,Pointer(i));
- end;
- end;
- initialization
- InitWaveInDevices;
- {$IFDEF _MMDEBUG}
- DB_Level(DEBUGLEVEL);
- {$ENDIF}
- finalization
- if (Devices <> nil) then
- Devices.Free;
- end.