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

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: 05.09.98 - 22:49:29 $                                        =}
  24. {========================================================================}
  25. unit MMDevice;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29. {$IFDEF WIN32}
  30.     Windows,
  31. {$ELSE}
  32.     WinTypes,
  33.     WinProcs,
  34. {$ENDIF}
  35.     Classes,
  36.     SysUtils,
  37.     MMSystem,
  38.     MMObj,
  39.     MMObsrv,
  40.     MMUtils;
  41. type
  42.     { D3: This lines rely on current Win32 API}
  43.     TMMAudioDeviceType = (dtMidiIn,dtMidiOut,dtWaveIn,dtWaveOut,dtAux,dtMixer);
  44. {$IFDEF WIN32}
  45.     TMMManufacturerId  = WORD;
  46.     TMMProductId       = WORD;
  47.     TMMVersion         = Byte;
  48. {$ENDIF}
  49. const
  50.     defAudioDeviceType  = dtWaveOut;
  51.     defDeviceId         = 0;
  52.     { D3: This lines rely on current Win32 API}
  53. type
  54.     {-- TMMDeviceCaps ---------------------------------------------------}
  55.     TMMDeviceCaps       = class(TPersistent)
  56.     private
  57.       FManufacturerId: TMMManufacturerId;
  58.       FProductId     : TMMProductId;
  59.       FVerMajor      : TMMVersion;
  60.       FVerMinor      : TMMVersion;
  61.       FProductName   : string;
  62.       FWDummy        : Word;
  63.       FVDummy        : TMMVersion;
  64.       procedure SetDummyStr(const Value: string);
  65.     public
  66.       procedure Clear;
  67.     published
  68.       property ManufacturerId: TMMManufacturerId read FManufacturerId write FWDummy stored False;
  69.       property ProductId     : TMMProductId read FProductId write FWDummy stored False;
  70.       property VerMajor      : TMMVersion read FVerMajor write FVDummy stored False;
  71.       property VerMinor      : TMMVersion read FVerMinor write FVDummy stored False;
  72.       property ProductName   : string read FProductName write SetDummyStr stored False;
  73.     end;
  74.     {-- TMMCustomAudioDevice ------------------------------------------------}
  75.     TMMCustomAudioDevice = class(TMMNonVisualComponent)
  76.     private
  77.       FActive    : Boolean;
  78.       FDeviceType: TMMAudioDeviceType;
  79.       FDeviceId  : TMMDeviceId;
  80.       FDeviceCaps: TMMDeviceCaps;
  81.       FObservable: TMMObservable;
  82.       FTempActive: Boolean;
  83.       FDummyInt  : Integer;
  84.       FDummyBool : Boolean;
  85.       FOnChange  : TNotifyEvent;
  86.       procedure SetDeviceType(Value: TMMAudioDeviceType);
  87.       procedure SetDeviceId(Value: TMMDeviceId);
  88.       function  GetDeviceCount: Integer;
  89.       function  GetDevices(index: integer): string;
  90.       procedure SetDeviceCaps(const Value: TMMDeviceCaps);
  91.       function  GetMixerId: TMMDeviceId;
  92.       function  GetDeviceCapsByID(AnID: TMMDeviceId): TMMDeviceCaps;
  93.     protected
  94.       procedure Open; virtual;
  95.       procedure Close; virtual;
  96.       procedure UpdateDevice; virtual;
  97.       procedure RetrieveDeviceCaps;
  98.       procedure SetActive(Value: Boolean);
  99.       function  GetActive: Boolean;
  100.       procedure Changed; virtual;
  101.       procedure DoChange; dynamic;
  102.       procedure Loaded; override;
  103.       { If descendant needs to immediately update device id w/o reopening }
  104.       procedure SetDeviceIdDirect(Value: TMMDeviceId);
  105.       function  GetMapper: Boolean;
  106.     public
  107.       constructor Create(AOwner: TComponent); override;
  108.       destructor Destroy; override;
  109.       procedure AddObserver(O: TMMObserver);
  110.       procedure RemoveObserver(O: TMMObserver);
  111.       function  ValidDevice: Boolean;
  112.       procedure GetDeviceList(List: TStrings; IncludeMapper: Boolean);
  113.       function  GetDeviceType: TMMAudioDeviceType;
  114.       { badDeviceId if no mixer for device }
  115.       property  MixerId: TMMDeviceId read GetMixerId;
  116.       property  Devices[index: integer]: string read GetDevices;
  117.     protected
  118.       property  DeviceType: TMMAudioDeviceType read FDeviceType write SetDeviceType default defAudioDeviceType;
  119.       {$IFDEF BUILD_ACTIVEX} public {$ELSE} protected {$ENDIF}
  120.       property  DeviceCapsByID[AnID: TMMDeviceId]: TMMDeviceCaps read GetDeviceCapsById;
  121.     published
  122.       property  DeviceCount : Integer read GetDeviceCount write FDummyInt stored False;
  123.       property  DeviceCaps  : TMMDeviceCaps read FDeviceCaps write SetDeviceCaps stored False;
  124.       property  Mapper      : Boolean read GetMapper write FDummyBool stored False;
  125.       property  Active      : Boolean read GetActive write SetActive default False;
  126.       property  DeviceId    : TMMDeviceId read FDeviceId write SetDeviceId;
  127.       property  OnChange    : TNotifyEvent read FOnChange write FOnChange;
  128.     end;
  129.     {-- TMMDeviceChange -------------------------------------------------}
  130.     TMMDeviceChange = class(TObject)
  131.     end;
  132.     {-- TMMAudioDevice --------------------------------------------------}
  133.     TMMAudioDevice = class(TMMCustomAudioDevice)
  134.     published
  135.       property DeviceType;
  136.     end;
  137.     {-- EMMMCIError ---------------------------------------------------------}
  138.     EMMMCIError = class(Exception)
  139.     private
  140.         FResult : MMResult;
  141.     public
  142.       constructor CreateRes(Res: MMResult);
  143.       property Result: MMResult read FResult;
  144.     end;
  145.     {-- EMMDeviceError ------------------------------------------------------}
  146.     EMMDeviceError = class(Exception)
  147.     end;
  148. function Check(MMRes: MMResult): MMResult;
  149. function CheckExcl(MMRes: MMResult; const Excl: array of MMResult): MMResult;
  150. {========================================================================}
  151. implementation
  152. {========================================================================}
  153. {------------------------------------------------------------------------}
  154. function Check(MMRes: MMResult): MMResult;
  155. begin
  156.    Result:= MMRes;
  157.    if (MMRes <> MMSYSERR_NOERROR) then
  158.       raise EMMMCIError.CreateRes(MMRes);
  159. end;
  160. {------------------------------------------------------------------------}
  161. function CheckExcl(MMRes: MMResult; const Excl: array of MMResult): MMResult;
  162. var
  163.     i: Integer;
  164. begin
  165.     Result:= MMRes;
  166.     for i:= Low(Excl) to High(Excl) do
  167.         if MMRes = Excl[i] then
  168.            Exit;
  169.     Result:= Check(MMRes);
  170. end;
  171. {$IFDEF WIN32}
  172. type
  173.     { D3: This code rely on current Win32 API }
  174.     TGenericCaps = packed record
  175.        wMid           : WORD;
  176.        wPid           : WORD;
  177.        vDriverVersion : MMVERSION;
  178.        szPname        : array[0..MAXPNAMELEN] of char;
  179.     end;
  180. {$ENDIF}
  181. {------------------------------------------------------------------------}
  182. function GetGenericCaps(DevType: TMMAudioDeviceType; DevId: TMMDeviceId): TGenericCaps;
  183. begin
  184.     { D3: This lines rely on current Win32 API}
  185.     { Can't use array because param list of following function contains
  186.       pointers to structures and can't be casted to Pointer }
  187.     case DevType of
  188.       dtMidiIn : Check(midiInGetDevCaps(DevId, @Result, SizeOf(Result)));
  189.       dtMidiOut: Check(midiOutGetDevCaps(DevId, @Result, SizeOf(Result)));
  190.       dtWaveIn : Check(waveInGetDevCaps(DevId, @Result, SizeOf(Result)));
  191.       dtWaveOut: Check(waveOutGetDevCaps(DevId, @Result, SizeOf(Result)));
  192.       dtAux    : Check(auxGetDevCaps(DevId, @Result, SizeOf(Result)));
  193.       dtMixer  : Check(mixerGetDevCaps(DevId, @Result, SizeOf(Result)));
  194.     end;
  195. end;
  196. {------------------------------------------------------------------------}
  197. function HasMapper(DevType: TMMAudioDeviceType): Boolean;
  198. var
  199.    i: integer;
  200.    Temp: TGenericCaps;
  201. begin
  202.     { D3: This lines rely on current Win32 API}
  203.     { Can't use array because param list of following function contains
  204.       pointers to structures and can't be casted to Pointer }
  205.     i := -1;
  206.     case DevType of
  207.       dtMidiIn : Result := CheckExcl(midiInGetDevCaps(i, @Temp, SizeOf(Temp)),[MMSYSERR_BADDEVICEID,MMSYSERR_INVALHANDLE]) = MMSYSERR_NOERROR;
  208.       dtMidiOut: Result := CheckExcl(midiOutGetDevCaps(i, @Temp, SizeOf(Temp)),[MMSYSERR_BADDEVICEID,MMSYSERR_INVALHANDLE]) = MMSYSERR_NOERROR;
  209.       dtWaveIn : Result := CheckExcl(waveInGetDevCaps(i, @Temp, SizeOf(Temp)),[MMSYSERR_BADDEVICEID,MMSYSERR_INVALHANDLE]) = MMSYSERR_NOERROR;
  210.       dtWaveOut: Result := CheckExcl(waveOutGetDevCaps(i, @Temp, SizeOf(Temp)),[MMSYSERR_BADDEVICEID,MMSYSERR_INVALHANDLE]) = MMSYSERR_NOERROR;
  211.       dtAux    : Result := CheckExcl(auxGetDevCaps(i, @Temp, SizeOf(Temp)),[MMSYSERR_BADDEVICEID,MMSYSERR_INVALHANDLE]) = MMSYSERR_NOERROR;
  212.       dtMixer  : Result := CheckExcl(mixerGetDevCaps(i, @Temp, SizeOf(Temp)),[MMSYSERR_BADDEVICEID,MMSYSERR_INVALHANDLE]) = MMSYSERR_NOERROR;
  213.     else
  214.       Result := False;
  215.     end;
  216. end;
  217. {== TMMCustomAudioDevice ================================================}
  218. procedure TMMDeviceCaps.SetDummyStr(const Value: string);
  219. begin
  220.   ;
  221. end;
  222. {-- TMMDeviceCaps -------------------------------------------------------}
  223. procedure TMMDeviceCaps.Clear;
  224. begin
  225.    FManufacturerId:= 0;
  226.    FProductId     := 0;
  227.    FVerMajor      := 0;
  228.    FVerMinor      := 0;
  229.    FProductName   := '';
  230. end;
  231. {== TMMCustomAudioDevice ================================================}
  232. constructor TMMCustomAudioDevice.Create(AOwner: TComponent);
  233. begin
  234.    inherited Create(AOwner);
  235.    FObservable:= TMMObservable.Create;
  236.    FDeviceType:= defAudioDeviceType;
  237.    FDeviceCaps:= TMMDeviceCaps.Create;
  238.    try
  239.       FDeviceId  := defDeviceId;
  240.       RetrieveDeviceCaps;
  241.    except
  242.       FDeviceId  := InvalidId;
  243.       RetrieveDeviceCaps;
  244.    end;
  245.    ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
  246.    if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
  247. end;
  248. {-- TMMCustomAudioDevice ------------------------------------------------}
  249. destructor TMMCustomAudioDevice.Destroy;
  250. begin
  251.    Close;
  252.    FDeviceCaps.Free;
  253.    FObservable.Free;
  254.    FObservable:= nil;
  255.    inherited Destroy;
  256. end;
  257. {-- TMMCustomAudioDevice ------------------------------------------------}
  258. procedure TMMCustomAudioDevice.AddObserver(O: TMMObserver);
  259. begin
  260.    FObservable.AddObserver(O);
  261. end;
  262. {-- TMMCustomAudioDevice ------------------------------------------------}
  263. procedure TMMCustomAudioDevice.RemoveObserver(O: TMMObserver);
  264. begin
  265.    if (FObservable <> nil) then
  266.       FObservable.RemoveObserver(O);
  267. end;
  268. {-- TMMCustomAudioDevice ------------------------------------------------}
  269. function TMMCustomAudioDevice.ValidDevice: Boolean;
  270. begin
  271.    Result:= (DeviceCount > 0) and (DeviceId <> InvalidId);
  272. end;
  273. {-- TMMCustomAudioDevice ------------------------------------------------}
  274. procedure TMMCustomAudioDevice.SetDeviceType(Value: TMMAudioDeviceType);
  275. begin
  276.    if (Value <> FDeviceType) then
  277.    begin
  278.       Close;
  279.       FDeviceType:= Value;
  280.       FDeviceId  := defDeviceID;
  281.       UpdateDevice;
  282.    end;
  283. end;
  284. {-- TMMCustomAudioDevice ------------------------------------------------}
  285. procedure TMMCustomAudioDevice.SetDeviceId(Value: TMMDeviceId);
  286. var
  287.    wasActive: Boolean;
  288. begin
  289.    if (Value <> 0) and (Value <> InvalidId) and (Value <> MapperId) and
  290.       not InRange(Value, 0, DeviceCount - 1) then
  291.         { TODO: Should be resource id }
  292.       raise EMMDeviceError.Create('Device id is out of range');
  293.    if (Value <> FDeviceId) then
  294.    begin
  295.       wasActive:= Active;
  296.       Close;
  297.       FDeviceId:= Value;
  298.       UpdateDevice;
  299.       if wasActive then Active := True;
  300.    end;
  301. end;
  302. {-- TMMCustomAudioDevice ------------------------------------------------}
  303. function TMMCustomAudioDevice.GetDeviceCount: Integer;
  304. type
  305.     TGetNumProc = function: UINT; stdcall;
  306. const
  307.     GetNums: array[TMMAudioDeviceType] of TGetNumProc = (midiInGetNumDevs,
  308.                                                          midiOutGetNumDevs,
  309.                                                          waveInGetNumDevs,
  310.                                                          waveOutGetNumDevs,
  311.                                                          auxGetNumDevs,
  312.                                                          mixerGetNumDevs);
  313. begin
  314.    Result:= GetNums[FDeviceType];
  315. end;
  316. {-- TMMCustomAudioDevice ------------------------------------------------}
  317. function TMMCustomAudioDevice.GetDevices(index: integer): string;
  318. begin
  319.    if (index < DeviceCount) then
  320.        Result := GetGenericCaps(FDeviceType,index).szPName
  321.    else
  322.        Result := '';
  323. end;
  324. {-- TMMCustomAudioDevice ------------------------------------------------}
  325. procedure TMMCustomAudioDevice.Open;
  326. begin
  327.    FActive := True;
  328. end;
  329. {-- TMMCustomAudioDevice ------------------------------------------------}
  330. procedure TMMCustomAudioDevice.Close;
  331. begin
  332.    FActive := False;
  333. end;
  334. {-- TMMCustomAudioDevice ------------------------------------------------}
  335. procedure TMMCustomAudioDevice.SetActive(Value: Boolean);
  336. begin
  337.    if csLoading in ComponentState then
  338.    begin
  339.       FTempActive:= Value;
  340.       Exit;
  341.    end;
  342.    if (FActive <> Value) then
  343.    begin
  344.       if Value then
  345.       begin
  346.          Close;
  347.          Open;
  348.       end
  349.       else Close;
  350.    end;
  351. end;
  352. {-- TMMCustomAudioDevice ------------------------------------------------}
  353. function TMMCustomAudioDevice.GetActive: Boolean;
  354. begin
  355.     if csLoading in ComponentState then
  356.         Result:= FTempActive
  357.     else
  358.         Result:= FActive;
  359. end;
  360. {-- TMMCustomAudioDevice ------------------------------------------------}
  361. procedure TMMCustomAudioDevice.Loaded;
  362. begin
  363.    inherited Loaded;
  364.    if (Active <> FTempActive) then
  365.       Active := FTempActive;
  366. end;
  367. {-- TMMCustomAudioDevice ------------------------------------------------}
  368. procedure TMMCustomAudioDevice.SetDeviceIdDirect(Value: TMMDeviceId);
  369. begin
  370.    FDeviceId:= Value;
  371. end;
  372. {-- TMMCustomAudioDevice ------------------------------------------------}
  373. procedure TMMCustomAudioDevice.SetDeviceCaps(const Value: TMMDeviceCaps);
  374. begin
  375.   ;
  376. end;
  377. {-- TMMCustomAudioDevice ------------------------------------------------}
  378. procedure TMMCustomAudioDevice.UpdateDevice;
  379. begin
  380.    RetrieveDeviceCaps;
  381.    Changed;
  382. end;
  383. {-- TMMCustomAudioDevice ------------------------------------------------}
  384. procedure TMMCustomAudioDevice.Changed;
  385. var
  386.    UpdChange: TMMDeviceChange;
  387. begin
  388.    UpdChange:= TMMDeviceChange.Create;
  389.    try
  390.       FObservable.NotifyObservers(UpdChange);
  391.    finally
  392.       UpdChange.Free;
  393.    end;
  394.    DoChange;
  395. end;
  396. {-- TMMCustomAudioDevice ------------------------------------------------}
  397. procedure TMMCustomAudioDevice.RetrieveDeviceCaps;
  398. var
  399.    Caps: TGenericCaps;
  400. begin
  401.    with FDeviceCaps do
  402.    if not ValidDevice then Clear
  403.    else
  404.    begin
  405.       Caps           := GetGenericCaps(FDeviceType,FDeviceId);
  406.       FManufacturerId:= Caps.wMid;
  407.       FProductId     := Caps.wPid;
  408.       FVerMajor      := Hi(Caps.vDriverVersion);
  409.       FVerMinor      := Lo(Caps.vDriverVersion);
  410.       FProductName   := StrPas(Caps.szPName);
  411.    end;
  412. end;
  413. {-- TMMCustomAudioDevice ------------------------------------------------}
  414. function TMMCustomAudioDevice.GetDeviceCapsByID(AnID: TMMDeviceId): TMMDeviceCaps;
  415. var
  416.   Caps: TGenericCaps;
  417. begin
  418.   try
  419.     Caps := GetGenericCaps(FDeviceType, AnId);
  420.     Result := TMMDeviceCaps.Create;
  421.     with Result do
  422.     begin
  423.       FManufacturerId := Caps.wMid;
  424.       FProductId := Caps.wPid;
  425.       FVerMajor := Hi(Caps.vDriverVersion);
  426.       FVerMinor := Lo(Caps.vDriverVersion);
  427.       FProductName := StrPas(Caps.szPName);
  428.     end;
  429.   except
  430.     Result := nil;
  431.   end;
  432. end;
  433. {-- TMMCustomAudioDevice ------------------------------------------------}
  434. procedure TMMCustomAudioDevice.GetDeviceList(List: TStrings; IncludeMapper: Boolean);
  435. var
  436.     i: Integer;
  437. begin
  438.    List.Clear;
  439.    if IncludeMapper and Mapper then
  440.       List.Add(GetGenericCaps(FDeviceType,-1).szPName);
  441.    for i:= 0 to DeviceCount - 1 do
  442.        List.Add(GetGenericCaps(FDeviceType,i).szPName);
  443. end;
  444. {-- TMMCustomAudioDevice ------------------------------------------------}
  445. function TMMCustomAudioDevice.GetDeviceType: TMMAudioDeviceType;
  446. begin
  447.    Result:= DeviceType;
  448. end;
  449. {-- TMMCustomAudioDevice ------------------------------------------------}
  450. procedure TMMCustomAudioDevice.DoChange;
  451. begin
  452.    if Assigned(FOnChange) then
  453.       FOnChange(Self);
  454. end;
  455. {-- TMMCustomAudioDevice ------------------------------------------------}
  456. function TMMCustomAudioDevice.GetMixerId: TMMDeviceId;
  457. const
  458.     MixerFlags: array[TMMAudioDeviceType] of DWORD = (MIXER_OBJECTF_MIDIIN,
  459.                                                       MIXER_OBJECTF_MIDIOUT,
  460.                                                       MIXER_OBJECTF_WAVEIN,
  461.                                                       MIXER_OBJECTF_WAVEOUT,
  462.                                                       MIXER_OBJECTF_AUX,
  463.                                                       MIXER_OBJECTF_MIXER);
  464. var
  465.     Res: DWORD;
  466. begin
  467.    CheckExcl(mixerGetId(DeviceId, Res, MixerFlags[DeviceType]),[MMSYSERR_NODRIVER]);
  468.    if integer(Res) = -1 then
  469.     Result := InvalidId
  470.    else
  471.     Result := Res;
  472. end;
  473. {-- TMMCustomAudioDevice ------------------------------------------------}
  474. function TMMCustomAudioDevice.GetMapper: Boolean;
  475. begin
  476.     Result := HasMapper(DeviceType);
  477. end;
  478. {== EMMMCIError =========================================================}
  479. constructor EMMMCIError.CreateRes(Res: MMResult);
  480. var
  481.    Buf: array[0..1023] of char;
  482. begin
  483.    FResult := Res;
  484.    if mciGetErrorString(Res, @Buf, SizeOf(Buf) - 1) then
  485.       inherited Create(StrPas(Buf))
  486.    else
  487.       inherited CreateFmt('MMSystem error: %d', [Res]);
  488. end;
  489. end.