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

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: 11.08.98 - 16:02:05 $                                        =}
  24. {========================================================================}
  25. unit MMDsCapt;
  26. {$C FIXED PRELOAD PERMANENT}
  27. {$I COMPILER.INC}
  28. {.$DEFINE _MMDEBUG}
  29. interface
  30. uses
  31.   Windows,
  32.   Classes,
  33.   SysUtils,
  34.   MMObj,
  35.   MMSystem,
  36.   MMOLE2,
  37.   MMUtils,
  38.   MMRegs,
  39.   MMWaveIO,
  40.   MMPCMSup,
  41. {$IFDEF _MMDEBUG}
  42.   MMDebug,
  43. {$ENDIF}
  44.   MMDSound;
  45. type
  46.   EDSWaveIn = class(Exception)
  47.   protected
  48.     FCode: MMRESULT;
  49.   public
  50.     constructor Create(Code: MMRESULT);
  51.   end;
  52. function DSWaveInGetNumDevs: UINT; stdcall;
  53. function DSWaveInGetDevCaps(HIn: HWaveIn; lpCaps: PWaveInCaps; uSize: UINT): MMRESULT; stdcall;
  54. function DSWaveInGetErrorText(mmrError: MMRESULT; lpText: PChar; uSize: UINT): MMRESULT; stdcall;
  55. function DSWaveInOpen(lpHWaveIn: PHWaveIn; uDeviceID: UINT; lpFormatEx: PWaveFormatEx; dwCallback, dwInstance, dwFlags: DWORD): MMRESULT; stdcall;
  56. function DSWaveInClose(HIn: HWaveIn): MMRESULT; stdcall;
  57. function DSWaveInPrepareHeader(HIn: HWaveIn; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
  58. function DSWaveInUnprepareHeader(HIn: HWaveIn; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
  59. function DSWaveInAddBuffer(HIn: HWaveIn; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
  60. function DSWaveInStart(HIn: HWaveIn): MMRESULT; stdcall;
  61. function DSWaveInStop(HIn: HWaveIn): MMRESULT; stdcall;
  62. function DSWaveInReset(HIn: HWaveIn): MMRESULT; stdcall;
  63. function DSWaveInGetPosition(HIn: HWaveIn; lpInfo: PMMTime; uSize: UINT): MMRESULT; stdcall;
  64. function DSWaveInGetID(HIn: HWaveIn; lpuDeviceID: PUINT): MMRESULT; stdcall;
  65. function DSWaveInMessage(HIn: HWaveIn; uMessage: UINT; dw1, dw2: DWORD): MMRESULT; stdcall;
  66. function DSWaveInGetIDirectSoundCapture(HIn: HWaveIn): IDirectSoundCapture;
  67. implementation
  68. const
  69.   DEFAULT_BUFFERSIZE    = 2048 + 1024;
  70.   DEFAULT_BUFFERCOUNT   = 4;
  71.   NOTIFICATIONTHREAD_TIMEOUT = INFINITE;
  72. type
  73.   TDsNotificationThread = class(TMMThreadEx)
  74.   protected
  75.     FSystemEvent: THandle;
  76.     procedure Execute; override;
  77.   public
  78.     constructor Create;
  79.     destructor Destroy; override;
  80.   end;
  81.   TDsWaveInDevice = class;
  82.   TDsWaveBuffer = class(TMMObject)
  83.   private
  84.     FData: PWaveHdr;
  85.   protected
  86.     function CanAccept: Integer;
  87.     function Accept(WaveData: Pointer; var Length: Integer): Boolean;
  88.   public
  89.     constructor Create(lpWaveHdr: PWaveHdr);
  90.     property Data: PWaveHdr read FData;
  91.   end;
  92.   TWaveDeviceState = (wdsInactive, wdsIdle, wdsStarted, wdsPaused);
  93.   PNotifyPointArray = ^TNotifyPointArray;
  94.   TNotifyPointArray = array[0..15] of TDSBPOSITIONNOTIFY;
  95.   TDsWaveInDevice = class(TMMObject)
  96.   private
  97.     FCapture: IDirectSoundCapture;
  98.     FGuid: PGUID;
  99.     FWaveMapped: Boolean;
  100.     FBuffer: IDirectSoundCaptureBuffer;
  101.     FNotifications: IDirectSoundNotify;
  102.     FNotifyPts: PNotifyPointArray;
  103.     FState: TWaveDeviceState;
  104.     FWaveBuffers,
  105.     FQueue: TList;
  106.     FBufferCount,                 // Count of buffer divisions
  107.     FBufferPartSize,              // Each division size
  108.     FBufferSize,                  // Multiplication of the previous two
  109.     FBufferOrigin,                // Global origin of DX buffer
  110.     FWritePosition: Integer;     // Global processed data position
  111.     FCallBackMode,
  112.     FCallBack,
  113.     FCBInstance: Integer;
  114.     function GetFormat: PWaveFormatEx;
  115.     procedure SetFormat(Value: PWaveFormatEx);
  116.     procedure ReturnBuffer;
  117.     function CaptureActive: Boolean;
  118.   protected
  119.     procedure NotifyMessage(Msg: UINT; wParam: WPARAM; lParam: LPARAM); stdcall;
  120.     procedure ProcessData(PointNumber: Integer);
  121.     procedure Reconfigure(lpFormat: PWaveFormatEx; ABufCount, ABufSize: Integer);
  122.   public
  123.     constructor Create(DeviceGuid: PGUID; lpFormat: PWaveFormatEx);
  124.     destructor Destroy; override;
  125.     class procedure EnterCritical;
  126.     class procedure LeaveCritical;
  127.     procedure AddBuffer(Header: PWaveHdr);
  128.     procedure PrepareBuffer(Header: PWaveHdr);
  129.     procedure UnprepareBuffer(Header: PWaveHdr);
  130.     function  FindBuffer(Header: PWaveHdr): TDsWaveBuffer;
  131.     procedure Start;
  132.     procedure Stop;
  133.     procedure Reset;
  134.     procedure GetPosition(lpInfo: PMMTime);
  135.     procedure GetCaps(var Caps: TWaveInCaps);
  136.     property Format: PWaveFormatEx read GetFormat write SetFormat;
  137.   end;
  138. var
  139.   CaptureDeviceList: TList;
  140.   OpenDevices: TList;
  141.   DsNotificationThread: TDsNotificationThread;
  142.   DsNotificationThread_RefCount: Integer = 0;
  143.  // EDSWaveIn
  144. constructor EDSWaveIn.Create(Code: MMRESULT);
  145. var
  146.   S: String;
  147. begin
  148.   SetLength(S, 250);
  149.   DSWaveInGetErrorText(Code, PChar(S), Length(S));
  150.   SetLength(S, StrLen(PChar(S)));
  151.   inherited Create(S);
  152.   FCode := Code;
  153. end;
  154. procedure MMCheck(Code: MMRESULT);
  155. begin
  156.   if Code <> MMSYSERR_NOERROR then
  157.     raise EDSWaveIn.Create(Code);
  158. end;
  159. procedure MMAssert(Condition: Boolean; Code: MMRESULT);
  160. begin
  161.   if not Condition then
  162.     raise EDSWaveIn.Create(Code);
  163. end;
  164. function HandleException: MMRESULT;
  165. begin
  166.   if ExceptObject is EDSWaveIn then
  167.     Result := EDSWaveIn(ExceptObject).FCode
  168.   else
  169.     Result := MMSYSERR_ERROR;
  170. end;
  171. procedure CheckHandle(HIn: HWaveIn);
  172. begin
  173.   MMAssert((OpenDevices <> nil) and (OpenDevices.IndexOf(Pointer(HIn)) <> -1),
  174.     MMSYSERR_INVALHANDLE);
  175. end;
  176. procedure DsNotificationThread_Addref;
  177. begin
  178.   if DsNotificationThread_RefCount = 0 then
  179.     DsNotificationThread := TDsNotificationThread.Create;
  180.   Inc(DsNotificationThread_RefCount);
  181. end;
  182. procedure DsNotificationThread_Release;
  183. begin
  184.   if DSNotificationThread_RefCount > 0 then
  185.   begin
  186.     Dec(DsNotificationThread_RefCount);
  187.     if DsNotificationThread_RefCount = 0 then
  188.     begin
  189.       DsNotificationThread.Terminate;
  190.       SetEvent(DsNotificationThread.FSystemEvent);
  191.       DsNotificationThread.Free;
  192.       DsNotificationThread := nil;
  193.     end;
  194.   end;
  195. end;
  196. function DeviceIdToGuid(DeviceID: Integer): PGUID;
  197. begin
  198.   if (DeviceID >= 0) and (DeviceID < DSWaveInGetNumDevs)
  199.     then Result := PDSDRIVERDESC(CaptureDeviceList[DeviceID]).lpGuid
  200.     else Result := nil;
  201. end;
  202. function IsEqualGuidEx(const p1, p2: TGUID): Boolean;
  203. begin
  204.   if Assigned(@p1) and Assigned(@p2) then
  205.     Result := IsEqualGUID(p1, p2)
  206.   else
  207.     Result := (not Assigned(@p1) or IsEqualGUID(p1, GUID_NULL)) and
  208.               (not Assigned(@p2) or IsEqualGUID(p2, GUID_NULL));
  209. end;
  210. procedure CaptureCapsToWaveInCaps(Capture: IDirectSoundCapture;
  211.   Guid: PGUID; var Caps: TWaveInCaps);
  212. var
  213.   CCaps: TDSCCAPS;
  214.   Index: Integer;
  215. begin
  216.   ZeroMemory(@CCaps, SizeOf(CCaps));
  217.   CCaps.dwSize := SizeOf(CCaps);
  218.   MMAssert(Capture.GetCaps(CCaps) = DS_OK, MMSYSERR_ERROR);
  219.   Caps.dwFormats := CCaps.dwFormats;
  220.   Caps.wChannels := CCaps.dwChannels;
  221.   for Index := CaptureDeviceList.Count-1 downto 0 do
  222.     with PDSDRIVERDESC(CaptureDeviceList[Index])^ do
  223.       if IsEqualGuidEx(lpGUID^, Guid^) then
  224.       begin
  225.         StrLCopy(Caps.szPname, PChar(Description), SizeOf(Caps.szPname));
  226.         break;
  227.       end;
  228. end;
  229.  // WaveIn -> DirectCapture API
  230. function DSWaveInGetNumDevs: UINT;
  231. begin
  232.   if not Assigned(CaptureDeviceList) then
  233.   begin
  234.     CaptureDeviceList := TList.Create;
  235.     if LoadDSoundDLL and Assigned(DirectSoundCaptureEnumerate) then
  236.       DirectSoundCaptureEnumerate(DriverEnumerate, CaptureDeviceList);
  237.   end;
  238.   Result := CaptureDeviceList.Count;
  239. end;
  240. function DSWaveInGetDevCaps(HIn: HWaveIn; lpCaps: PWaveInCaps; uSize: UINT): MMRESULT;
  241. var
  242.   Index: Integer;
  243.   AlreadyOpened: Boolean;
  244.   lpGuid: PGUID;
  245.   Capture: IDirectSoundCapture;
  246. begin
  247.   try
  248.      // HIn can be eather an opened device handle ...
  249.     if Assigned(OpenDevices) and (OpenDevices.IndexOf(Pointer(HIn)) <> -1) then
  250.     begin
  251.       TDsWaveInDevice(HIn).GetCaps(lpCaps^)
  252.     end else
  253.      // ... or DeviceID ...
  254.     if (HIn = integer(WAVE_MAPPER)) or ((HIn >= 0) and (HIn < CaptureDeviceList.Count)) then
  255.     begin
  256.       AlreadyOpened := False;
  257.       lpGuid := DeviceIdToGuid(HIn);
  258.        // Maybe it is already opened ?
  259.       if Assigned(OpenDevices) then
  260.         for Index := OpenDevices.Count-1 downto 0 do
  261.           if IsEqualGuidEx(TDsWaveInDevice(OpenDevices[Index]).FGuid^,
  262.                lpGuid^) then
  263.           begin
  264.             TDsWaveInDevice(OpenDevices[Index]).GetCaps(lpCaps^);
  265.             AlreadyOpened := True;
  266.             break;
  267.           end;
  268.       if not AlreadyOpened then
  269.       begin
  270.         MMAssert(Assigned(DirectSoundCaptureCreate), MMSYSERR_NODRIVER);
  271.         MMAssert(DirectSoundCaptureCreate(lpGuid, Capture, nil) = DS_OK,
  272.           MMSYSERR_NODRIVER);
  273.         try
  274.           CaptureCapsToWaveInCaps(Capture, lpGuid, lpCaps^);
  275.         finally
  276.           Capture.Release
  277.         end;
  278.       end;
  279.     end else
  280.      // ... otherwise this is an error
  281.       CheckHandle(HIn);
  282.     Result := MMSYSERR_NOERROR;
  283.   except
  284.     Result := HandleException;
  285.   end;
  286. end;
  287. function DSWaveInGetErrorText(mmrError: MMRESULT; lpText: PChar; uSize: UINT): MMRESULT;
  288. begin
  289.   Result := waveInGetErrorText(mmrError, lpText, uSize)
  290. end;
  291. function DSWaveInOpen(lpHWaveIn: PHWaveIn; uDeviceID: UINT; lpFormatEx: PWaveFormatEx; dwCallback, dwInstance, dwFlags: DWORD): MMRESULT;
  292. var
  293.   Capture: TDsWaveInDevice;
  294.   CallbackType: Integer;
  295. begin
  296.   try
  297.      // TODO: uDeviceID cab be a handle of an open device ???
  298.     MMAssert(LoadDSoundDLL and Assigned(DirectSoundCaptureCreate) and
  299.       (uDeviceID < DSWaveInGetNumDevs), MMSYSERR_NODRIVER);
  300.     MMAssert(lpFormatEx <> nil, MMSYSERR_INVALPARAM);
  301.     MMAssert(dwFlags and WAVE_ALLOWSYNC = 0, MMSYSERR_NOTSUPPORTED);
  302.     Capture := TDsWaveInDevice.Create(DeviceIdToGuid(uDeviceID), lpFormatEx);
  303.     if dwFlags and WAVE_FORMAT_QUERY = 0 then
  304.     begin
  305.       CallbackType := CALLBACK_NULL;
  306.       if dwFlags and CALLBACK_FUNCTION <> 0 then CallbackType := CALLBACK_FUNCTION else
  307.       if dwFlags and CALLBACK_WINDOW   <> 0 then CallbackType := CALLBACK_WINDOW   else
  308.       if dwFlags and CALLBACK_THREAD   <> 0 then CallbackType := CALLBACK_THREAD   else
  309.         MMCheck(MMSYSERR_INVALPARAM);
  310.       MMAssert(dwCallBack <> 0, MMSYSERR_INVALPARAM);
  311.       Capture.FCallBackMode := CallbackType;
  312.       Capture.FCallBack := dwCallback;
  313.       Capture.FCBInstance := dwInstance;
  314.       MMAssert(Assigned(lpHWaveIn), MMSYSERR_INVALPARAM);
  315.       lpHWaveIn^ := HWaveIn(Capture);
  316.       Capture.NotifyMessage(MM_WIM_OPEN, lphWaveIn^, 0);
  317.     end else
  318.       Capture.Free;
  319.     Result := MMSYSERR_NOERROR;
  320.   except
  321.     Result := HandleException;
  322.   end;
  323. end;
  324. function DSWaveInClose(HIn: HWaveIn): MMRESULT;
  325. begin
  326.   try
  327.     CheckHandle(HIn);
  328.     with TDsWaveInDevice(HIn) do
  329.     begin
  330.       NotifyMessage(MM_WIM_CLOSE, HIn, 0);
  331.       Free;
  332.     end;
  333.     Result := MMSYSERR_NOERROR;
  334.   except
  335.     Result := HandleException;
  336.   end;
  337. end;
  338. function DSWaveInPrepareHeader(HIn: HWaveIn; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT;
  339. begin
  340.   try
  341.     CheckHandle(HIn);
  342.     TDsWaveInDevice(HIn).PrepareBuffer(lpWaveInHdr);
  343.     Result := MMSYSERR_NOERROR;
  344.   except
  345.     Result := HandleException;
  346.   end;
  347. end;
  348. function DSWaveInUnprepareHeader(HIn: HWaveIn; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT;
  349. begin
  350.   try
  351.     CheckHandle(HIn);
  352.     TDsWaveInDevice(HIn).UnprepareBuffer(lpWaveInHdr);
  353.     Result := MMSYSERR_NOERROR;
  354.   except
  355.     Result := HandleException;
  356.   end;
  357. end;
  358. function DSWaveInAddBuffer(HIn: HWaveIn; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT;
  359. begin
  360.   try
  361.     CheckHandle(HIn);
  362.     TDsWaveInDevice(HIn).AddBuffer(lpWaveInHdr);
  363.     Result := MMSYSERR_NOERROR;
  364.   except
  365.     Result := HandleException;
  366.   end;
  367. end;
  368. function DSWaveInStart(HIn: HWaveIn): MMRESULT;
  369. begin
  370.   try
  371.     CheckHandle(HIn);
  372.     TDsWaveInDevice(HIn).Start;
  373.     Result := MMSYSERR_NOERROR;
  374.   except
  375.     Result := HandleException;
  376.   end;
  377. end;
  378. function DSWaveInStop(HIn: HWaveIn): MMRESULT;
  379. begin
  380.   try
  381.     CheckHandle(HIn);
  382.     TDsWaveInDevice(HIn).Stop;
  383.     Result := MMSYSERR_NOERROR;
  384.   except
  385.     Result := HandleException;
  386.   end;
  387. end;
  388. function DSWaveInReset(HIn: HWaveIn): MMRESULT;
  389. begin
  390.   try
  391.     CheckHandle(HIn);
  392.     TDsWaveInDevice(HIn).Reset;
  393.     Result := MMSYSERR_NOERROR;
  394.   except
  395.     Result := HandleException;
  396.   end;
  397. end;
  398. function DSWaveInGetPosition(HIn: HWaveIn; lpInfo: PMMTime; uSize: UINT): MMRESULT;
  399. begin
  400.   try
  401.     CheckHandle(HIn);
  402.     TDsWaveInDevice(HIn).GetPosition(lpInfo);
  403.     Result := MMSYSERR_NOERROR;
  404.   except
  405.     Result := HandleException;
  406.   end;
  407. end;
  408. function DSWaveInGetID(HIn: HWaveIn; lpuDeviceID: PUINT): MMRESULT;
  409. begin
  410.   try
  411.     CheckHandle(HIn);
  412.     lpuDeviceID^ := HIn;
  413.     Result := MMSYSERR_NOERROR;
  414.   except
  415.     Result := HandleException;
  416.   end;
  417. end;
  418. function DSWaveInMessage(HIn: HWaveIn; uMessage: UINT; dw1, dw2: DWORD): MMRESULT;
  419. begin
  420.   try
  421.     CheckHandle(HIn);
  422.      // ??? What are these messages
  423.      // TDsWaveInDevice(HIn).NotifyMessage(uMessage, dw1, dw2);
  424.     Result := MMSYSERR_NOERROR;
  425.   except
  426.     Result := HandleException;
  427.   end;
  428. end;
  429. function DSWaveInGetIDirectSoundCapture(HIn: HWaveIn): IDirectSoundCapture;
  430. begin
  431.   Result := nil;
  432.   try
  433.     CheckHandle(HIn);
  434.     Result := TDsWaveInDevice(HIn).FCapture;
  435.   except
  436.     ;
  437.   end;
  438. end;
  439.  // TDsNotificationThread
  440. constructor TDsNotificationThread.Create;
  441. begin
  442.    inherited Create(False);
  443.    FSystemEvent := CreateEvent(nil, False, False, nil);
  444. end;
  445. destructor TDsNotificationThread.Destroy;
  446. begin
  447.    CloseHandle(FSystemEvent);
  448.    inherited;
  449. end;
  450. procedure TDsNotificationThread.Execute;
  451. type
  452.   TDeviceArray = array[0..0] of TDsWaveInDevice;
  453.   PDeviceArray = ^TDeviceArray;
  454. var
  455.   HandleCount: Integer;
  456.   Handles: PWOHandleArray;
  457.   Devices: PDeviceArray;
  458.   procedure CollectHandles;
  459.   var
  460.     Index, HandleIndex, i,
  461.     DeviceCount: Integer;
  462.     Device: TDsWaveInDevice;
  463.   begin
  464.     TDsWaveInDevice.EnterCritical;
  465.     try
  466.       DeviceCount := OpenDevices.Count;
  467.       HandleCount := 1;
  468.       for Index := 0 to DeviceCount-1 do
  469.       begin
  470.         Device := OpenDevices[Index];
  471.         Inc(HandleCount, Device.FBufferCount + 1);
  472.       end;
  473.       GetMem(Handles, HandleCount * SizeOf(THandle));
  474.       GetMem(Devices, HandleCount * SizeOf(Devices^[0]));
  475.       HandleIndex := 0;
  476.       for Index := 0 to DeviceCount-1 do
  477.       begin
  478.         Device := OpenDevices[Index];
  479.         for i := 0 to Device.FBufferCount do
  480.         begin
  481.           Handles^[HandleIndex] := Device.FNotifyPts[i].hEventNotify;
  482.           Devices^[HandleIndex] := Device;
  483.           Inc(HandleIndex);
  484.         end;
  485.       end;
  486.       Handles^[HandleIndex] := FSystemEvent;
  487.       Devices^[HandleIndex] := nil;
  488.     finally
  489.       TDsWaveInDevice.LeaveCritical;
  490.     end;
  491.   end;
  492.   procedure FreeHandles;
  493.   begin
  494.     FreeMem(Handles, HandleCount * SizeOf(THandle));
  495.     FreeMem(Devices, HandleCount * SizeOf(Devices^[0]));
  496.     Handles := nil;
  497.     Devices := nil;
  498.   end;
  499. var
  500.   WaitResult, PointNumber: Integer;
  501. begin
  502.   while not Terminated do
  503.   begin
  504.     Priority := tpHigher;
  505.     CollectHandles;
  506.     WaitResult := WaitForMultipleObjects(HandleCount, Handles,
  507.       False, NOTIFICATIONTHREAD_TIMEOUT) - WAIT_OBJECT_0;
  508. {$IFDEF _MMDEBUG}
  509. //    DB_FormatLn(0, 'Thread received result: %d', [WaitResult]);
  510. {$ENDIF}
  511.     if WaitResult = HandleCount - 1 then
  512.        { System Event - do nothing just starting another loop }
  513.     else if (WaitResult >= 0) and (WaitResult < HandleCount - 1) then
  514.     begin
  515.        { Process next block ... }
  516.       PointNumber := 0;
  517.       while WaitResult > PointNumber do
  518.         if Devices^[WaitResult - PointNumber - 1] = Devices^[WaitResult] then
  519.           Inc(PointNumber);
  520.        // It's possible that buffer has already been destroyed
  521.        // while the thread was waiting to be activated
  522.       with Devices^[WaitResult] do
  523.         if Assigned(FBuffer) then ProcessData(PointNumber);
  524.     end;
  525.     FreeHandles;
  526.   end;
  527. end;
  528.  // TDsWaveInDevice
  529. var
  530.   DataSection: TRtlCriticalSection;
  531.   DataSectionOK: Boolean = False;
  532. constructor TDsWaveInDevice.Create(DeviceGuid: PGUID; lpFormat: PWaveFormatEx);
  533. begin
  534.   inherited Create;
  535.   FWaveBuffers := TList.Create;
  536.   FQueue := TList.Create;
  537.   MMAssert(DirectSoundCaptureCreate(DeviceGuid, FCapture, nil) = S_OK,
  538.     MMSYSERR_NODRIVER);
  539.   FGuid := DeviceGuid;
  540.   Reconfigure(lpFormat, DEFAULT_BUFFERCOUNT, DEFAULT_BUFFERSIZE);
  541.   DsNotificationThread_Addref;
  542.    // Global Initializations
  543.   if not DataSectionOK then
  544.   begin
  545.     ZeroMemory(@DataSection, SizeOf(DataSection));
  546.     InitializeCriticalSection(DataSection);
  547.     DataSectionOK := True;
  548.   end;
  549.   EnterCritical;
  550.   if OpenDevices = nil then
  551.     OpenDevices := TList.Create;
  552.   OpenDevices.Add(Self);
  553.   FState := wdsIdle;
  554.   LeaveCritical;
  555.   SetEvent(DsNotificationThread.FSystemEvent);
  556. end;
  557. destructor TDsWaveInDevice.Destroy;
  558. var
  559.   i: integer;
  560. begin
  561.   Reset;
  562.   for i := FWaveBuffers.Count-1 downto 0 do
  563.     TDsWaveBuffer(FWaveBuffers[i]).Free;
  564.   FWaveBuffers.Clear;
  565.   EnterCritical;
  566.   if OpenDevices <> nil then
  567.     OpenDevices.Remove(Self);
  568.   LeaveCritical;
  569.   Reconfigure(nil, 0, 0);
  570.   if Assigned(FCapture) then
  571.   begin
  572.     FCapture.Release;
  573.     FCapture := nil;
  574.   end;
  575.   FQueue.Free;
  576.   FWaveBuffers.Free;
  577.   inherited;
  578. end;
  579. class procedure TDsWaveInDevice.EnterCritical;
  580. begin
  581.   if DataSectionOK then
  582.     EnterCriticalSection(DataSection);
  583. end;
  584. class procedure TDsWaveInDevice.LeaveCritical;
  585. begin
  586.   if DataSectionOK then
  587.     LeaveCriticalSection(DataSection);
  588. end;
  589. procedure TDsWaveInDevice.Reconfigure(lpFormat: PWaveFormatEx; ABufCount, ABufSize: Integer);
  590. var
  591.   BufferDesc: TDSCBUFFERDESC;
  592.   Caps: TDSCBCAPS;
  593.   i: Integer;
  594. begin
  595.   EnterCritical;
  596.   try
  597.     if Assigned(FNotifications) then
  598.     begin
  599.       for i := 0 to FBufferCount do
  600.         with FNotifyPts^[i] do CloseHandle(hEventNotify);
  601.       FreeMem(FNotifyPts);
  602.       FNotifyPts := nil;
  603.       FNotifications.Release;
  604.       FNotifications := nil;
  605.     end;
  606.     if Assigned(FBuffer) then
  607.     begin
  608.       FBuffer.Release;
  609.       FBuffer := nil;
  610.     end;
  611.     if lpFormat <> nil then
  612.     begin
  613.       if ABufCount < DEFAULT_BUFFERCOUNT then
  614.         ABufCount := DEFAULT_BUFFERCOUNT;
  615.       FBufferCount := ABufCount;
  616.       FBufferPartSize := ABufSize - (ABufSize mod lpFormat^.nBlockAlign);
  617.       FBufferSize := FBufferPartSize * FBufferCount;
  618.       ZeroMemory(@BufferDesc, SizeOf(BufferDesc));
  619.       with BufferDesc do
  620.       begin
  621.         dwSize := SizeOf(BufferDesc);
  622.         dwFlags := DSCBCAPS_WAVEMAPPED;
  623.         dwBufferBytes := FBufferSize;
  624.         lpwfxFormat := lpFormat;
  625.       end;
  626.       MMAssert(FCapture.CreateCaptureBuffer(BufferDesc, FBuffer, nil) = S_OK,
  627.         MMSYSERR_INVALPARAM);
  628.       ZeroMemory(@Caps, SizeOf(Caps));
  629.       Caps.dwSize := SizeOf(Caps);
  630.       FBuffer.GetCaps(Caps);
  631.       FWaveMapped := Caps.dwFlags and DSCBCAPS_WAVEMAPPED > 0;
  632.       MMAssert(FBuffer.QueryInterface(IID_IDirectSoundNotify, FNotifications) = S_OK,
  633.         MMSYSERR_NOTSUPPORTED);
  634.      // FNotifications.AddRef; // Does not seem to be required (?)
  635.       FNotifyPts := AllocMem(SizeOf(FNotifyPts^[0]) * (FBufferCount + 1));
  636.       for i := 0 to FBufferCount-1 do
  637.         with FNotifyPts^[i] do
  638.         begin
  639.           dwOffset := (i + 1) * FBufferPartSize - lpFormat^.nBlockAlign;
  640.           hEventNotify := CreateEvent(nil, False, False, nil);
  641.         end;
  642.       with FNotifyPts^[FBufferCount] do
  643.       begin
  644.         dwOffset := DSBPN_OFFSETSTOP;
  645.         hEventNotify := CreateEvent(nil, False, False, nil);
  646.       end;
  647.       MMAssert(FNotifications.SetNotificationPositions(FBufferCount + 1,
  648.         @FNotifyPts^[0]) = S_OK, MMSYSERR_NOTSUPPORTED);
  649.     end;
  650.   finally
  651.     LeaveCritical;
  652.     if Assigned(DsNotificationThread) then
  653.       SetEvent(DsNotificationThread.FSystemEvent);
  654.   end;
  655. end;
  656. procedure TDsWaveInDevice.NotifyMessage(Msg: UINT; wParam: WPARAM; lParam: LPARAM); stdcall;
  657. type
  658.   TWaveInFunc = procedure(HIn: HWaveIn; wMsg:UINT; dwInstance, dwParam1, dwParam2:Longint); stdcall;
  659. begin
  660.   case FCallBackMode of
  661.     CALLBACK_WINDOW:
  662.       PostMessage(FCallBack, Msg, wParam, lParam);
  663.     CALLBACK_THREAD:
  664.       PostThreadMessage(FCallBack, Msg, wParam, lParam);
  665.     CALLBACK_FUNCTION:
  666.       TWaveInFunc(FCallBack)(HWaveIn(Self), Msg, FCBInstance, lParam, 0);
  667.   end;
  668. end;
  669. procedure TDsWaveInDevice.GetCaps(var Caps: TWaveInCaps);
  670. begin
  671.   CaptureCapsToWaveInCaps(FCapture, FGuid, Caps);
  672. end;
  673. function TDsWaveInDevice.GetFormat: PWaveFormatEx;
  674. var
  675.   wf: TWaveFormatEx;
  676. begin
  677.   MMAssert(FBuffer.GetFormat(@wf, SizeOf(wf), DWORD(nil^)) = DS_OK,
  678.     MMSYSERR_ERROR);
  679.    // Warning!!! the result remains on stack, so be careful with it
  680.   Result := @wf;
  681. end;
  682. procedure TDsWaveInDevice.SetFormat(Value: PWaveFormatEx);
  683. begin
  684.   MMCheck(MMSYSERR_NOTSUPPORTED);
  685. end;
  686. function TDsWaveInDevice.CaptureActive: Boolean;
  687. var
  688.   Status: DWORD;
  689. begin
  690.   if Assigned(FBuffer) then
  691.   begin
  692.     MMAssert(FBuffer.GetStatus(Status) = DS_OK, MMSYSERR_ERROR);
  693.     Result := Status and DSCBSTATUS_CAPTURING <> 0;
  694.   end else
  695.     Result := False;
  696. end;
  697. procedure TDsWaveInDevice.ProcessData(PointNumber: Integer);
  698. var
  699.    // Cursors have DirectX buffer as origin,
  700.    // Positions - capture reset
  701.   CaptureCursor, ReadCursor: DWORD;
  702.   WriteCursor, ReadPosition: integer;
  703.   procedure PassData(P: Pointer; L: Integer);
  704.   var
  705.     Buffer: TDsWaveBuffer;
  706.     L0, L1: Integer;
  707.   begin
  708.     L0 := L;
  709.     while (FQueue.Count > 0) and (L0 > 0) do
  710.     begin
  711.       Buffer := FQueue[0];
  712.       L1 := L0;
  713.       if Buffer.Accept(P, L1) then
  714.         ReturnBuffer;
  715.       Dec(L0, L1);
  716.       Inc(PChar(P), L1);
  717.     end;
  718.     if L0 > 0 then Stop;
  719.   end;
  720.   procedure TakeData(FromCursor, ToCursor: Integer);
  721.   var
  722.     Length: Integer;
  723.     p1, p2: Pointer;
  724.     l1, l2: DWORD;
  725.   begin
  726.     Length := ToCursor - FromCursor;
  727.     if Length > 0 then
  728.     begin
  729. {$IFDEF _MMDEBUG}
  730.       DB_FormatLn(0, 'Locking buffer at %5d - %5d', [FromCursor, ToCursor]);
  731. {$ENDIF}
  732.       MMAssert(FBuffer.Lock(FromCursor, Length, p1, l1, p2, l2, 0) = DS_OK,
  733.         MMSYSERR_ERROR);
  734.       try
  735.         PassData(p1, l1);
  736.         if l2 > 0 then PassData(p2, l2);
  737.       finally
  738.         MMAssert(FBuffer.Unlock(p1, l1, p2, l2) = DS_OK, MMSYSERR_ERROR);
  739.       end;
  740.     end
  741.   end;
  742. begin
  743.   EnterCritical;
  744.   try
  745.     if PointNumber = FBufferCount - 1 then
  746.       Inc(FBufferOrigin, FBufferSize);
  747.     MMAssert(FBuffer.GetCurrentPosition(CaptureCursor, ReadCursor) = DS_OK,
  748.       MMSYSERR_ERROR);
  749.     ReadPosition := FBufferOrigin + ReadCursor;
  750.     if ReadPosition > FWritePosition then
  751.     begin
  752.       WriteCursor := FWritePosition - FBufferOrigin;
  753.       if WriteCursor < 0 then
  754.       begin
  755.          // Check overflow
  756.         if WriteCursor < ReadCursor - FBufferSize then
  757.           WriteCursor := ReadCursor - FBufferSize;
  758.         TakeData(WriteCursor + FBufferSize, FBufferSize);
  759.         TakeData(0, ReadCursor);
  760.       end else
  761.         TakeData(WriteCursor, ReadCursor);
  762.       FWritePosition := ReadPosition;
  763.     end;
  764.   except
  765.     try
  766.       Stop;
  767.     except
  768.       // Something bad happenned if we are there...
  769.     end;
  770.   end;
  771.   LeaveCritical;
  772. end;
  773. function TDsWaveInDevice.FindBuffer(Header: PWaveHdr): TDsWaveBuffer;
  774. var
  775.   Index: Integer;
  776. begin
  777.   for Index := FWaveBuffers.Count-1 downto 0 do
  778.   begin
  779.     Result := FWaveBuffers[Index];
  780.     if Result.Data = Header then
  781.       exit;
  782.   end;
  783.   Result := nil;
  784. end;
  785. procedure TDsWaveInDevice.ReturnBuffer;
  786. var
  787.   Buffer: TDsWaveBuffer;
  788. begin
  789.   if FQueue.Count > 0 then
  790.   begin
  791.     Buffer := FQueue[0];
  792.     FQueue.Delete(0);
  793.     with Buffer.Data^ do
  794.       dwFlags := dwFlags and not WHDR_INQUEUE or WHDR_DONE;
  795.     NotifyMessage(MM_WIM_DATA, HWaveIn(Self), Integer(Buffer.Data));
  796.   end;
  797. end;
  798. procedure TDsWaveInDevice.AddBuffer(Header: PWaveHdr);
  799. var
  800.   Buffer: TDsWaveBuffer;
  801. begin
  802.   Buffer := FindBuffer(Header);
  803.   MMAssert(Assigned(Buffer) and (Buffer.FData.dwFlags and WHDR_PREPARED <> 0),
  804.     WAVERR_UNPREPARED);
  805.   with Buffer.Data^ do
  806.   begin
  807.     dwFlags := dwFlags and not WHDR_DONE or WHDR_INQUEUE;
  808.     dwBytesRecorded := 0;
  809.     lpNext := nil;
  810.   end;
  811.   EnterCritical;
  812.   if FQueue.Count > 0 then
  813.     TDsWaveBuffer(FQueue[FQueue.Count-1]).Data.lpNext := Buffer.Data;
  814.   FQueue.Add(Buffer);
  815.   LeaveCritical;
  816. end;
  817. procedure TDsWaveInDevice.PrepareBuffer(Header: PWaveHdr);
  818. var
  819.   Buffer: TDsWaveBuffer;
  820.   i, MinBufferSize: Integer;
  821.   wfx: TWaveFormatEx;
  822. begin
  823.   MMAssert(Header^.dwFlags and WHDR_PREPARED = 0, MMSYSERR_INVALPARAM);
  824.   Header^.dwFlags := WHDR_PREPARED;
  825.   Buffer := TDsWaveBuffer.Create(Header);
  826.   FWaveBuffers.Add(Buffer);
  827.    // Reconfigure internal buffers so that they match outer ones
  828.   if FState in [wdsInactive, wdsIdle] then
  829.   begin
  830.     MinBufferSize := Header.dwBufferLength;
  831.     for i := FWaveBuffers.Count-1 downto 0 do
  832.     begin
  833.       Buffer := FWaveBuffers[i];
  834.       if Buffer.Data.dwBufferLength < MinBufferSize then
  835.         MinBufferSize := Buffer.Data.dwBufferLength;
  836.     end;
  837.     if (MinBufferSize <> FBufferPartSize) or
  838.        (FWaveBuffers.Count >= DEFAULT_BUFFERCOUNT) and
  839.        ((FWaveBuffers.Count >= FBufferCount shl 1) or
  840.         (FWaveBuffers.Count shl 1 <= FBufferCount)) then
  841.     begin
  842.       wfx := Format^;
  843.       Reconfigure(@wfx, FWaveBuffers.Count, MinBufferSize);
  844.     end;
  845.   end;
  846. end;
  847. procedure TDsWaveInDevice.UnprepareBuffer(Header: PWaveHdr);
  848. var
  849.   Buffer: TDsWaveBuffer;
  850. begin
  851.   Buffer := FindBuffer(Header);
  852.   MMAssert(Assigned(Buffer) and (Header^.dwFlags and WHDR_PREPARED <> 0),
  853.     MMSYSERR_INVALPARAM);
  854.   MMAssert(FQueue.IndexOf(Buffer) = -1, WAVERR_STILLPLAYING);
  855.   EnterCritical;
  856.   Buffer.Free;
  857.   FWaveBuffers.Remove(Buffer);
  858.   LeaveCritical;
  859.   with Header^ do
  860.     dwFlags := dwFlags and not WHDR_PREPARED;
  861. end;
  862. procedure TDsWaveInDevice.Start;
  863. begin
  864.   if not CaptureActive then
  865.     MMAssert(FBuffer.Start(DSCBSTART_LOOPING) = DS_OK, MMSYSERR_ERROR);
  866.   FState := wdsStarted;
  867. end;
  868. procedure TDsWaveInDevice.Stop;
  869. begin
  870.   if CaptureActive then
  871.   begin
  872.     MMAssert(FBuffer.Stop = DS_OK, MMSYSERR_ERROR);
  873.     if (FQueue.Count > 0) and
  874.        (TDsWaveBuffer(FQueue[0]).Data.dwBytesRecorded > 0) then
  875.       ReturnBuffer;
  876.   end;
  877.   FState := wdsIdle;
  878. end;
  879. procedure TDsWaveInDevice.Reset;
  880. begin
  881.   Stop;
  882.   while FQueue.Count > 0 do
  883.     ReturnBuffer;
  884. end;
  885. procedure TDsWaveInDevice.GetPosition(lpInfo: PMMTime);
  886. var
  887.   CaptureCursor, ReadCursor: DWORD;
  888. begin
  889.   MMAssert(lpInfo <> nil, MMSYSERR_INVALPARAM);
  890.   MMAssert(FBuffer.GetCurrentPosition(CaptureCursor, ReadCursor) = DS_OK,
  891.     MMSYSERR_ERROR);
  892.   lpInfo^.cb := FBufferOrigin + CaptureCursor;
  893.   with lpInfo^ do case wType of
  894.     TIME_BYTES:
  895.       ;
  896.     TIME_MS:
  897.       ms := MulDiv(cb, 1000, Format.nAvgBytesPerSec);
  898.     TIME_SAMPLES:
  899.       sample := MulDiv(cb, 1000, Format.nBlockAlign);
  900.   else
  901.     MMCheck(MMSYSERR_INVALFLAG);
  902.   end;
  903. end;
  904.  // TDsWaveBuffer
  905. constructor TDsWaveBuffer.Create(lpWaveHdr: PWaveHdr);
  906. begin
  907.   inherited Create;
  908.   FData := lpWaveHdr;
  909. end;
  910. function TDsWaveBuffer.CanAccept: Integer;
  911. begin
  912.   with FData^ do
  913.     Result := dwBufferLength - dwBytesRecorded;
  914. end;
  915. function TDsWaveBuffer.Accept(WaveData: Pointer; var Length: Integer): Boolean;
  916. var
  917.   FreeRoom: Integer;
  918. begin
  919.   FreeRoom := CanAccept;
  920.   Result := Length >= FreeRoom;
  921.   if Result then
  922.     Length := FreeRoom;
  923.   with FData^ do
  924.   begin
  925.     CopyMemory(lpData + dwBytesRecorded, WaveData, Length);
  926.     Inc(dwBytesRecorded, Length);
  927.   end;
  928. end;
  929. procedure Cleanup;
  930. var
  931.   i: integer;
  932. begin
  933.   if Assigned(CaptureDeviceList) then
  934.   begin
  935.     FreeDriverList(CaptureDeviceList);
  936.     CaptureDeviceList.Free;
  937.     CaptureDeviceList := nil
  938.   end;
  939.   if Assigned(OpenDevices) then
  940.   begin
  941.     for i := OpenDevices.Count-1 downto 0 do
  942.       TObject(OpenDevices[i]).Free;
  943.     OpenDevices.Free;
  944.     OpenDevices := nil;
  945.   end;
  946.   if DataSectionOK then
  947.   begin
  948.     DataSectionOK := False;
  949.     DeleteCriticalSection(DataSection);
  950.   end;
  951. end;
  952. // Initialization
  953. initialization
  954. finalization
  955.    CleanUp;
  956. end.