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

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/index.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: 25.11.98 - 13:23:40 $                                        =}
  24. {========================================================================}
  25. unit MMWavIn;
  26. {$C FIXED PRELOAD PERMANENT}
  27. {$I COMPILER.INC}
  28. {.$DEFINE _MMDEBUG}
  29. interface
  30. uses
  31. {$IFDEF WIN32}
  32.   Windows,
  33. {$ELSE}
  34.   WinTypes,
  35.   WinProcs,
  36. {$ENDIF}
  37.   SysUtils,
  38.   Messages,
  39.   Classes,
  40.   Graphics,
  41.   Controls,
  42.   Forms,
  43.   Dialogs,
  44.   MMSystem,
  45.   MMUtils,
  46.   MMObj,
  47.   MMString,
  48.   MMDSPObj,
  49.   MMDSPMtr,
  50.   MMRegs,
  51.   MMPCMSup,
  52.   MMAlloc,
  53.   MMWaveIO
  54.   {$IFDEF _MMDEBUG}
  55.   ,MMDebug
  56.   {$ENDIF};
  57. {$IFDEF _MMDEBUG}
  58.    {$DEFINE NUMERATE}
  59.    const
  60.         DEBUGLEVEL = 0; { 0,1,2 }
  61. {$ENDIF}
  62. const
  63.   {$IFDEF CBUILDER3} {$EXTERNALSYM MAXERRORLENGTH} {$ENDIF}
  64.   MAXERRORLENGTH   = 255;
  65.   {$IFDEF CBUILDER3} {$EXTERNALSYM MAXINBUFFERS} {$ENDIF}
  66.   MAXINBUFFERS     = 500;
  67.   {$IFDEF CBUILDER3} {$EXTERNALSYM MINBUFFERSIZE} {$ENDIF}
  68.   MINBUFFERSIZE    = 32;
  69. type
  70.   EMMWaveInError   = class(Exception);
  71.   TMMWaveInStates  = (wisClose, wisOpen, wisRecord,wisPause);
  72.   TMMWaveInState   = set of TMMWaveInStates;
  73.   { Pointers to waveIn headers }
  74.   TMMWaveInHdrs    = array[0..MAXINBUFFERS-1] of PWaveHdr;
  75.   TMMCustomWaveIn  = class;
  76.   {$IFDEF WIN32}
  77.   {-- TMMWaveInThread ----------------------------------------------------}
  78.   TMMWaveInThread = class(TMMDSPThread)
  79.   private
  80.      procedure Execute; override;
  81.   end;
  82.   {$ENDIF}
  83.   {-- TMMCustomWaveIn ---------------------------------------------------------}
  84.   TMMCustomWaveIn = class(TMMCustomSoundComponent)
  85.   private
  86.     FHandle        : THandle;        { handle used for callback window    }
  87.     FPriority      : TThreadPriority;{ thread priority                    }
  88.     FDeviceID      : TMMDeviceID;    { WAVEIN device ID                   }
  89.     FHWaveIn       : HWaveIn;        { Handle to input device             }
  90.     FState         : TMMWaveInState; { Current device state               }
  91.     FWaveInHdrs    : TMMWaveInHdrs;  { WaveIn Headers and Buffers         }
  92.     FBufferIndex   : integer;        { the current Header/BufferIndex     }
  93.     FCallbackMode  : TMMCBMode;      { use Window or Callback function    }
  94.     FError         : integer;        { Last WaveIn Error                  }
  95.     FNumdevs       : integer;      { Num. of input devices on system    }
  96.     FWaveInCaps    : TWaveInCaps;    { Stuff from WAVEINCAPS              }
  97.     FProductName   : String;
  98.     FDriverVersion : integer;        { Specifies the driver version       }
  99.                                      { high-order byte is major version   }
  100.                                      { low-order byte is minor version    }
  101.     FInHandler     : integer;        { marks that we in any event handler }
  102.     FStopIt        : Boolean;        { we should stop playing if possible }
  103.     FCloseIt       : Boolean;        { we should close device if possible }
  104.     FStopping      : Boolean;        { we actually stop the device        }
  105.     FClosing       : Boolean;        { we actually close the device       }
  106.     FReseting      : Boolean;        { we actually resting the device     }
  107.     FPosted        : Boolean;
  108.     FBytesRecorded : Longint;        { total bytes we have recorded       }
  109.     FLastPosition  : Cardinal;       { the last playback position         }
  110.     FWrapArrounds  : Cardinal;       { number of position wrap-arrounds   }
  111.     FWrapSize      : Cardinal;       { where has the position wrapped ?   }
  112.     FNumBuffers    : integer;        { number of buffers for queue        }
  113.     FBufferCounter : integer;        { buffer counter for buffers in use  }
  114.     FTimeFormat    : TMMTimeFormats; { the actual time format for Position}
  115.     FWaveFormat    : TWaveFormatEx;  { internal WaveFormatEx              }
  116.     FMode          : TMMMode;        { Mono / Stereo                      }
  117.     FBits          : TMMBits;        { 8 / 16 bits                        }
  118.     FRate          : Longint;        { SampleRate                         }
  119.     FMaxRecTime    : Longint;        { maximal recording time             }
  120.     FMaxRecBytes   : Longint;
  121.     FAllocator     : TMMAllocator;
  122.     {$IFDEF WIN32}
  123.     FThreadError   : Boolean;        { Erro in Thread handler             }
  124.     FInThread      : TMMWaveInThread;{ Input Thread for callback handling }
  125.     DataSection    : TRtlCriticalSection;{ CriticalSection Object         }
  126.     DataSEctionOK  : Boolean;        { CriticalSection prepared           }
  127.     FInEvent       : THandle;        { event object for notify handling   }
  128.     FCloseEvent    : THandle;        { event object to close the device   }
  129.     {$ENDIF}
  130.     { Events }
  131.     FOnError       : TNotifyEvent;   { Error occured                    }
  132.     FOnOpen        : TNotifyEvent;   { Wave Device succ. opened         }
  133.     FOnStart       : TNotifyEvent;   { Wave Device succ. started        }
  134.     FOnPause       : TNotifyEvent;   { Wave Device succ. paused         }
  135.     FOnRestart     : TNotifyEvent;   { Wave Device succ. restarted      }
  136.     FOnStop        : TNotifyEvent;   { Wave Device succ. stopped        }
  137.     FOnClose       : TNotifyEvent;   { Wave Device succ. closed         }
  138.     function  WaveInErrorString(WError: integer): String;
  139.     procedure SetPriority(aValue: TThreadPriority);
  140.     procedure SetMode(aValue: TMMMode);
  141.     procedure SetBits(aValue: TMMBits);
  142.     procedure SetSampleRate(aValue: Longint);
  143.     procedure SetTimeFormat(aValue: TMMTimeFormats);
  144.     procedure SetMaxRecTime(aValue: Longint);
  145.     procedure CalcMaxRecBytes;
  146.     function  GetSamplePosition: Cardinal;
  147.     function  GetInternalPosition: int64;
  148.     function  GetPosition: MM_int64;
  149.     function  GetPositionHigh: Cardinal;
  150.     function  GetPosition64: int64;
  151.     procedure SetWaveParams;
  152.     procedure WaveInHandler(VAR Msg: TMessage);
  153.     procedure AllocWaveHeaders;
  154.     procedure FreeWaveHeaders;
  155.     procedure PrepareWaveHeaders;
  156.     procedure UnPrepareWaveHeaders;
  157.     procedure AddWaveHeader(lpWaveHdr: PWaveHdr);
  158.     procedure ProcessWaveHeader(lpWaveHdr: PWaveHdr);
  159.     {$IFDEF WIN32}
  160.     procedure InitThread;
  161.     procedure DoneThread;
  162.     procedure CloseEvents;
  163.     {$ENDIF}
  164.     procedure InitCritical;
  165.     procedure EnterCritical;
  166.     procedure LeaveCritical;
  167.     procedure DoneCritical;
  168.   protected
  169.     {-- Private Waveform API declarations to be overridden in descendants --}
  170.     waveInGetNumDevs: function: UINT; stdcall;
  171.     waveInGetDevCaps: function(hwin: HWAVEIN; lpCaps: PWaveInCaps; uSize: UINT): MMRESULT; stdcall;
  172.     waveInGetErrorText: function(mmrError: MMRESULT; lpText: PChar; uSize: UINT): MMRESULT; stdcall;
  173.     waveInOpen: function(lphWaveIn: PHWAVEIN; uDeviceID: UINT; lpFormatEx: PWaveFormatEx; dwCallback, dwInstance, dwFlags: DWORD): MMRESULT; stdcall;
  174.     waveInClose: function(hWaveIn: HWAVEIN): MMRESULT; stdcall;
  175.     waveInPrepareHeader: function(hWaveIn: HWAVEIN; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
  176.     waveInUnprepareHeader: function(hWaveIn: HWAVEIN; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
  177.     waveInAddBuffer: function(hWaveIn: HWAVEIN; lpWaveInHdr: PWaveHdr; uSize: UINT): MMRESULT; stdcall;
  178.     waveInStart: function(hWaveIn: HWAVEIN): MMRESULT; stdcall;
  179.     waveInStop: function(hWaveIn: HWAVEIN): MMRESULT; stdcall;
  180.     waveInReset: function(hWaveIn: HWAVEIN): MMRESULT; stdcall;
  181.     waveInGetPosition: function(hWaveIn: HWAVEIN; lpInfo: PMMTime; uSize: UINT): MMRESULT; stdcall;
  182.     waveInGetID: function(hWaveIn: HWAVEIN; lpuDeviceID: PUINT): MMRESULT; stdcall;
  183.     { And set up all this stuff! }
  184.     procedure SetupWaveEngine; virtual; abstract;
  185.     procedure SetPWaveFormat(aValue: PWaveFormatEx); override;
  186.     procedure SetBufferSize(aValue: Longint); override;
  187.     function  GetBufferSize: Longint; override;
  188.     procedure SetNumBuffers(aValue: integer); override;
  189.     function  GetNumBuffers: integer; override;
  190.     procedure SetDeviceID(aValue: TMMDeviceID); override;
  191.     function  GetDeviceID: TMMDeviceID; override;
  192.     procedure SetProductName(aValue: string); override;
  193.     function  GetProductName: string; override;
  194.     procedure SetCallBackMode(aValue: TMMCBMode); override;
  195.     function  GetCallBackMode: TMMCBMode; override;
  196.     procedure Opened; override;
  197.     procedure Started; override;
  198.     procedure Paused; override;
  199.     procedure Restarted; override;
  200.     procedure Stopped; override;
  201.     procedure Closed; override;
  202.     procedure BufferReady(lpwh: PWaveHdr); override;
  203.     procedure Error(Msg: string); virtual;
  204.   public
  205.     constructor Create(AOwner: TComponent); override;
  206.     destructor Destroy; override;
  207.     procedure Open; virtual;
  208.     procedure Close; virtual;
  209.     procedure Start; virtual;
  210.     procedure Pause; virtual;
  211.     procedure Restart; virtual;
  212.     procedure Stop; virtual;
  213.     function  QueryDevice(aDeviceID: TMMDeviceID; pwfx: PWaveFormatEx): Boolean;
  214.     {$IFDEF WIN32}
  215.     { maybe you must syncronize anything if UseThread = True ? }
  216.     procedure SynchronizeVCL(VCLProc: TThreadMethod);
  217.     {$ENDIF}
  218.     property Handle: HWaveIn read FHWaveIn;
  219.     property WaveInCaps: TWaveInCaps read FWaveInCaps;
  220.     property Numdevs: integer read FNumdevs;
  221.     property State: TMMWaveInState read FState;
  222.     property DriverVersion: integer read FDriverVersion;
  223.     property BytesRecorded: Longint read FBytesRecorded;
  224.     property Position: MM_int64 read GetPosition;
  225.     property PositionHigh: Cardinal read GetPositionHigh;
  226.     property Position64: int64 read GetPosition64;
  227.     property BufferIndex: integer read FBufferIndex;
  228.     property PWaveFormat;
  229.     {$IFNDEF CBUILDER3}
  230.     property WaveHdrs: TMMWaveInHdrs read FWaveInHdrs;
  231.     {$ENDIf}
  232.   published
  233.     { Events }
  234.     property OnError: TNotifyEvent read FOnError write FOnError;
  235.     property OnOpen: TNotifyEvent read FOnOpen write FOnOpen;
  236.     property OnStart: TNotifyEvent read FOnStart write FOnStart;
  237.     property OnPause: TNotifyEvent read FOnPause write FOnPause;
  238.     property OnRestart: TNotifyEvent read FOnRestart write FOnRestart;
  239.     property OnStop: TNotifyEvent read FOnStop write FOnStop;
  240.     property OnClose: TNotifyEvent read FOnClose write FOnClose;
  241.     property OnBufferReady;
  242.     property Output;
  243.     property BufferSize;
  244.     property CallBackMode;
  245.     property DeviceID;
  246.     property NumBuffers;
  247.     property ProductName;
  248.     property Mode: TMMMode read FMode write SetMode default mMono;
  249.     property BitLength: TMMBits read FBits write SetBits default b8Bit;
  250.     property SampleRate: Longint read FRate write SetSampleRate default 11025;
  251.     property TimeFormat: TMMTimeFormats read FTimeFormat write SetTimeFormat default tfByte;
  252.     property MaxRecordTime: Longint read FMaxRecTime write SetMaxRecTime default -1;
  253.     property Priority: TThreadPriority read FPriority write SetPriority default tpHigher;
  254.   end;
  255.   {-- TMMWaveIn ---------------------------------------------------------------}
  256.   TMMWaveIn = class(TMMCustomWaveIn)
  257.   protected
  258.     procedure SetupWaveEngine; override;
  259.   end;
  260. function WaveInGetDeviceName(DeviceID: TMMDeviceID): String;
  261. function WaveInReady(DeviceID: TMMDeviceID): Boolean;
  262. function DeviceFullDuplex(DeviceID: TMMDeviceID; pwfx: PWaveFormatEx): Boolean;
  263. var
  264.    Devices: TStringList = nil;
  265.    
  266. implementation
  267. uses consts;
  268. const
  269.      MM_WIM_STOP = MM_USER+2;
  270. {$IFNDEF WIN32}
  271. { Bug fix for Error in Delphi 1.0 MMSystem declaration }
  272. function WaveInClose(hWaveIn: THandle): Word; far; external 'MMSYSTEM' index 505;
  273. {$ENDIF}
  274. procedure WaveInFunc(hWaveIn:HWaveIn;wMsg:UINT;dwInstance,dwParam1,dwParam2:Longint);
  275. export;{$IFDEF WIN32}stdcall;{$ENDIF}forward;
  276. {$IFDEF _MMDEBUG}
  277. {-------------------------------------------------------------------------}
  278. procedure DebugStr(Level: integer; s: String);
  279. begin
  280.    if (s <> ' ') then s := 'WaveIn: '+s;
  281.    DB_WriteStrLn(Level,s);
  282. end;
  283. {$ENDIF}
  284. {-------------------------------------------------------------------------}
  285. function DeviceFullDuplex(DeviceID: TMMDeviceID; pwfx: PWaveFormatEx): Boolean;
  286. var
  287.    InHandle,OutHandle: HWAVEOUT;
  288.    Error: MMRESULT;
  289.    wfx: TWaveFormatEx;
  290. begin
  291.    Result := False;
  292.    if (DeviceID < waveOutGetNumDevs) and (DeviceID >= integer(WAVE_MAPPER)) then
  293.    try
  294.       OutHandle := 0;
  295.       InHandle := 0;
  296.       if (pwfx = nil) then
  297.       begin
  298.          pwfx := @wfx;
  299.          pcmBuildWaveHeader(pwfx, 16, 2, 22050);
  300.       end;
  301.       {$IFDEF WIN32}
  302.       Error := WaveInOpen(@InHandle, DeviceId, MMSystem.PWaveFormatEx(pwfx), 0, 0, CALLBACK_NULL);
  303.       {$ELSE}
  304.       Error := WaveInOpen(@InHandle, DeviceId, Pointer(pwfx), 0, 0, CALLBACK_NULL);
  305.       {$ENDIF}
  306.       if (Error = MMSYSERR_NOERROR) then
  307.       begin
  308.          {$IFDEF WIN32}
  309.          Error := WaveOutOpen(@OutHandle, DeviceID, MMSystem.PWaveFormatEx(pwfx), 0, 0, CALLBACK_NULL);
  310.          {$ELSE}
  311.          Error := WaveOutOpen(@OutHandle, DeviceID, Pointer(pwfx), 0, 0, CALLBACK_NULL);
  312.          {$ENDIF}
  313.          if (Error = MMSYSERR_NOERROR) then Result := True;
  314.       end;
  315.    finally
  316.       if (OutHandle <> 0) then WaveOutClose(OutHandle);
  317.       if (InHandle <> 0) then WaveInClose(InHandle);
  318.    end;
  319. end;
  320. {-------------------------------------------------------------------------}
  321. function WaveInReady(DeviceID: TMMDeviceID): Boolean;
  322. var
  323.    InHandle: HWAVEOUT;
  324.    Error: MMRESULT;
  325.    wfx: TWaveFormatEx;
  326. begin
  327.    Result := False;
  328.    if (DeviceID < waveInGetNumDevs) and (DeviceID >= integer(WAVE_MAPPER)) then
  329.    try
  330.       InHandle := 0;
  331.       pcmBuildWaveHeader(@wfx, 8, 1, 22050);
  332.       {$IFDEF WIN32}
  333.       Error := WaveInOpen(@InHandle, DeviceId, MMSystem.PWaveFormatEx(@wfx), 0, 0, CALLBACK_NULL);
  334.       {$ELSE}
  335.       Error := WaveInOpen(@InHandle, DeviceId, Pointer(@wfx), 0, 0, CALLBACK_NULL);
  336.       {$ENDIF}
  337.       if (Error = MMSYSERR_NOERROR) then
  338.       begin
  339.          Result := True;
  340.       end;
  341.    finally
  342.       if (InHandle <> 0) then WaveInClose(InHandle);
  343.    end;
  344. end;
  345. {-------------------------------------------------------------------------}
  346. function WaveInGetDeviceName(DeviceID: TMMDeviceID): String;
  347. var
  348.    Caps   : TWaveInCaps;
  349. begin
  350.    Result := '';
  351.    if (DeviceID < waveInGetNumDevs) and (DeviceID >= integer(WAVE_MAPPER)) then
  352.    begin
  353.       { Set the name and other WAVEOUTCAPS properties to match the ID }
  354.       if waveInGetDevCaps(DeviceID, @Caps, sizeof(TWaveInCaps)) = 0 then
  355.          Result := StrPas(Caps.szPname);
  356.    end;
  357. end;
  358. {-- TMMCustomWaveIn ------------------------------------------------------------}
  359. constructor TMMCustomWaveIn.Create(AOwner: TComponent);
  360. begin
  361.    inherited Create(AOwner);
  362.    SetupWaveEngine;
  363.    { Set defaults }
  364.    FHWaveIn       := 0;
  365.    FState         := [wisClose];
  366.    FError         := 0;
  367.    FNumBuffers    := 10;
  368.    FMode          := mMono;
  369.    FBits          := b8Bit;
  370.    FRate          := 11025;
  371.    FProductName   := '';
  372.    FDriverVersion := 0;
  373.    FBytesRecorded := 0;
  374.    FTimeFormat    := tfByte;
  375.    FCallBackMode  := cmWindow;
  376.    FStopping      := False;
  377.    FPosted        := False;
  378.    FClosing       := False;
  379.    FReseting      := False;
  380.    FMaxRecTime    := -1;
  381.    FMaxRecBytes   := MaxLongint;
  382.    FPriority      := tpHigher;
  383.    FAllocator     := TMMAllocator.Create;
  384.    FBufferIndex := 0;
  385.    { clear all pointers to Nil }
  386.    FillChar(FWaveInHdrs, sizeOf(TMMWaveInHdrs), 0);
  387.    FNumDevs := waveInGetNumDevs;
  388.    SetWaveParams;
  389.    SetDeviceID(0);
  390.    {$IFDEF WIN32}
  391.    DataSectionOK := False;
  392.    {$ENDIF}
  393.    { Create the window for callback notification }
  394.    if not (csDesigning in ComponentState) then
  395.            FHandle := AllocateHwnd(WaveInHandler);
  396.    ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
  397.    if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
  398. end;
  399. {-- TMMCustomWaveIn ------------------------------------------------------------}
  400. destructor TMMCustomWaveIn.Destroy;
  401. begin
  402.    { Close the device if it's open }
  403.    if (FHWaveIn <> 0) then Close;
  404.    { Destroy the window for callback notification }
  405.    if (FHandle <> 0) then DeallocateHwnd(FHandle);
  406.    if (FAllocator <> nil) then FAllocator.Free;
  407.    inherited Destroy;
  408. end;
  409. {-- TMMCustomWaveIn ------------------------------------------------------------}
  410. procedure TMMCustomWaveIn.Error(Msg: string);
  411. begin
  412.    if assigned(FOnError) then FOnError(Self);
  413.    raise EMMWaveInError.Create(Msg);
  414. end;
  415. {-- TMMCustomWaveIn ------------------------------------------------------------}
  416. { Allocate memory for the WaveIn header and buffers }
  417. procedure TMMCustomWaveIn.AllocWaveHeaders;
  418. Var
  419.    i: integer;
  420.    lpwh: PWaveHdr;
  421. begin
  422.    if (BufferSize > 0) then
  423.    begin
  424.       for i := 0 to FNumBuffers-1 do
  425.       begin
  426.          if (FWaveInHdrs[i] = Nil) then
  427.          begin
  428.               { set up a wave header for recording and lock     }
  429.               lpwh := FAllocator.AllocBuffer(GPTR, SizeOf(TMMWaveHdr) + BufferSize);
  430.               if lpwh = NIL then
  431.                  Error(LoadResStr(IDS_HEADERMEMERROR));
  432.               { Data occurs directly after the header }
  433.               lpwh^.lpData         := PChar(lpwh) + sizeOf(TMMWaveHdr);
  434.               lpwh^.dwBufferLength := BufferSize;
  435.               lpwh^.dwBytesRecorded:= 0;
  436.               lpwh^.dwFlags        := 0;
  437.               lpwh^.dwLoops        := 0;
  438.               lpwh^.dwUser         := 0;
  439.               lpwh^.lpNext         := nil;
  440.               FWaveInHdrs[i]       := lpwh;
  441.          end;
  442.       end;
  443.    end;
  444. end;
  445. {-- TMMCustomWaveIn ------------------------------------------------------------}
  446. procedure TMMCustomWaveIn.FreeWaveHeaders;
  447. Var
  448.    i: integer;
  449. begin
  450.    for i := 0 to FNumBuffers-1 do
  451.    begin
  452.       { unlock and free memory for WaveInHdr }
  453.       if FWaveInHdrs[i] <> NIL then
  454.       begin
  455.          FAllocator.FreeBuffer(Pointer(FWaveInHdrs[i]));
  456.          FWaveInHdrs[i] := Nil;
  457.       end;
  458.    end;
  459. end;
  460. {-- TMMCustomWaveIn ------------------------------------------------------------}
  461. function TMMCustomWaveIn.WaveInErrorString(WError: integer): String;
  462. Var
  463.    errorDesc: PChar;
  464. begin
  465.    { convert the numeric return code from an MMSYSTEM function to a string }
  466.    errorDesc := Nil;
  467.    try
  468.       errorDesc := StrAlloc(MAXERRORLENGTH);
  469.       if waveInGetErrorText(WError, errorDesc, MAXERRORLENGTH) = 0 then
  470.          Result := StrPas(errorDesc)
  471.       else
  472.          Result := LoadResStr(IDS_ERROROUTOFRANGE);
  473.    finally
  474.       StrDispose(errorDesc);
  475.    end;
  476. end;
  477. {-- TMMCustomWaveIn ------------------------------------------------------------}
  478. Procedure TMMCustomWaveIn.SetDeviceID(aValue: TMMDeviceID);
  479. begin
  480.    if (wisOpen in FState) then
  481.       Error(LoadResStr(IDS_PROPERTYOPEN));
  482.    FProductName := LoadResStr(IDS_WINODEVICE);
  483.    FDriverVersion := 0;
  484.    if (FNumDevs > 0) and (aValue >= MapperId) and (aValue < FNumDevs) then
  485.    begin
  486.       { Set the name and other WAVEINCAPS properties to match the ID }
  487.       FError := waveInGetDevCaps(aValue, @FWaveInCaps, sizeof(TWaveInCaps));
  488.       if FError = 0 then
  489.       with FWaveInCaps do
  490.       begin
  491.          FProductName := StrPas(szPname);
  492.          FDriverVersion := vDriverVersion;
  493.       end
  494.    end;
  495.    { set the new device }
  496.    FDeviceID := aValue;
  497.    if (aValue < MapperId) or (aValue >= FNumDevs) then
  498.        FDeviceID := InvalidID;
  499.    {$IFDEF WIN32}
  500.    {$IFDEF TRIAL}
  501.    {$DEFINE _HACK1}
  502.    {$I MMHACK.INC}
  503.    {$ENDIF}
  504.    {$ENDIF}
  505. end;
  506. {-- TMMCustomWaveIn ------------------------------------------------------------}
  507. function TMMCustomWaveIn.GetDeviceID: TMMDeviceID;
  508. begin
  509.    Result := FDeviceID;
  510. end;
  511. {-- TMMCustomWaveIn ------------------------------------------------------------}
  512. procedure TMMCustomWaveIn.SetProductName(aValue: String);
  513. begin
  514.    { dummy }
  515. end;
  516. {-- TMMCustomWaveIn ------------------------------------------------------------}
  517. function TMMCustomWaveIn.GetProductName: String;
  518. begin
  519.    Result := FProductName;
  520. end;
  521. {-- TMMCustomWaveIn ------------------------------------------------------------}
  522. function TMMCustomWaveIn.QueryDevice(aDeviceID: TMMDeviceID; pwfx: PWaveFormatEx): Boolean;
  523. Var
  524.    aRate: Word;
  525.    aMode: Word;
  526.    aBits: Word;
  527.    aWaveInCaps: TWaveInCaps;
  528.    aHandle: HWaveIn;
  529. begin
  530.    if (aDeviceID >= MapperId) and (aDeviceID < FNumDevs) and (pwfx <> nil) then
  531.    begin
  532.       { query the Wave input device. }
  533.       Result := WaveInOpen(@aHandle,
  534.                            aDeviceId,
  535.                            Pointer(pwfx),
  536.                            0, 0,
  537.                            WAVE_FORMAT_QUERY) = 0;
  538.       if Result and (pwfx^.wFormatTag = WAVE_FORMAT_PCM) then
  539.       begin
  540.          Result := waveInGetDevCaps(aDeviceID,
  541.                                     @aWaveInCaps,
  542.                                     sizeof(TWaveInCaps)) = 0;
  543.          if Result then
  544.          with aWaveInCaps do
  545.          begin
  546.              aRate := pwfx^.nSamplesPerSec;
  547.              aMode := pwfx^.nChannels;
  548.              aBits := pwfx^.wBitsPerSample;
  549.              case aRate of
  550.              8000..11025: case aMode of
  551.                              1: case aBits of
  552.                                    8: Result := (dwFormats AND Wave_Format_1M08 <> 0);
  553.                                   16: Result := (dwFormats AND Wave_Format_1M16 <> 0);
  554.                                 end;
  555.                              2: case aBits of
  556.                                    8: Result := (dwFormats AND Wave_Format_1S08 <> 0);
  557.                                   16: Result := (dwFormats AND Wave_Format_1S16 <> 0);
  558.                                 end;
  559.                           end;
  560.             11026..22050: case aMode of
  561.                              1: case aBits of
  562.                                    8: Result := (dwFormats AND Wave_Format_2M08 <> 0);
  563.                                   16: Result := (dwFormats AND Wave_Format_2M16 <> 0);
  564.                                 end;
  565.                              2: case aBits of
  566.                                    8: Result := (dwFormats AND Wave_Format_2S08 <> 0);
  567.                                   16: Result := (dwFormats AND Wave_Format_2S16 <> 0);
  568.                                 end;
  569.                           end;
  570.             22051..48000: case aMode of
  571.                              1: case aBits of
  572.                                    8: Result := (dwFormats AND Wave_Format_4M08 <> 0);
  573.                                   16: Result := (dwFormats AND Wave_Format_4M16 <> 0);
  574.                                 end;
  575.                              2: case aBits of
  576.                                    8: Result := (dwFormats AND Wave_Format_4S08 <> 0);
  577.                                   16: Result := (dwFormats AND Wave_Format_4S16 <> 0);
  578.                                 end;
  579.                           end;
  580.              end;
  581.          end;
  582.       end;
  583.    end
  584.    else Result := False;
  585.    {$IFDEF WIN32}
  586.    {$IFDEF TRIAL}
  587.    {$DEFINE _HACK2}
  588.    {$I MMHACK.INC}
  589.    {$ENDIF}
  590.    {$ENDIF}
  591. end;
  592. {-- TMMCustomWaveIn -----------------------------------------------------------}
  593. procedure TMMCustomWaveIn.SetTimeFormat(aValue: TMMTimeFormats);
  594. begin
  595.    if (aValue <> FTimeFormat) then
  596.    begin
  597.       FTimeFormat := aValue;
  598.       if (FMaxRecTime >= 0) then
  599.       begin
  600.          case FTimeFormat of
  601.              tfMillisecond: FMaxRecTime := wioBytesToTime(PWaveFormat,FMaxRecBytes);
  602.              tfSample     : FMaxRecTime := wioBytesToSamples(PWaveFormat,FMaxRecBytes);
  603.            else FMaxRecTime:= FMaxRecBytes;
  604.          end;
  605.       end;
  606.    end;
  607. end;
  608. {-- TMMCustomWaveIn -----------------------------------------------------------}
  609. procedure TMMCustomWaveIn.SetMaxRecTime(aValue: Longint);
  610. begin
  611.    if (aValue <> FMaxRecTime) then
  612.    begin
  613.       FMaxRecTime := aValue;
  614.       CalcMaxRecBytes;
  615.    end;
  616. end;
  617. {-- TMMCustomWaveIn -----------------------------------------------------------}
  618. procedure TMMCustomWaveIn.CalcMaxRecBytes;
  619. begin
  620.    if (FMaxRecTime >= 0) and (PWaveFormat <> nil) then
  621.    begin
  622.       try
  623.          case FTimeFormat of
  624.             tfMillisecond: FMaxRecBytes := wioTimeToBytes(PWaveFormat,FMaxRecTime);
  625.             tfSample     : FMaxRecBytes := wioSamplesToBytes(PWaveFormat,FMaxRecTime);
  626.             else FMaxRecBytes := FMaxRecTime;
  627.          end;
  628.       except
  629.          FMaxRecBytes := MaxLongint;
  630.       end;
  631.    end
  632.    else FMaxRecBytes := MaxLongint;
  633.    FMaxRecBytes := FMaxRecBytes-(FMaxRecBytes mod PWaveFormat^.nBlockAlign);
  634. end;
  635. {-- TMMCustomWaveIn -----------------------------------------------------------}
  636. procedure TMMCustomWaveIn.SetPriority(aValue: TThreadPriority);
  637. begin
  638.    FPriority := aValue;
  639.    if (FInThread <> nil) then
  640.        FInThread.Priority := FPriority;
  641. end;
  642. {-- TMMCustomWaveIn -----------------------------------------------------------}
  643. function TMMCustomWaveIn.GetSamplePosition: Cardinal;
  644. Var
  645.    MMTime: TMMTime;
  646. begin
  647.    Result := 0;
  648.    if (wisOpen in FState) and (PWaveFormat <> Nil) and not FClosing then
  649.    begin
  650.       MMTime.wType := Time_Samples;
  651.       FError := WaveInGetPosition(FHWaveIn, @MMTime, SizeOf(TMMTime));
  652.       if (FError <> 0) or (MMTime.wType <> Time_Samples) then
  653.       begin
  654.          MMTime.wType := Time_Bytes;
  655.          FError := WaveInGetPosition(FHWaveIn, @MMTime, SizeOf(TMMTime));
  656.          if (FError <> 0) then
  657.              Error('WaveInGetPosition:'#10#13+WaveInErrorString(FError));
  658.          MMTime.Sample := wioBytesToSamples(PWaveFormat,MMTime.cb);
  659.       end;
  660.       Result := MMTime.Sample;
  661.    end;
  662. end;
  663. {-- TMMCustomWaveIn -----------------------------------------------------------}
  664. function TMMCustomWaveIn.GetInternalPosition: Int64;
  665. var
  666.    Samples,Pos: int64;
  667.    S: Cardinal;
  668.    WrapSize: int64;
  669. begin
  670.    Result := 0;
  671.    if (wisOpen in FState) and (PWaveFormat <> Nil) and not FCloseIt then
  672.    begin
  673.       S := GetSamplePosition;
  674.       {$IFDEF WIN32}
  675.       asm
  676.          mov   eax, S
  677.          mov   dword ptr Pos[0], eax
  678.          xor   eax, eax
  679.          mov   dword ptr Pos[4], eax
  680.          mov   eax, Self
  681.          mov   eax, TMMWaveIn(eax).FWrapSize
  682.          mov   dword ptr WrapSize[0], eax
  683.          xor   eax, eax
  684.          mov   dword ptr WrapSize[4], eax
  685.       end;
  686.       Samples := (FWrapArrounds*WrapSize)+Pos;
  687.       {$ELSE}
  688.       Samples := S;
  689.       {$ENDIF}
  690.       case FTimeFormat of
  691.            tfMilliSecond: Result := wioSamplesToTime64(PWaveFormat,Samples);
  692.            tfByte       : Result := wioSamplesToBytes64(PWaveFormat,Samples);
  693.            tfSample     : Result := Samples;
  694.       end;
  695.       if (FMaxRecTime > 0) and (Result >= FMaxRecTime) then
  696.           Result := FMaxRecTime;
  697.    end;
  698. end;
  699. {-- TMMCustomWaveIn -----------------------------------------------------------}
  700. function TMMCustomWaveIn.GetPosition: MM_int64;
  701. {$IFNDEF DELPHI4}
  702. var
  703.    Temp: TLargeInteger;
  704. {$ENDIF}
  705. begin
  706.    {$IFDEF DELPHI4}
  707.    Result := GetInternalPosition;
  708.    {$ELSE}
  709.    Temp.QuadPart := GetInternalPosition;
  710.    Result := Temp.LowPart;
  711.    {$ENDIF}
  712. end;
  713. {-- TMMCustomWaveIn -----------------------------------------------------------}
  714. function TMMCustomWaveIn.GetPositionHigh: Cardinal;
  715. {$IFNDEF DELPHI4}
  716. var
  717.    Temp: TLargeInteger;
  718. {$ENDIF}
  719. begin
  720.    {$IFDEF DELPHI4}
  721.    Result := (GetInternalPosition shr 32);
  722.    {$ELSE}
  723.    Temp.QuadPart := GetInternalPosition;
  724.    Result := Temp.HighPart;
  725.    {$ENDIF}
  726. end;
  727. {-- TMMCustomWaveIn -----------------------------------------------------------}
  728. function TMMCustomWaveIn.GetPosition64: int64;
  729. begin
  730.    Result := GetInternalPosition;
  731. end;
  732. {-- TMMCustomWaveIn ------------------------------------------------------------}
  733. Procedure TMMCustomWaveIn.SetCallBackMode(aValue: TMMCBMode);
  734. begin
  735.    if (wisOpen in FState) then
  736.        Error(LoadResStr(IDS_PROPERTYOPEN));
  737.    if (aValue <> FCallBackMode) then
  738.    begin
  739.       if (aValue = cmCallBack) then
  740.       begin
  741.          {$IFDEF WIN32}
  742.          if not _Win95_ then
  743.          {$ENDIF}
  744.          begin
  745.             Application.MessageBox('"CallBacks" are called at interrupt time !'#10#13+
  746.                                    'This is currently only supported under Windows 95',
  747.                                    'TMMWaveIn', MB_OK);
  748.             exit;
  749.          end;
  750.       end;
  751.       FCallBackMode := aValue;
  752.    end;
  753.    {$IFDEF WIN32}
  754.    {$IFDEF TRIAL}
  755.    {$DEFINE _HACK3}
  756.    {$I MMHACK.INC}
  757.    {$ENDIF}
  758.    {$ENDIF}
  759. end;
  760. {-- TMMCustomWaveIn ------------------------------------------------------------}
  761. function TMMCustomWaveIn.GetCallBackMode: TMMCBMode;
  762. begin
  763.    Result := FCallbackMode;
  764. end;
  765. {-- TMMCustomWaveIn ------------------------------------------------------------}
  766. Procedure TMMCustomWaveIn.SetPWaveFormat(aValue: PWaveFormatEx);
  767. begin
  768.    { stop and close the device }
  769.    Close;
  770.    if (aValue <> nil) then
  771.    begin
  772.       if pcmIsValidFormat(aValue) then
  773.       begin
  774.          SampleRate := aValue^.nSamplesPerSec;
  775.          BitLength := TMMBits(aValue^.wBitsPerSample div 8 - 1);
  776.          Mode := TMMMode(aValue^.nChannels-1);
  777.       end;
  778.    end;
  779.    inherited SetPWaveFormat(aValue);
  780. end;
  781. {-- TMMCustomWaveIn ------------------------------------------------------------}
  782. procedure TMMCustomWaveIn.SetWaveParams;
  783. begin
  784.    pcmBuildWaveHeader(@FWaveFormat,(Ord(FBits)+1)*8,Ord(FMode)+1,FRate);
  785.    PWaveFormat := @FWaveFormat;
  786. end;
  787. {-- TMMCustomWaveIn ------------------------------------------------------------}
  788. Procedure TMMCustomWaveIn.SetMode(aValue: TMMMode);
  789. begin
  790.    if (FMode <> aValue) and (aValue in [mMono,mStereo]) then
  791.    begin
  792.       if (wisOpen in FState) then
  793.           Error(LoadResStr(IDS_PROPERTYOPEN));
  794.       FMode := aValue;
  795.       SetWaveParams;
  796.    end;
  797. end;
  798. {-- TMMCustomWaveIn ------------------------------------------------------------}
  799. Procedure TMMCustomWaveIn.SetSampleRate(aValue: Longint);
  800. begin
  801.    if (FRate <> aValue) then
  802.    begin
  803.       if (wisOpen in FState) then
  804.          Error(LoadResStr(IDS_PROPERTYOPEN));
  805.       FRate := MinMax(aValue,8000,100000);
  806.       SetWaveParams;
  807.    end;
  808. end;
  809. {-- TMMCustomWaveIn ------------------------------------------------------------}
  810. Procedure TMMCustomWaveIn.SetBits(aValue: TMMBits);
  811. begin
  812.    if (FBits <> aValue) then
  813.    begin
  814.       if (wisOpen in FState) then
  815.          Error(LoadResStr(IDS_PROPERTYOPEN));
  816.       FBits := aValue;
  817.       SetWaveParams;
  818.    end;
  819. end;
  820. {-- TMMCustomWaveIn ------------------------------------------------------------}
  821. Procedure TMMCustomWaveIn.SetNumBuffers(aValue: integer);
  822. begin
  823.    if (aValue <> FNumBuffers) AND (aValue > 1) then
  824.    begin
  825.       if (wisOpen in FState) then
  826.           Error(LoadResStr(IDS_PROPERTYOPEN));
  827.       FNumBuffers := Min(aValue,MAXINBUFFERS);
  828.    end;
  829.    {$IFDEF WIN32}
  830.    {$IFDEF TRIAL}
  831.    {$DEFINE _HACK1}
  832.    {$I MMHACK.INC}
  833.    {$ENDIF}
  834.    {$ENDIF}
  835. end;
  836. {-- TMMCustomWaveIn ------------------------------------------------------------}
  837. function TMMCustomWaveIn.GetNumBuffers: integer;
  838. begin
  839.    Result := FNumBuffers;
  840. end;
  841. {-- TMMCustomWaveIn ------------------------------------------------------------}
  842. Procedure TMMCustomWaveIn.SetBufferSize(aValue: Longint);
  843. begin
  844.    if (aValue <> inherited GetBufferSize) then
  845.    begin
  846.       if (wisOpen in FState) then
  847.           Error(LoadResStr(IDS_PROPERTYOPEN));
  848.       if assigned(FAllocator) then
  849.          FAllocator.Discard;
  850.       inherited SetBufferSize(Max(aValue,MINBUFFERSIZE));
  851.    end;
  852. end;
  853. {-- TMMCustomWaveIn ------------------------------------------------------------}
  854. function TMMCustomWaveIn.GetBufferSize: Longint;
  855. begin
  856.    Result := inherited GetBufferSize;
  857. end;
  858. {-- TMMCustomWaveIn ------------------------------------------------------------}
  859. Procedure TMMCustomWaveIn.PrepareWaveHeaders;
  860. Var
  861.    i: integer;
  862. begin
  863.    { Prepare waveform headers for recording }
  864.    for i := 0 to FNumBuffers-1 do
  865.    begin
  866.       if FWaveInHdrs[i] <> Nil then
  867.       begin
  868.          FError := waveInPrepareHeader(FHWaveIn,
  869.                                        FWaveInHdrs[i],
  870.                                        sizeOf(TWaveHdr));
  871.          if FError <> 0 then
  872.             Error('WaveInPrepareHeader:'#10#13+WaveInErrorString(FError));
  873.       end;
  874.    end;
  875. end;
  876. {-- TMMCustomWaveIn ------------------------------------------------------------}
  877. Procedure TMMCustomWaveIn.UnPrepareWaveHeaders;
  878. Var
  879.    i: integer;
  880.    TimeOut: Longint;
  881. begin
  882.    {$IFDEF _MMDEBUG}
  883.    DebugStr(1,' ');
  884.    {$ENDIF}
  885.    for i := 0 to FNumBuffers-1 do
  886.    begin
  887.       if (FWaveInHdrs[i] <> Nil) then
  888.       begin
  889.          TimeOut := 65000;
  890.          { wait until the buffer is marked as done }
  891.          repeat
  892.              dec(TimeOut);
  893.          until (FWaveInHdrs[i]^.dwFlags and WHDR_DONE = WHDR_DONE) or (TimeOut = 0);
  894.          { mark buffer as done }
  895.          if (TimeOut = 0) then FWaveInHdrs[i]^.dwFlags := WHDR_DONE;
  896.          { unprepare buffer }
  897.          FError := WaveInUnprepareHeader(FHWaveIn,
  898.                                          FWaveInHdrs[i],
  899.                                          sizeOf(TWAVEHDR));
  900.          if FError <> 0 then
  901.             Error('WaveInUnprepareHeader:'#10#13+WaveInErrorString(FError));
  902.          {$IFDEF _MMDEBUG}
  903.          DebugStr(1,'UnprepareHeader '+IntToStr(i));
  904.          {$ENDIF}
  905.       end;
  906.    end;
  907.    {$IFDEF _MMDEBUG}
  908.    DebugStr(1,' ');
  909.    {$ENDIF}
  910. end;
  911. {-- TMMCustomWaveIn ------------------------------------------------------------}
  912. Procedure TMMCustomWaveIn.AddWaveHeader(lpWaveHdr: PWaveHdr);
  913. begin
  914.    { reset flags field (remove WHDR_DONE attribute) }
  915.    lpWaveHdr^.dwFlags := lpWaveHdr^.dwFlags and not WHDR_DONE or WHDR_PREPARED;
  916.    { queue the buffer for input... }
  917.    FError := WaveInAddBuffer(FHWaveIn,
  918.                              lpWaveHdr,
  919.                              sizeof(TWAVEHDR));
  920.    if FError <> 0 then
  921.       Error('WaveInAddBuffer:'#10#13+WaveInErrorString(FError));
  922.    inc(FBufferCounter);
  923.    {$IFDEF _MMDEBUG}
  924.    DebugStr(2,'Wave-Header '+IntToStr(lpWaveHdr^.dwUser)+' queued');
  925.    {$ENDIF}
  926. end;
  927. {$IFDEF WIN32}
  928. {-- TMMCustomWaveIn ------------------------------------------------------------}
  929. procedure TMMCustomWaveIn.SynchronizeVCL(VCLProc: TThreadMethod);
  930. begin
  931.    if (FCallBackMode = cmThread) and (FInEvent <> 0) then
  932.    begin
  933.       FInThread.Synchronize(VCLProc);
  934.    end
  935.    else VCLProc;
  936. end;
  937. {-- TMMCustomWaveIn ------------------------------------------------------------}
  938. procedure TMMCustomWaveIn.InitThread;
  939. begin
  940.    if (FCallBackMode = cmThread) then
  941.    begin
  942.       EnterCritical;
  943.       try
  944.          FThreadError := False;
  945.          { create event objects }
  946.          FInEvent   := CreateEvent(nil, False, False, nil);
  947.          FCloseEvent := CreateEvent(nil, False, False, nil);
  948.          { create the output thread }
  949.          FInThread := TMMWaveInThread.CreateSuspended(Self);
  950.          if (FInThread = nil) then
  951.              Error('WaveIn:'#10#13+LoadResStr(IDS_THREADERROR));
  952.          FInThread.FreeOnTerminate := True;
  953.          FInThread.Resume;
  954.          { Wait for it to start... }
  955.          if WaitForSingleObject(FInEvent, 5000) <> WAIT_OBJECT_0 then
  956.             Error('WaveIn:'#10#13+LoadResStr(IDS_THREADERROR));
  957.          {$IFDEF _MMDEBUG}
  958.          DebugStr(0,'Thread Started');
  959.          {$ENDIF}
  960.       finally
  961.         LeaveCritical;
  962.       end;
  963.    end;
  964. end;
  965. {-- TMMCustomWaveIn ------------------------------------------------------------}
  966. procedure TMMCustomWaveIn.DoneThread;
  967. begin
  968.    if (FCallBackMode = cmThread) and not FThreadError then
  969.    begin
  970.       { Force the output thread to close... }
  971.       SetEvent(FCloseEvent);
  972.       { ...and wait for it to die }
  973.       WaitForSingleObject(FInEvent, 5000);
  974.       { close all events and remove critical section }
  975.       CloseEvents;
  976.       {$IFDEF _MMDEBUG}
  977.       DebugStr(0,'Thread Terminated');
  978.       {$ENDIF}
  979.    end;
  980. end;
  981. {-- TMMCustomWaveIn ------------------------------------------------------------}
  982. procedure TMMCustomWaveIn.CloseEvents;
  983. begin
  984.    { release events }
  985.    CloseHandle(FInEvent);
  986.    CloseHandle(FCloseEvent);
  987.    { Free the critical section }
  988.    DoneCritical;
  989. end;
  990. {$ENDIF}
  991. {-- TMMCustomWaveIn ------------------------------------------------------------}
  992. procedure TMMCustomWaveIn.InitCritical;
  993. begin
  994.    {$IFDEF WIN32}
  995.    if (FCallBackMode <> cmWindow) then
  996.    begin
  997.       { create critical section object }
  998.       FillChar(DataSection, SizeOf(DataSection), 0);
  999.       InitializeCriticalSection(DataSection);
  1000.       DataSEctionOK := True;
  1001.    end;
  1002.    {$ENDIF}
  1003. end;
  1004. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1005. procedure TMMCustomWaveIn.EnterCritical;
  1006. begin
  1007.    {$IFDEF WIN32}
  1008.    if (FCallBackMode <> cmWindow) and DataSectionOK then
  1009.       EnterCriticalSection(DataSection);
  1010.    {$ENDIF}
  1011. end;
  1012. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1013. procedure TMMCustomWaveIn.LeaveCritical;
  1014. begin
  1015.    {$IFDEF WIN32}
  1016.    if (FCallBackMode <> cmWindow) and DataSectionOK then
  1017.       LeaveCriticalSection(DataSection);
  1018.    {$ENDIF}
  1019. end;
  1020. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1021. procedure TMMCustomWaveIn.DoneCritical;
  1022. begin
  1023.    {$IFDEF WIN32}
  1024.    if (FCallBackMode <> cmWindow) and DataSectionOK then
  1025.    begin
  1026.       DataSectionOK := False;
  1027.       DeleteCriticalSection(DataSection);
  1028.    end;
  1029.    {$ENDIF}
  1030. end;
  1031. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1032. Procedure TMMCustomWaveIn.Open;
  1033. var
  1034.    TimeOut: integer;
  1035.    aState: TMMWaveInState;
  1036. begin
  1037.    if (FNumDevs = 0) then
  1038.       Error(LoadResStr(IDS_WINODEVICE));
  1039.    if (FDeviceID = InvalidId) then
  1040.       Error(LoadResStr(IDS_INVALIDDEVICEID));
  1041.    if (PWaveFormat = nil) then
  1042.       Error(LoadResStr(IDS_NOFORMAT));
  1043.    if (wisOpen in FState) then Close;
  1044.    if (Not(wisOpen in FState)) and not FClosing then
  1045.    begin
  1046.       TimeOut := 100;
  1047.       FClosing := False;
  1048.       FReseting := False;
  1049.       FStopping := False;
  1050.       FPosted := False;
  1051.       try
  1052.          if not QueryDevice(FDeviceID, PWaveFormat) then
  1053.             Error('WaveInOpen:'#10#13+LoadResStr(IDS_CANTRECORD));
  1054.          { Create the window for callback notification }
  1055.          if (FHandle = 0) then FHandle := AllocateHwnd(WaveInHandler);
  1056.          FHWaveIn := 0;
  1057.          FCloseIt := False;
  1058.          {$IFDEF _MMDEBUG}
  1059.          DebugStr(0,'Try to open device...');
  1060.          {$ENDIF}
  1061.          { some fullduplex drivers require that WaveIn is opened before WaveOut  }
  1062.          { so we open the WaveIn device first and then open all other components }
  1063.          { create critical section object }
  1064.          InitCritical;
  1065.          {$IFDEF WIN32}
  1066.          if (FCallBackMode = cmThread) then InitThread;
  1067.          {$ENDIF}
  1068.          { now open Wave input device. }
  1069.          if _Win9x_ or _WinNT4_ then
  1070.          begin
  1071.             FError := WaveInOpen(@FHWaveIn,
  1072.                                  FDeviceId,
  1073.                                  Pointer(PWaveFormat),
  1074.                                  Longint(@WaveInFunc),
  1075.                                  Longint(Self),
  1076.                                  CALLBACK_FUNCTION);
  1077.          end
  1078.          else
  1079.          begin
  1080.             FError := WaveInOpen(@FHWaveIn,
  1081.                                  FDeviceId,
  1082.                                  Pointer(PWaveFormat),
  1083.                                  FHandle,
  1084.                                  0,
  1085.                                  CALLBACK_WINDOW);
  1086.          end;
  1087.          if (FError <> 0) then
  1088.          begin
  1089.             Error('WaveInOpen:'#10#13+WaveInErrorString(FError));
  1090.          end;
  1091.          aState := FState;
  1092.          FState := [wisClose];
  1093.          inherited Opened;
  1094.          FState := aState;
  1095.          { wait until the device returns its status }
  1096.          repeat
  1097.              if _Win9x_ or _WinNT4_ then
  1098.                 Delay(10,False)
  1099.              else
  1100.                 Delay(10,True);
  1101.              dec(TimeOut);
  1102.          until (wisOpen in FState) or (TimeOut <= 0);
  1103.          if (TimeOut <= 0) then
  1104.      Error('WaveInOpen:'#10#13+LoadResStr(IDS_CANTOPENDEVICE));
  1105.          { create the waveIn headers and buffers }
  1106.          AllocWaveHeaders;
  1107.          { Prepare waveform headers for recording }
  1108.          PrepareWaveHeaders;
  1109.          Opened;
  1110.       except
  1111.          if assigned(FOnError) then FOnError(Self);
  1112.          FState := [wisOpen];
  1113.          Close;
  1114.          FState := [wisClose];
  1115.          raise;
  1116.       end;
  1117.    end;
  1118. end;
  1119. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1120. Procedure TMMCustomWaveIn.Close;
  1121. var
  1122.    TimeOut: integer;
  1123. begin
  1124.    if (wisOpen in FState) and (not FClosing or FCloseIt) then
  1125.    try
  1126.       FClosing := True;
  1127.       { stop recording }
  1128.       if (wisRecord in FState) OR (wisPause in FState) then Stop;
  1129.       TimeOut := 100;
  1130.       { Close the device (finally!) }
  1131.       if FStopIt then FCloseIt := True
  1132.       else
  1133.       begin
  1134.          FCloseIt := False;
  1135.          if (FHWaveIn <> 0) then
  1136.          begin
  1137.             WaveInStop(FHWaveIn);
  1138.             WaveInReset(FHWaveIn);
  1139.             { unprepare wave headers }
  1140.             UnPrepareWaveHeaders;
  1141.             {$IFDEF _MMDEBUG}
  1142.             if (FInHandler > 0) then
  1143.                DebugStr(0,'Try to close device (while in Handler)...')
  1144.             else
  1145.                DebugStr(0,'Try to close device...');
  1146.             {$ENDIF}
  1147.             FError := WaveInClose(FHWaveIn);
  1148.             if FError <> 0 then
  1149.                Error('WaveInClose:'#10#13+WaveInErrorString(FError));
  1150.             {$IFDEF _MMDEBUG}
  1151.             DebugStr(0,'Waiting for state...');
  1152.             {$ENDIF}
  1153.             { wait until the device returns its status }
  1154.             repeat
  1155.                if _Win9x_ or _WinNT4_ then
  1156.                   Delay(10,False)
  1157.                else
  1158.                   Delay(10,True);
  1159.                dec(TimeOut);
  1160.             until (wisClose in FState) or (TimeOut <= 0);
  1161.             FWrapArrounds   := 0;
  1162.             FWrapSize       := 0;
  1163.          end
  1164.          else
  1165.          begin
  1166.             FState := [wisClose];
  1167.          end;
  1168.          { now notify all other components }
  1169.          inherited Closed;
  1170.          {$IFDEF WIN32}
  1171.          if (FCallBackMode = cmThread) then
  1172.              DoneThread
  1173.          else
  1174.              DoneCritical;
  1175.          {$ENDIF}
  1176.          Closed;
  1177.           if (TimeOut <= 0) then
  1178.             Error('WaveInOpen:'#10#13+LoadResStr(IDS_CANTCLOSEDEVICE));
  1179.       end;
  1180.    except
  1181.       FClosing := False;
  1182.    end;
  1183. end;
  1184. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1185. Procedure TMMCustomWaveIn.Start;
  1186. Var
  1187.    i: integer;
  1188. begin
  1189.    try
  1190.       if not (wisOpen in FState) then Open;
  1191.       if (wisOpen in FState) and (not (wisRecord in FState)) then
  1192.       begin
  1193.          { reset the total bytes recorded counter }
  1194.          FBytesRecorded := 0;
  1195.          FBufferIndex := 0;
  1196.          FInHandler := 0;
  1197.          FStopIt := False;
  1198.          FStopping := False;
  1199.          FReseting := False;
  1200.          FPosted := False;
  1201.          FBufferCounter := 0;
  1202.          FLastPosition := 0;
  1203.          FWrapArrounds := 0;
  1204.          FWrapSize := 0;
  1205.          CalcMaxRecBytes;
  1206.          { To start recording, send the buffers to driver }
  1207.          for i := 0 to FNumBuffers-1 do
  1208.          begin
  1209.             {$IFDEF NUMERATE}
  1210.             FWaveInHdrs[i]^.dwUser := i;
  1211.             {$ENDIF}
  1212.             AddWaveHeader(FWaveInHdrs[i]);
  1213.          end;
  1214.          Started;
  1215.       end;
  1216.    except
  1217.       if assigned(FOnError) then FOnError(Self);
  1218.       FState := FState + [wisRecord];
  1219.       Close;
  1220.       FState := [wisClose];
  1221.       raise;
  1222.    end;
  1223. end;
  1224. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1225. Procedure TMMCustomWaveIn.Pause;
  1226. begin
  1227.    try
  1228.       if not (wisOpen in FState) then Open;
  1229.       if (wisOpen in FState) and (not (wisPause in FState)) then
  1230.       begin
  1231.          if (wisRecord in FState) then
  1232.          begin
  1233.             {$IFDEF _MMDEBUG}
  1234.             DebugStr(0,'Try to pause device...');
  1235.             {$ENDIF}
  1236.             FError := WaveInStop(FHWaveIn);
  1237.             if FError <> 0 then
  1238.                Error('WaveInPause:'#10#13+WaveInErrorString(FError));
  1239.          end;
  1240.          Paused;
  1241.       end;
  1242.    except
  1243.       if assigned(FOnError) then FOnError(Self);
  1244.       Close;
  1245.       raise;
  1246.    end;
  1247. end;
  1248. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1249. Procedure TMMCustomWaveIn.Restart;
  1250. begin
  1251.    try
  1252.       if (wisRecord in FState) and (wisPause in FState) then
  1253.       begin
  1254.          {$IFDEF _MMDEBUG}
  1255.          DebugStr(0,'Try to restart device...');
  1256.          {$ENDIF}
  1257.          FError := WaveInStart(FHWaveIn);
  1258.          if FError <> 0 then
  1259.             Error('WaveInRestart:'#10#13+WaveInErrorString(FError));
  1260.          Restarted;
  1261.       end;
  1262.    except
  1263.       if assigned(FOnError) then FOnError(Self);
  1264.       Close;
  1265.       raise;
  1266.    end;
  1267. end;
  1268. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1269. procedure TMMCustomWaveIn.Stop;
  1270. var
  1271.    TimeOut: Longint;
  1272. begin
  1273.    if (wisRecord in FState) or (wisPause in FState) then
  1274.    begin
  1275.       try
  1276.          EnterCritical;
  1277.          try
  1278.             FStopping := True;
  1279.             {$IFDEF _MMDEBUG}
  1280.             if (FInHandler > 0) then
  1281.                DebugStr(0,'Try to stop device (while in Handler)...')
  1282.             else
  1283.                DebugStr(0,'Try to stop device...');
  1284.             {$ENDIF}
  1285.             FError := WaveInStop(FHWaveIn);
  1286.             if FError <> 0 then
  1287.                Error('WaveInStop:'#10#13+WaveInErrorString(FError));
  1288.             {$IFDEF _MMDEBUG}
  1289.             DebugStr(0,'WaveInStop Done...');
  1290.             {$ENDIF}
  1291.             FWrapArrounds := 0;
  1292.             FWrapSize     := 0;
  1293.             FReseting := True;
  1294.             FError := WaveInReset(FHWaveIn);
  1295.             if FError <> 0 then
  1296.                Error('WaveInReset:'#10#13+WaveInErrorString(FError));
  1297.             {$IFDEF _MMDEBUG}
  1298.             DebugStr(0,'WaveInReset Done...');
  1299.             {$ENDIF}
  1300.          finally
  1301.             LeaveCritical;
  1302.          end;
  1303.          if (FInHandler = 0) then
  1304.          begin
  1305.             TimeOut := 100;
  1306.             repeat
  1307.                if (FCallBackMode <> cmWindow) then
  1308.                    Delay(10,False)
  1309.                else
  1310.                    Delay(10,True);
  1311.                dec(TimeOut);
  1312.             until (FBufferCounter = 0) or (TimeOut <= 0);
  1313.          end;
  1314.          Stopped;
  1315.       except
  1316.          if assigned(FOnError) then FOnError(Self);
  1317.          Close;
  1318.          raise;
  1319.       end;
  1320.    end;
  1321. end;
  1322. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1323. procedure TMMCustomWaveIn.Opened;
  1324. begin
  1325.    {$IFDEF _MMDEBUG}
  1326.    DebugStr(0,'Device is now open...');
  1327.    {$ENDIF}
  1328.    if Assigned(FOnOpen) then FOnOpen(Self);
  1329. end;
  1330. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1331. procedure TMMCustomWaveIn.Closed;
  1332. begin
  1333.    FHWaveIn := 0;
  1334.    { free memory and remove }
  1335.    FreeWaveHeaders;
  1336.    {$IFDEF _MMDEBUG}
  1337.    DebugStr(0,'Device is now closed...');
  1338.    {$ENDIF}
  1339.    FClosing := False;
  1340.    if not (csDestroying in ComponentState) then
  1341.       if Assigned(FOnClose) then FOnClose(Self);
  1342. end;
  1343. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1344. procedure TMMCustomWaveIn.Started;
  1345. begin
  1346.    Include(FState, wisRecord);
  1347.    if not (wisPause in FState) then
  1348.    begin
  1349.       { start the buffers recording (unpause) }
  1350.       FError := WaveInStart(FHWaveIn);
  1351.       if FError <> 0 then
  1352.         Error('WaveInStart:'#10#13+WaveInErrorString(FError));
  1353.    end;
  1354.    { now notify all other components }
  1355.    inherited Started;
  1356.    {$IFDEF _MMDEBUG}
  1357.    DebugStr(0,'Device is now started...');
  1358.    {$ENDIF}
  1359.    InitDSPMeter;
  1360.    if assigned(FOnStart) then FOnStart(Self);
  1361. end;
  1362. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1363. procedure TMMCustomWaveIn.Paused;
  1364. begin
  1365.    Include(FState, wisPause);
  1366.    inherited Paused;
  1367.    {$IFDEF _MMDEBUG}
  1368.    DebugStr(0,'Device is now paused...');
  1369.    {$ENDIF}
  1370.    if assigned(FOnPause) then FOnPause(Self);
  1371. end;
  1372. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1373. procedure TMMCustomWaveIn.Restarted;
  1374. begin
  1375.    FState := FState - [wisPause];
  1376.    inherited Restarted;
  1377.    {$IFDEF _MMDEBUG}
  1378.    DebugStr(0,'Device is now restarted...');
  1379.    {$ENDIF}
  1380.    if assigned(FOnRestart) then FOnRestart(Self);
  1381. end;
  1382. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1383. procedure TMMCustomWaveIn.Stopped;
  1384. begin
  1385.    if (wisRecord in FState) or (wisPause in FState) then
  1386.    begin
  1387.       if (FInHandler > 0) then FStopIt := True
  1388.       else
  1389.       begin
  1390.          FState := FState - [wisRecord,wisPause];
  1391.          FBufferIndex := 0;
  1392.          FBufferCounter := 0;
  1393.          FStopIt := False;
  1394.          DoneDSPMeter;
  1395.          { notify all other components }
  1396.          inherited Stopped;
  1397.          {$IFDEF _MMDEBUG}
  1398.          DebugStr(0,'Device is now stopped...');
  1399.          {$ENDIF}
  1400.          if not (csDestroying in ComponentState) then
  1401.             if assigned(FOnStop) then FOnStop(Self);
  1402.          if FCloseIt then Close;
  1403.       end;
  1404.    end;
  1405. end;
  1406. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1407. procedure TMMCustomWaveIn.BufferReady(lpwh: PWaveHdr);
  1408. var
  1409.    bStopIt: Boolean;
  1410. begin
  1411.    StartDSPMeter;
  1412.    try
  1413.       { inc the bytes we have already recorded }
  1414.       inc(FBytesRecorded, lpwh^.dwBytesRecorded);
  1415.       if (FMaxRecTime > 0) and (FBytesRecorded >= FMaxRecBytes) then
  1416.       begin
  1417.          dec(lpwh^.dwBytesRecorded,FBytesRecorded-FMaxRecBytes);
  1418.          FBytesRecorded := FMaxRecBytes;
  1419.          bStopIt := True;
  1420.       end
  1421.       else bStopIt := False;
  1422.       inc(FBufferIndex);
  1423.       if FBufferIndex >= FNumBuffers then FBufferIndex := 0;
  1424.       inherited BufferReady(lpwh);
  1425.       if bStopIt then Stop;
  1426.    finally
  1427.       StopDSPMeter;
  1428.    end;
  1429. end;
  1430. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1431. procedure TMMCustomWaveIn.ProcessWaveHeader(lpWaveHdr: PWaveHdr);
  1432. var
  1433.    CurPos,LastPos: Cardinal;
  1434.    Wrapped: integer;
  1435. begin
  1436.    if (wisRecord in FState) then
  1437.    begin
  1438.       if FReseting or FStopping then
  1439.       begin
  1440.          { Buffer has returned from driver but should not queued again }
  1441.          {$IFDEF _MMDEBUG}
  1442.          DebugStr(2,'Buffer '+IntToStr(lpWaveHdr^.dwUser)+' returned while reseting');
  1443.          {$ENDIF}
  1444.          if not FReseting and (lpWaveHdr^.dwBytesRecorded > 0) then
  1445.             BufferReady(lpWaveHdr);
  1446.          EnterCritical;
  1447.          dec(FBufferCounter);
  1448.          if (FBufferCounter = 0) then FReseting := False;
  1449.          LeaveCritical;
  1450.          if not FStopIt then exit;
  1451.       end;
  1452.       inc(FInHandler);
  1453.       try
  1454.          {$IFDEF _MMDEBUG}
  1455.          DebugStr(2,'Buffer '+IntToStr(lpWaveHdr^.dwUser)+' returned');
  1456.          {$ENDIF}
  1457.          EnterCritical;
  1458.          dec(FBufferCounter);
  1459.          LeaveCritical;
  1460.          try
  1461.             BufferReady(lpWaveHdr);
  1462.             if not FStopIt then
  1463.             begin
  1464.                {$IFDEF WIN32}
  1465.                { wrap arround handling }
  1466.                CurPos := GetSamplePosition;
  1467.                if (CurPos > 0) then
  1468.                begin
  1469.                   LastPos:= FLastPosition;
  1470.                   asm
  1471.                      mov  Wrapped, False
  1472.                      mov  eax, CurPos
  1473.                      cmp  eax, LastPos
  1474.                      jnb  @@exit
  1475.                      mov  eax, LastPos
  1476.                      sub  eax, CurPos
  1477.                      cmp  eax, $FFFF
  1478.                      jb   @@exit
  1479.                      mov  Wrapped, True
  1480.                   @@exit:
  1481.                   end;
  1482.                   if (Wrapped = 1) then
  1483.                   begin
  1484.                      { every driver wraps at a different position           }
  1485.                      { here we try to detect where the position has wrapped }
  1486.                      { hey, this looks realy cool                           }
  1487.                      FWrapSize := (FLastPosition and $FFF00000) or $FFFFF;
  1488.                      inc(FWrapArrounds);
  1489.                   end;
  1490.                   FLastPosition := CurPos;
  1491.                end;
  1492.                {$ENDIF}
  1493.                { Refresh the wave input device with new buffer. }
  1494.                AddWaveHeader(lpWaveHdr);
  1495.             end;
  1496.          except
  1497.             if assigned(FOnError) then FOnError(Self);
  1498.             raise;
  1499.          end;
  1500.       finally
  1501.          dec(FInHandler);
  1502.          if (FInHandler = 0) and FStopIt and not FPosted then
  1503.          begin
  1504.             FPosted := True;
  1505.             FStopping := True;
  1506.             {$IFDEF _MMDEBUG}
  1507.             DebugStr(0,'Stop Message posted...');
  1508.             {$ENDIF}
  1509.             PostMessage(FHandle,MM_WIM_STOP,FHWaveIn,0);
  1510.          end;
  1511.       end;
  1512.    end;
  1513. end;
  1514. {-- TMMCustomWaveIn ------------------------------------------------------------}
  1515. procedure TMMCustomWaveIn.WaveInHandler(Var Msg: TMessage );
  1516. begin
  1517.   with Msg do
  1518.   try
  1519.      if wParam = FHWaveIn then
  1520.      case Msg of
  1521.        MM_WIM_OPEN :
  1522.        begin
  1523.           { device is now open }
  1524.           FState:= [wisOpen];
  1525.        end;
  1526.        MM_WIM_CLOSE:
  1527.        begin
  1528.           { device is now closed }
  1529.           FState:= [wisClose];
  1530.        end;
  1531.        MM_WIM_DATA:
  1532.        begin
  1533.           { buffer has been returned to app, so queue it.}
  1534.           ProcessWaveHeader(PWaveHdr(lparam));
  1535.           exit;
  1536.        end;
  1537.        MM_WIM_STOP:
  1538.        begin
  1539.           { should stop the device }
  1540.           {$IFDEF _MMDEBUG}
  1541.           DebugStr(0,'Stop message received...');
  1542.           {$ENDIF}
  1543.           Stop;
  1544.           exit;
  1545.        end;
  1546.      end;
  1547.      Result := DefWindowProc(FHandle, Msg, wParam, lParam);
  1548.   except
  1549.      Close;
  1550.      Application.HandleException(Self);
  1551.   end;
  1552. end;
  1553. {== TMMWaveIn =================================================================}
  1554. procedure TMMWaveIn.SetupWaveEngine;
  1555. begin
  1556.   @waveInGetNumDevs       := @MMSystem.waveInGetNumDevs;
  1557.   @waveInGetDevCaps       := @MMSystem.waveInGetDevCaps;
  1558.   @waveInGetErrorText     := @MMSystem.waveInGetErrorText;
  1559.   @waveInOpen             := @MMSystem.waveInOpen;
  1560.   @waveInClose            := @MMSystem.waveInClose;
  1561.   @waveInPrepareHeader    := @MMSystem.waveInPrepareHeader;
  1562.   @waveInUnprepareHeader  := @MMSystem.waveInUnprepareHeader;
  1563.   @waveInAddBuffer        := @MMSystem.waveInAddBuffer;
  1564.   @waveInStart            := @MMSystem.waveInStart;
  1565.   @waveInStop             := @MMSystem.waveInStop;
  1566.   @waveInReset            := @MMSystem.waveInReset;
  1567.   @waveInGetPosition      := @MMSystem.waveInGetPosition;
  1568.   @waveInGetID            := @MMSystem.waveInGetID;
  1569. end;
  1570. {-- WaveInFunc -----------------------------------------------------------}
  1571. procedure WaveInFunc(hWaveIn:HWaveIn;wMsg:UINT;dwInstance,dwParam1,dwParam2:Longint);
  1572. begin
  1573.    if (dwInstance <> 0) then
  1574.    with TMMCustomWaveIn(dwInstance) do
  1575.    {$IFDEF WIN32}
  1576.    try
  1577.    {$ELSE}
  1578.    begin
  1579.    {$ENDIF}
  1580.       case wMsg of
  1581.          WIM_OPEN :
  1582.          begin
  1583.             { device is now open }
  1584.             FState:= [wisOpen];
  1585.          end;
  1586.          WIM_CLOSE:
  1587.          begin
  1588.             { device is now closed }
  1589.             FState:= [wisClose];
  1590.          end;
  1591.          WIM_DATA :
  1592.          begin
  1593.             case FCallBackMode of
  1594.                   cmWindow: PostMessage(FHandle,MM_WIM_DATA,hWaveIn,dwParam1);
  1595.                 {$IFDEF WIN32}
  1596.                 cmCallBack: ProcessWaveHeader(PWaveHdr(dwparam1));
  1597.                   cmThread: PostThreadMessage(FInThread.ThreadID,MM_WIM_DATA,hWaveIn,dwParam1);
  1598.                 {$ENDIF}
  1599.             end;
  1600.          end;
  1601.       end;
  1602.    {$IFDEF WIN32}
  1603.    except
  1604.       Close;
  1605.       Application.HandleException(TMMCustomWaveIn(dwInstance));
  1606.    {$ENDIF}
  1607.    end;
  1608. end;
  1609. {$IFDEF WIN32}
  1610. {-------------------------------------------------------------------------}
  1611. procedure TMMWaveInThread.Execute;
  1612. {- Wait for and process input messages }
  1613. var
  1614.    Res       : DWORD;
  1615.    Msg       : TMsg;
  1616.    {$IFDEF _MMDEBUG}
  1617.    _Error    : Longint;
  1618.    {$ENDIF}
  1619. begin
  1620.    with TMMCustomWaveIn(Owner) do
  1621.    try
  1622.       SetPriority(FPriority);
  1623.       
  1624.       { make sure we have a message queue... }
  1625.       PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
  1626.       { Ready to go, set the input event }
  1627.       SetEvent(FInEvent);
  1628.       { Repeat until device is closed }
  1629.       while not Terminated do
  1630.       try
  1631.          if not PeekMessage(msg, 0, 0, 0, PM_REMOVE) then
  1632.          begin
  1633.             Res := MsgWaitForMultipleObjects(1, FCloseEvent, False,
  1634.                                              INFINITE, QS_ALLEVENTS);
  1635.             case Res of
  1636.                 WAIT_FAILED:       { Wait failed.  Shouldn't happen. }
  1637.                 begin
  1638.                    {$IFDEF _MMDEBUG}
  1639.                    _Error := GetLastError;
  1640.                    DebugStr(0,'Wait Failed... Error: '+SysErrorMessage(_Error));
  1641.                    {$ENDIF}
  1642.                    Continue;
  1643.                 end;
  1644.                 WAIT_OBJECT_0:     { CloseEvent signaled!            }
  1645.                 begin
  1646.                    { Finished here, okay to close device }
  1647.                    {$IFDEF _MMDEBUG}
  1648.                    DebugStr(0,'CloseEvent signaled...');
  1649.                    {$ENDIF}
  1650.                    exit;
  1651.                 end;
  1652.                 WAIT_OBJECT_0+1:    { New message was received.      }
  1653.                 begin
  1654.                    { Get the message that woke us up by looping again.}
  1655.                    {$IFDEF _MMDEBUG}
  1656.                    DebugStr(2,'WaveIn message reveived...');
  1657.                    {$ENDIF}
  1658.                    Continue;
  1659.                 end;
  1660.             end;
  1661.          end;
  1662.          { Process the message. }
  1663.          with msg do
  1664.          begin
  1665.             if (wParam = FHWaveIn) and (message = MM_WIM_DATA) then
  1666.             begin             { done playing queued wave buffer... }
  1667.                ProcessWaveHeader(PWaveHdr(lparam));
  1668.             end
  1669.             else
  1670.             begin
  1671.                {$IFDEF _MMDEBUG}
  1672.                DebugStr(0,'Unknown message received...');
  1673.                {$ENDIF}
  1674.                TranslateMessage(Msg);
  1675.                DispatchMessage(msg);
  1676.             end;
  1677.          end;
  1678.       except
  1679.          FThreadError := True;
  1680.          if (FHWaveIn <> 0) then
  1681.          begin
  1682.             FClosing := True;
  1683.             Stop;
  1684.             UnPrepareWaveHeaders;
  1685.             WaveInClose(FHWaveIn);
  1686.             Closed;
  1687.             CloseEvents;
  1688.          end;
  1689.          Application.HandleException(nil);
  1690.          exit;
  1691.       end;
  1692.    finally
  1693.      SetEvent(FInEvent);
  1694.      {$IFDEF _MMDEBUG}
  1695.      DebugStr(0,'Exit Thread-Proc');
  1696.      {$ENDIF}
  1697.    end;
  1698. end;
  1699. {$ENDIF}
  1700. procedure InitWaveInDevices;
  1701. var
  1702.    i: integer;
  1703.    Name: string;
  1704.    function CheckDevice(DeviceID: integer; var Name: string): Boolean;
  1705.    var
  1706.       Res: integer;
  1707.       Caps: TWAVEINCAPS;
  1708.    begin
  1709.       Result := False;
  1710.       Name   := '';
  1711.       Res := WaveInGetDevCaps(i,@Caps,sizeof(Caps));
  1712.       if (Res = 0) then
  1713.       begin
  1714.          Name := StrPas(Caps.szPname);
  1715.          Result := True;
  1716.       end;
  1717.    end;
  1718. begin
  1719.    Devices := TStringList.Create;
  1720.    for i := 0 to WaveInGetNumDevs-1 do
  1721.    begin
  1722.       if CheckDevice(i,Name) then
  1723.          Devices.AddObject(Name,Pointer(i));
  1724.    end;
  1725. end;
  1726. initialization
  1727.    InitWaveInDevices;
  1728. {$IFDEF _MMDEBUG}
  1729.    DB_Level(DEBUGLEVEL);
  1730. {$ENDIF}
  1731. finalization
  1732.    if (Devices <> nil) then
  1733.        Devices.Free;
  1734. end.