Subversion Repositories spacemission

Rev

Rev 4 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit DXSounds;
  2.  
  3. interface
  4.  
  5. {$INCLUDE DelphiXcfg.inc}
  6.  
  7. uses
  8.   Windows, Messages, SysUtils, Classes, Controls, Forms, ExtCtrls, MMSystem,
  9.   DirectX, DXClass, Wave;
  10.  
  11. type
  12.  
  13.   {  EDirectSoundError  }
  14.  
  15.   EDirectSoundError = class(EDirectXError);
  16.   EDirectSoundBufferError = class(EDirectSoundError);
  17.  
  18.   {  TDirectSound  }
  19.  
  20.   TDirectSoundBuffer = class;
  21.  
  22.   TDirectSound = class(TDirectX)
  23.   private
  24.     FBufferList: TList;
  25.     FGlobalFocus: Boolean;
  26.     FIDSound: IDirectSound;
  27.     FInRestoreBuffer: Boolean;
  28.     FStickyFocus: Boolean;
  29.     function GetBuffer(Index: Integer): TDirectSoundBuffer;
  30.     function GetBufferCount: Integer;
  31.     function GetIDSound: IDirectSound;
  32.     function GetISound: IDirectSound;
  33.   protected          
  34.     procedure CheckBuffer(Buffer: TDirectSoundBuffer);
  35.     procedure DoRestoreBuffer; virtual;
  36.   public
  37.     constructor Create(GUID: PGUID);
  38.     destructor Destroy; override;
  39.     class function Drivers: TDirectXDrivers;
  40.     property BufferCount: Integer read GetBufferCount;
  41.     property Buffers[Index: Integer]: TDirectSoundBuffer read GetBuffer;
  42.     property IDSound: IDirectSound read GetIDSound;
  43.     property ISound: IDirectSound read GetISound;
  44.   end;
  45.  
  46.   {  TDirectSoundBuffer  }
  47.  
  48.   TDirectSoundBuffer = class(TDirectX)
  49.   private
  50.     FDSound: TDirectSound;
  51.     FIDSBuffer: IDirectSoundBuffer;
  52.     FCaps: TDSBCaps;
  53.     FFormat: PWaveFormatEx;
  54.     FFormatSize: Integer;
  55.     FLockAudioPtr1, FLockAudioPtr2: array[0..0] of Pointer;
  56.     FLockAudioSize1, FLockAudioSize2: array[0..0] of DWORD;
  57.     FLockCount: Integer;
  58.     function GetBitCount: Longint;
  59.     function GetFormat: PWaveFormatEx;
  60.     function GetFrequency: Integer;
  61.     function GetIDSBuffer: IDirectSoundBuffer;
  62.     function GetIBuffer: IDirectSoundBuffer;
  63.     function GetPlaying: Boolean;
  64.     function GetPan: Integer;
  65.     function GetPosition: Longint;
  66.     function GetSize: Integer;
  67.     function GetStatus: Integer;
  68.     function GetVolume: Integer;
  69.     procedure SetFrequency(Value: Integer);
  70.     procedure SetIDSBuffer(Value: IDirectSoundBuffer);
  71.     procedure SetPan(Value: Integer);
  72.     procedure SetPosition(Value: Longint);
  73.     procedure SetVolume(Value: Integer);
  74.   protected
  75.     procedure Check; override;
  76.   public
  77.     constructor Create(ADirectSound: TDirectSound);
  78.     destructor Destroy; override;
  79.     procedure Assign(Source: TPersistent); override;
  80.     function CreateBuffer(const BufferDesc: TDSBufferDesc): Boolean;
  81.     procedure LoadFromFile(const FileName: string);
  82.     procedure LoadFromMemory(const Format: TWaveFormatEx;
  83.       Data: Pointer; Size: Integer);
  84.     procedure LoadFromStream(Stream: TStream);
  85.     procedure LoadFromWave(Wave: TWave);
  86.     function Lock(LockPosition, LockSize: Longint;
  87.       var AudioPtr1: Pointer; var AudioSize1: Longint;
  88.       var AudioPtr2: Pointer; var AudioSize2: Longint): Boolean;
  89.     function Play(Loop: Boolean{$IFNDEF VER100}=False{$ENDIF}): Boolean;
  90.     function Restore: Boolean;
  91.     function SetFormat(const Format: TWaveFormatEx): Boolean;
  92.     procedure SetSize(const Format: TWaveFormatEx; Size: Integer);
  93.     procedure Stop;
  94.     procedure UnLock;
  95.     property BitCount: Longint read GetBitCount;
  96.     property DSound: TDirectSound read FDSound;
  97.     property Format: PWaveFormatEx read GetFormat;
  98.     property FormatSize: Integer read FFormatSize;
  99.     property Frequency: Integer read GetFrequency write SetFrequency;
  100.     property IBuffer: IDirectSoundBuffer read GetIBuffer;
  101.     property IDSBuffer: IDirectSoundBuffer read GetIDSBuffer write SetIDSBuffer;
  102.     property Playing: Boolean read GetPlaying;
  103.     property Pan: Integer read GetPan write SetPan;
  104.     property Position: Longint read GetPosition write SetPosition;
  105.     property Size: Integer read GetSize;
  106.     property Volume: Integer read GetVolume write SetVolume;
  107.   end;
  108.  
  109.   {  EAudioStreamError  }
  110.  
  111.   EAudioStreamError = class(Exception);
  112.  
  113.   {  TAudioStream  }
  114.  
  115.   TAudioStream = class
  116.   private
  117.     FAutoUpdate: Boolean;
  118.     FBuffer: TDirectSoundBuffer;
  119.     FBufferLength: Integer;
  120.     FBufferPos: DWORD;
  121.     FPlayBufferPos: DWORD;
  122.     FBufferSize: DWORD;
  123.     FDSound: TDirectSound;
  124.     FLooped: Boolean;
  125.     FPlayedSize: Integer;
  126.     FPlaying: Boolean;
  127.     FPosition: Integer;
  128.     FWaveStream: TCustomWaveStream;
  129.     FWritePosition: Integer;
  130.     FNotifyEvent: THandle;
  131.     FNotifyThread: TThread;
  132.     function GetFormat: PWaveFormatEX;
  133.     function GetFormatSize: Integer;
  134.     function GetFrequency: Integer;
  135.     function GetPan: Integer;
  136.     function GetPlayedSize: Integer;
  137.     function GetSize: Integer;
  138.     function GetVolume: Integer;
  139.     function GetWriteSize: Integer;
  140.     procedure SetAutoUpdate(Value: Boolean);
  141.     procedure SetBufferLength(Value: Integer);
  142.     procedure SetFrequency(Value: Integer);
  143.     procedure SetLooped(Value: Boolean);
  144.     procedure SetPan(Value: Integer);
  145.     procedure SetPlayedSize(Value: Integer);
  146.     procedure SetPosition(Value: Integer);
  147.     procedure SetVolume(Value: Integer);
  148.     procedure SetWaveStream(Value: TCustomWaveStream);
  149.     procedure Update2(InThread: Boolean);
  150.     procedure UpdatePlayedSize;
  151.     function WriteWave(WriteSize: Integer): Integer;
  152.   public
  153.     constructor Create(ADirectSound: TDirectSound);
  154.     destructor Destroy; override;
  155.     procedure Play;
  156.     procedure RecreateBuf;
  157.     procedure Stop;
  158.     procedure Update;
  159.     property AutoUpdate: Boolean read FAutoUpdate write SetAutoUpdate;
  160.     property BufferLength: Integer read FBufferLength write SetBufferLength;
  161.     property Format: PWaveFormatEx read GetFormat;
  162.     property FormatSize: Integer read GetFormatSize;
  163.     property Frequency: Integer read GetFrequency write SetFrequency;
  164.     property Pan: Integer read GetPan write SetPan;
  165.     property PlayedSize: Integer read GetPlayedSize write SetPlayedSize;
  166.     property Playing: Boolean read FPlaying;
  167.     property Position: Integer read FPosition write SetPosition;
  168.     property Looped: Boolean read FLooped write SetLooped;
  169.     property Size: Integer read GetSize;
  170.     property Volume: Integer read GetVolume write SetVolume;
  171.     property WaveStream: TCustomWaveStream read FWaveStream write SetWaveStream;
  172.   end;
  173.    
  174.   {  TAudioFileStream  }
  175.  
  176.   TAudioFileStream = class(TAudioStream)
  177.   private
  178.     FFileName: string;
  179.     FWaveFileStream: TWaveFileStream;
  180.     procedure SetFileName(const Value: string);
  181.   public
  182.     destructor Destroy; override;
  183.     property FileName: string read FFileName write SetFileName;
  184.   end;
  185.  
  186.   {  TSoundCaptureFormat  }
  187.  
  188.   TSoundCaptureFormat = class(TCollectionItem)
  189.   private
  190.     FBitsPerSample: Integer;
  191.     FChannels: Integer;
  192.     FSamplesPerSec: Integer;
  193.   public
  194.     property BitsPerSample: Integer read FBitsPerSample;
  195.     property Channels: Integer read FChannels;
  196.     property SamplesPerSec: Integer read FSamplesPerSec;
  197.   end;
  198.  
  199.   {  TSoundCaptureFormats  }
  200.  
  201.   TSoundCaptureFormats = class(TCollection)
  202.   private
  203.     function GetItem(Index: Integer): TSoundCaptureFormat;
  204.   public
  205.     constructor Create;
  206.     function IndexOf(ASamplesPerSec, ABitsPerSample, AChannels: Integer): Integer;
  207.     property Items[Index: Integer]: TSoundCaptureFormat read GetItem; default;
  208.   end;
  209.  
  210.   {  TSoundCaptureStream  }
  211.  
  212.   ESoundCaptureStreamError = class(EWaveStreamError);
  213.  
  214.   TSoundCaptureStream = class(TCustomWaveStream2)
  215.   private
  216.     FBuffer: IDirectSoundCaptureBuffer;
  217.     FBufferLength: Integer;
  218.     FBufferPos: DWORD;
  219.     FBufferSize: DWORD;
  220.     FCapture: IDirectSoundCapture;
  221.     FCaptureFormat: Integer;
  222.     FCapturing: Boolean;
  223.     FNotifyEvent: THandle;
  224.     FNotifyThread: TThread;
  225.     FOnFilledBuffer: TNotifyEvent;
  226.     FSupportedFormats: TSoundCaptureFormats;
  227.     function GetReadSize: Integer;
  228.     procedure SetBufferLength(Value: Integer);
  229.     procedure SetOnFilledBuffer(Value: TNotifyEvent);
  230.   protected
  231.     procedure DoFilledBuffer; virtual;
  232.     function GetFilledSize: Integer; override;
  233.     function ReadWave(var Buffer; Count: Integer): Integer; override;
  234.   public
  235.     constructor Create(GUID: PGUID);
  236.     destructor Destroy; override;
  237.     class function Drivers: TDirectXDrivers;
  238.     procedure Start;
  239.     procedure Stop;
  240.     property BufferLength: Integer read FBufferLength write SetBufferLength;
  241.     property CaptureFormat: Integer read FCaptureFormat write FCaptureFormat;
  242.     property Capturing: Boolean read FCapturing;
  243.     property OnFilledBuffer: TNotifyEvent read FOnFilledBuffer write SetOnFilledBuffer;
  244.     property SupportedFormats: TSoundCaptureFormats read FSupportedFormats;
  245.   end;
  246.  
  247.   {  TSoundEngine  }
  248.  
  249.   TSoundEngine = class
  250.   private
  251.     FDSound: TDirectSound;
  252.     FEffectList: TList;
  253.     FEnabled: Boolean;
  254.     FTimer: TTimer;
  255.     function GetEffect(Index: Integer): TDirectSoundBuffer;
  256.     function GetEffectCount: Integer;
  257.     procedure SetEnabled(Value: Boolean);
  258.     procedure TimerEvent(Sender: TObject);
  259.   public
  260.     constructor Create(ADSound: TDirectSound);
  261.     destructor Destroy; override;
  262.     procedure Clear;
  263.     procedure EffectFile(const Filename: string; Loop, Wait: Boolean);
  264.     procedure EffectStream(Stream: TStream; Loop, Wait: Boolean);
  265.     procedure EffectWave(Wave: TWave; Loop, Wait: Boolean);
  266.     property EffectCount: Integer read GetEffectCount;
  267.     property Effects[Index: Integer]: TDirectSoundBuffer read GetEffect;
  268.     property Enabled: Boolean read FEnabled write SetEnabled;
  269.   end;
  270.  
  271.   {  EDXSoundError  }
  272.  
  273.   EDXSoundError = class(Exception);
  274.  
  275.   {  TCustomDXSound  }
  276.  
  277.   TCustomDXSound = class;
  278.  
  279.   TDXSoundOption = (soGlobalFocus, soStickyFocus, soExclusive);
  280.   TDXSoundOptions = set of TDXSoundOption;
  281.  
  282.   TDXSoundNotifyType = (dsntDestroying, dsntInitializing, dsntInitialize, dsntFinalize, dsntRestore);
  283.   TDXSoundNotifyEvent = procedure(Sender: TCustomDXSound; NotifyType: TDXSoundNotifyType) of object;
  284.  
  285.   TCustomDXSound = class(TComponent)
  286.   private
  287.     FAutoInitialize: Boolean;
  288.     FCalledDoInitialize: Boolean;
  289.     FDriver: PGUID;
  290.     FDriverGUID: TGUID;
  291.     FDSound: TDirectSound;
  292.     FForm: TCustomForm;
  293.     FInitialized: Boolean;
  294.     FInternalInitialized: Boolean;
  295.     FNotifyEventList: TList;
  296.     FNowOptions: TDXSoundOptions;
  297.     FOnFinalize: TNotifyEvent;
  298.     FOnInitialize: TNotifyEvent;
  299.     FOnInitializing: TNotifyEvent;
  300.     FOnRestore: TNotifyEvent;
  301.     FOptions: TDXSoundOptions;
  302.     FPrimary: TDirectSoundBuffer;
  303.     FSubClass: TControlSubClass;
  304.     procedure FormWndProc(var Message: TMessage; DefWindowProc: TWndMethod);
  305.     procedure NotifyEventList(NotifyType: TDXSoundNotifyType);
  306.     procedure SetDriver(Value: PGUID);
  307.     procedure SetForm(Value: TCustomForm);
  308.     procedure SetOptions(Value: TDXSoundOptions);
  309.   protected
  310.     procedure DoFinalize; virtual;
  311.     procedure DoInitialize; virtual;
  312.     procedure DoInitializing; virtual;
  313.     procedure DoRestore; virtual;
  314.     procedure Loaded; override;
  315.   public
  316.     constructor Create(AOwner: TComponent); override;
  317.     destructor Destroy; override;
  318.     class function Drivers: TDirectXDrivers;
  319.     procedure Finalize;
  320.     procedure Initialize;
  321.     procedure Restore;
  322.     procedure RegisterNotifyEvent(NotifyEvent: TDXSoundNotifyEvent);
  323.     procedure UnRegisterNotifyEvent(NotifyEvent: TDXSoundNotifyEvent);
  324.  
  325.     property AutoInitialize: Boolean read FAutoInitialize write FAutoInitialize;
  326.     property Driver: PGUID read FDriver write SetDriver;
  327.     property DSound: TDirectSound read FDSound;
  328.     property Initialized: Boolean read FInitialized;
  329.     property NowOptions: TDXSoundOptions read FNowOptions;
  330.     property Primary: TDirectSoundBuffer read FPrimary;
  331.     property OnFinalize: TNotifyEvent read FOnFinalize write FOnFinalize;
  332.     property OnInitialize: TNotifyEvent read FOnInitialize write FOnInitialize;
  333.     property OnInitializing: TNotifyEvent read FOnInitializing write FOnInitializing;
  334.     property OnRestore: TNotifyEvent read FOnRestore write FOnRestore;
  335.     property Options: TDXSoundOptions read FOptions write SetOptions;
  336.   end;
  337.  
  338.   {  TDXSound  }
  339.  
  340.   TDXSound = class(TCustomDXSound)
  341.   published
  342.     property AutoInitialize;
  343.     property Options;
  344.     property OnFinalize;
  345.     property OnInitialize;
  346.     property OnInitializing;
  347.     property OnRestore;
  348.   end;
  349.  
  350.   {  EWaveCollectionError  }
  351.  
  352.   EWaveCollectionError = class(Exception);
  353.  
  354.   {  TWaveCollectionItem  }
  355.  
  356.   TWaveCollection = class;
  357.  
  358.   TWaveCollectionItem = class(THashCollectionItem)
  359.   private
  360.     FBuffer: TDirectSoundBuffer;
  361.     FBufferList: TList;
  362.     FFrequency: Integer;
  363.     FInitialized: Boolean;
  364.     FLooped: Boolean;
  365.     FMaxPlayingCount: Integer;
  366.     FPan: Integer;
  367.     FVolume: Integer;
  368.     FWave: TWave;
  369.     function CreateBuffer: TDirectSoundBuffer;
  370.     procedure Finalize;
  371.     procedure Initialize;
  372.     function GetBuffer: TDirectSoundBuffer;
  373.     function GetWaveCollection: TWaveCollection;
  374.     procedure SetFrequency(Value: Integer);
  375.     procedure SetLooped(Value: Boolean);
  376.     procedure SetMaxPlayingCount(Value: Integer);
  377.     procedure SetPan(Value: Integer);
  378.     procedure SetVolume(Value: Integer);
  379.     procedure SetWave(Value: TWave);
  380.   public
  381.     constructor Create(Collection: TCollection); override;
  382.     destructor Destroy; override;
  383.     procedure Assign(Source: TPersistent); override;
  384.     procedure Play(Wait: Boolean);
  385.     procedure Restore;
  386.     procedure Stop;
  387.     property Frequency: Integer read FFrequency write SetFrequency;
  388.     property Initialized: Boolean read FInitialized;
  389.     property Pan: Integer read FPan write SetPan;
  390.     property Volume: Integer read FVolume write SetVolume;
  391.     property WaveCollection: TWaveCollection read GetWaveCollection;
  392.   published
  393.     property Looped: Boolean read FLooped write SetLooped;
  394.     property MaxPlayingCount: Integer read FMaxPlayingCount write SetMaxPlayingCount;
  395.     property Wave: TWave read FWave write SetWave;
  396.   end;
  397.  
  398.   {  TWaveCollection  }
  399.  
  400.   TWaveCollection = class(THashCollection)
  401.   private
  402.     FDXSound: TCustomDXSound;
  403.     FOwner: TPersistent;
  404.     function GetItem(Index: Integer): TWaveCollectionItem;
  405.     function Initialized: Boolean;
  406.   protected
  407.     function GetOwner: TPersistent; override;
  408.   public
  409.     constructor Create(AOwner: TPersistent);
  410.     function Find(const Name: string): TWaveCollectionItem;
  411.     procedure Finalize;
  412.     procedure Initialize(DXSound: TCustomDXSound);
  413.     procedure Restore;
  414.     procedure LoadFromFile(const FileName: string);
  415.     procedure LoadFromStream(Stream: TStream);
  416.     procedure SaveToFile(const FileName: string);
  417.     procedure SaveToStream(Stream: TStream);
  418.     property DXSound: TCustomDXSound read FDXSound;
  419.     property Items[Index: Integer]: TWaveCollectionItem read GetItem; default;
  420.   end;
  421.  
  422.   {  TCustomDXWaveList  }
  423.  
  424.   TCustomDXWaveList = class(TComponent)
  425.   private
  426.     FDXSound: TCustomDXSound;
  427.     FItems: TWaveCollection;
  428.     procedure DXSoundNotifyEvent(Sender: TCustomDXSound; NotifyType: TDXSoundNotifyType);
  429.     procedure SetDXSound(Value: TCustomDXSound);
  430.     procedure SetItems(Value: TWaveCollection);
  431.   protected
  432.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  433.   public
  434.     constructor Create(AOwner: TComponent); override;
  435.     destructor Destroy; override;
  436.     property DXSound: TCustomDXSound read FDXSound write SetDXSound;
  437.     property Items: TWaveCollection read FItems write SetItems;
  438.   end;
  439.  
  440.   {  TDXWaveList  }
  441.  
  442.   TDXWaveList = class(TCustomDXWaveList)
  443.   published
  444.     property DXSound;
  445.     property Items;
  446.   end;
  447.  
  448. implementation
  449.  
  450. uses DXConsts;
  451.  
  452. function DXDirectSoundCreate(lpGUID: PGUID; out lpDS: IDirectSound;
  453.   pUnkOuter: IUnknown): HRESULT;
  454. type
  455.   TDirectSoundCreate = function(lpGUID: PGUID; out lplpDD: IDirectSound;
  456.     pUnkOuter: IUnknown): HRESULT; stdcall;
  457. begin
  458.   Result := TDirectSoundCreate(DXLoadLibrary('DSound.dll', 'DirectSoundCreate'))
  459.     (lpGUID, lpDS, pUnkOuter);
  460. end;
  461.  
  462. function DXDirectSoundEnumerate(lpCallback: TDSEnumCallbackA;
  463.     lpContext: Pointer): HRESULT;
  464. type
  465.   TDirectSoundEnumerate = function(lpCallback: TDSEnumCallbackA;
  466.     lpContext: Pointer): HRESULT; stdcall;
  467. begin
  468.   Result := TDirectSoundEnumerate(DXLoadLibrary('DSound.dll', 'DirectSoundEnumerateA'))
  469.     (lpCallback, lpContext);
  470. end;
  471.  
  472. function DXDirectSoundCaptureCreate(lpGUID: PGUID; out lplpDSC: IDirectSoundCapture;
  473.   pUnkOuter: IUnknown): HRESULT;
  474. type
  475.   TDirectSoundCaptureCreate = function(lpGUID: PGUID; out lplpDD: IDirectSoundCapture;
  476.     pUnkOuter: IUnknown): HRESULT; stdcall;
  477. begin
  478.   try
  479.     Result := TDirectSoundCaptureCreate(DXLoadLibrary('DSound.dll', 'DirectSoundCaptureCreate'))
  480.       (lpGUID, lplpDSC, pUnkOuter);
  481.   except
  482.     raise EDirectXError.Create(SSinceDirectX5);
  483.   end;
  484. end;
  485.  
  486. function DXDirectSoundCaptureEnumerate(lpCallback: TDSEnumCallbackA;
  487.     lpContext: Pointer): HRESULT;
  488. type
  489.   TDirectSoundCaptureEnumerate = function(lpCallback: TDSEnumCallbackA;
  490.     lpContext: Pointer): HRESULT; stdcall;
  491. begin
  492.   try
  493.     Result := TDirectSoundCaptureEnumerate(DXLoadLibrary('DSound.dll', 'DirectSoundCaptureEnumerateA'))
  494.       (lpCallback, lpContext);
  495.   except
  496.     raise EDirectXError.Create(SSinceDirectX5);
  497.   end;
  498. end;
  499.  
  500. var
  501.   DirectSoundDrivers: TDirectXDrivers;
  502.   DirectSoundCaptureDrivers: TDirectXDrivers;
  503.  
  504. function EnumDirectSoundDrivers_DSENUMCALLBACK(lpGuid: PGUID; lpstrDescription: LPCSTR;
  505.   lpstrModule: LPCSTR; lpContext: Pointer): BOOL; stdcall;
  506. begin
  507.   Result := True;
  508.   with TDirectXDriver.Create(TDirectXDrivers(lpContext)) do
  509.   begin
  510.     Guid := lpGuid;
  511.     Description := lpstrDescription;
  512.     DriverName := lpstrModule;
  513.   end;
  514. end;
  515.  
  516. function EnumDirectSoundDrivers: TDirectXDrivers;
  517. begin
  518.   if DirectSoundDrivers=nil then
  519.   begin
  520.     DirectSoundDrivers := TDirectXDrivers.Create;
  521.     try
  522.       DXDirectSoundEnumerate(@EnumDirectSoundDrivers_DSENUMCALLBACK, DirectSoundDrivers);
  523.     except
  524.       DirectSoundDrivers.Free;
  525.       raise;
  526.     end;
  527.   end;
  528.  
  529.   Result := DirectSoundDrivers;
  530. end;
  531.  
  532. function EnumDirectSoundCaptureDrivers: TDirectXDrivers;
  533. begin
  534.   if DirectSoundCaptureDrivers=nil then
  535.   begin
  536.     DirectSoundCaptureDrivers := TDirectXDrivers.Create;
  537.     try
  538.       DXDirectSoundCaptureEnumerate(@EnumDirectSoundDrivers_DSENUMCALLBACK, DirectSoundCaptureDrivers);
  539.     except
  540.       DirectSoundCaptureDrivers.Free;
  541.       raise;
  542.     end;
  543.   end;
  544.  
  545.   Result := DirectSoundCaptureDrivers;
  546. end;
  547.  
  548. {  TDirectSound  }
  549.  
  550. constructor TDirectSound.Create(GUID: PGUID);
  551. begin
  552.   inherited Create;
  553.   FBufferList := TList.Create;
  554.  
  555.   if DXDirectSoundCreate(GUID, FIDSound, nil)<>DS_OK then
  556.     raise EDirectSoundError.CreateFmt(SCannotInitialized, [SDirectSound]);
  557. end;
  558.  
  559. destructor TDirectSound.Destroy;
  560. begin
  561.   while BufferCount>0 do
  562.     Buffers[BufferCount-1].Free;
  563.   FBufferList.Free;
  564.  
  565.   FIDSound := nil;
  566.   inherited Destroy;
  567. end;
  568.  
  569. class function TDirectSound.Drivers: TDirectXDrivers;
  570. begin
  571.   Result := EnumDirectSoundDrivers;
  572. end;
  573.  
  574. procedure TDirectSound.CheckBuffer(Buffer: TDirectSoundBuffer);
  575. begin
  576.   case Buffer.DXResult of
  577.     DSERR_BUFFERLOST:
  578.       begin
  579.         if not FInRestoreBuffer then
  580.         begin
  581.           FInRestoreBuffer := True;
  582.           try
  583.             DoRestoreBuffer;
  584.           finally
  585.             FInRestoreBuffer := False;
  586.           end;
  587.         end;
  588.       end;
  589.   end;
  590. end;
  591.  
  592. procedure TDirectSound.DoRestoreBuffer;
  593. begin
  594. end;
  595.  
  596. function TDirectSound.GetBuffer(Index: Integer): TDirectSoundBuffer;
  597. begin
  598.   Result := FBufferList[Index];
  599. end;
  600.  
  601. function TDirectSound.GetBufferCount: Integer;
  602. begin
  603.   Result := FBufferList.Count;
  604. end;
  605.  
  606. function TDirectSound.GetIDSound: IDirectSound;
  607. begin
  608.   if Self<>nil then
  609.     Result := FIDSound
  610.   else
  611.     Result := nil;
  612. end;
  613.  
  614. function TDirectSound.GetISound: IDirectSound;
  615. begin
  616.   Result := IDSound;
  617.   if Result=nil then
  618.     raise EDirectSoundError.CreateFmt(SNotMade, ['IDirectSound']);
  619. end;
  620.  
  621. {  TDirectSoundBuffer  }
  622.  
  623. constructor TDirectSoundBuffer.Create(ADirectSound: TDirectSound);
  624. begin
  625.   inherited Create;
  626.   FDSound := ADirectSound;
  627.   FDSound.FBufferList.Add(Self);
  628. end;
  629.  
  630. destructor TDirectSoundBuffer.Destroy;
  631. begin
  632.   IDSBuffer := nil;
  633.   FDSound.FBufferList.Remove(Self);
  634.   inherited Destroy;
  635. end;
  636.  
  637. procedure TDirectSoundBuffer.Assign(Source: TPersistent);
  638. var
  639.   TempBuffer: IDirectSoundBuffer;
  640. begin
  641.   if Source=nil then
  642.     IDSBuffer := nil
  643.   else if Source is TWave then
  644.     LoadFromWave(TWave(Source))
  645.   else if Source is TDirectSoundBuffer then
  646.   begin
  647.     if TDirectSoundBuffer(Source).IDSBuffer=nil then
  648.       IDSBuffer := nil
  649.     else begin
  650.       FDSound.DXResult := FDSound.ISound.DuplicateSoundBuffer(TDirectSoundBuffer(Source).IDSBuffer,
  651.         TempBuffer);
  652.       if FDSound.DXResult=0 then
  653.       begin
  654.         IDSBuffer := TempBuffer;
  655.       end;
  656.     end;
  657.   end else
  658.     inherited Assign(Source);
  659. end;
  660.  
  661. procedure TDirectSoundBuffer.Check;
  662. begin
  663.   FDSound.CheckBuffer(Self);
  664. end;
  665.  
  666. function TDirectSoundBuffer.CreateBuffer(const BufferDesc: TDSBufferDesc): Boolean;
  667. var
  668.   TempBuffer: IDirectSoundBuffer;
  669. begin
  670.   IDSBuffer := nil;
  671.  
  672.   FDSound.DXResult := FDSound.ISound.CreateSoundBuffer(BufferDesc, TempBuffer, nil);
  673.   FDXResult := FDSound.DXResult;
  674.   Result := DXResult=DS_OK;
  675.   if Result then
  676.     IDSBuffer := TempBuffer;
  677. end;
  678.  
  679. function TDirectSoundBuffer.GetBitCount: Longint;
  680. begin
  681.   Result := Format.wBitsPerSample;
  682. end;
  683.  
  684. function TDirectSoundBuffer.GetFormat: PWaveFormatEx;
  685. begin
  686.   GetIBuffer;
  687.   Result := FFormat;
  688. end;
  689.  
  690. function TDirectSoundBuffer.GetFrequency: Integer;
  691. begin
  692.   DXResult := IBuffer.GetFrequency(DWORD(Result));
  693. end;
  694.  
  695. function TDirectSoundBuffer.GetIDSBuffer: IDirectSoundBuffer;
  696. begin
  697.   if Self<>nil then
  698.     Result := FIDSBuffer
  699.   else
  700.     Result := nil;
  701. end;
  702.  
  703. function TDirectSoundBuffer.GetIBuffer: IDirectSoundBuffer;
  704. begin
  705.   Result := IDSBuffer;
  706.   if Result=nil then
  707.     raise EDirectSoundBufferError.CreateFmt(SNotMade, ['IDirectSoundBuffer']);
  708. end;
  709.  
  710. function TDirectSoundBuffer.GetPlaying: Boolean;
  711. begin
  712.   Result := (GetStatus and (DSBSTATUS_PLAYING or DSBSTATUS_LOOPING))<>0;
  713. end;
  714.  
  715. function TDirectSoundBuffer.GetPan: Integer;
  716. begin
  717.   DXResult := IBuffer.GetPan(Longint(Result));
  718. end;
  719.  
  720. function TDirectSoundBuffer.GetPosition: Longint;
  721. var                                    
  722.   dwCurrentWriteCursor: Longint;
  723. begin
  724.   IBuffer.GetCurrentPosition(DWORD(Result), DWORD(dwCurrentWriteCursor));
  725. end;
  726.  
  727. function TDirectSoundBuffer.GetSize: Integer;
  728. begin
  729.   Result := FCaps.dwBufferBytes;
  730. end;
  731.  
  732. function TDirectSoundBuffer.GetStatus: Integer;
  733. begin
  734.   DXResult := IBuffer.GetStatus(DWORD(Result));
  735. end;
  736.  
  737. function TDirectSoundBuffer.GetVolume: Integer;
  738. begin
  739.   DXResult := IBuffer.GetVolume(Longint(Result));
  740. end;
  741.  
  742. procedure TDirectSoundBuffer.LoadFromFile(const FileName: string);
  743. var
  744.   Stream : TFileStream;
  745. begin
  746.   Stream := TFileStream.Create(FileName, fmOpenRead);
  747.   try
  748.     LoadFromStream(Stream);
  749.   finally
  750.     Stream.Free;
  751.   end;
  752. end;
  753.  
  754. procedure TDirectSoundBuffer.LoadFromMemory(const Format: TWaveFormatEx;
  755.   Data: Pointer; Size: Integer);
  756. var
  757.   Data1, Data2: Pointer;
  758.   Data1Size, Data2Size: Longint;
  759. begin
  760.   SetSize(Format, Size);
  761.  
  762.   if Data<>nil then
  763.   begin
  764.     if Lock(0, Size, Data1, Data1Size, Data2, Data2Size) then
  765.     begin
  766.       try
  767.         Move(Data^, Data1^, Data1Size);
  768.         if Data2<>nil then
  769.           Move(Pointer(Longint(Data)+Data1Size)^, Data2^, Data2Size);
  770.       finally
  771.         UnLock;
  772.       end;
  773.     end else
  774.     begin
  775.       FIDSBuffer := nil;
  776.       raise EDirectSoundBufferError.CreateFmt(SCannotLock, [SDirectSoundBuffer]);
  777.     end;
  778.   end;
  779. end;
  780.  
  781. procedure TDirectSoundBuffer.LoadFromStream(Stream: TStream);
  782. var  
  783.   Wave: TWave;
  784. begin
  785.   Wave := TWave.Create;
  786.   try
  787.     Wave.LoadFromStream(Stream);
  788.     LoadFromWave(Wave);
  789.   finally
  790.     Wave.Free;
  791.   end;
  792. end;
  793.  
  794. procedure TDirectSoundBuffer.LoadFromWave(Wave: TWave);
  795. begin
  796.   LoadFromMemory(Wave.Format^, Wave.Data, Wave.Size);
  797. end;
  798.  
  799. function TDirectSoundBuffer.Lock(LockPosition, LockSize: Longint;
  800.   var AudioPtr1: Pointer; var AudioSize1: Longint;
  801.   var AudioPtr2: Pointer; var AudioSize2: Longint): Boolean;
  802. begin
  803.   Result := False;
  804.   if IDSBuffer=nil then Exit;
  805.  
  806.   if FLockCount>High(FLockAudioPtr1) then Exit;
  807.  
  808.   DXResult := IBuffer.Lock(LockPosition, LockSize,
  809.     FLockAudioPtr1[FLockCount], FLockAudioSize1[FLockCount],
  810.     FLockAudioPtr2[FLockCount], FLockAudioSize2[FLockCount], 0);
  811.   Result := DXResult=DS_OK;
  812.  
  813.   if Result then
  814.   begin
  815.     AudioPtr1 := FLockAudioPtr1[FLockCount];
  816.     AudioPtr2 := FLockAudioPtr2[FLockCount];
  817.     AudioSize1 := FLockAudioSize1[FLockCount];
  818.     AudioSize2 := FLockAudioSize2[FLockCount];
  819.     Inc(FLockCount);
  820.   end;
  821. end;
  822.  
  823. function TDirectSoundBuffer.Play(Loop: Boolean): Boolean;
  824. begin
  825.   if Loop then
  826.     DXResult := IBuffer.Play(0, 0, DSBPLAY_LOOPING)
  827.   else
  828.     DXResult := IBuffer.Play(0, 0, 0);
  829.   Result := DXResult=DS_OK;
  830. end;
  831.  
  832. function TDirectSoundBuffer.Restore: Boolean;
  833. begin
  834.   DXResult := IBuffer.Restore;
  835.   Result := DXResult=DS_OK;
  836. end;
  837.  
  838. function TDirectSoundBuffer.SetFormat(const Format: TWaveFormatEx): Boolean;
  839. begin
  840.   DXResult := IBuffer.SetFormat(Format);
  841.   Result := DXResult=DS_OK;
  842.  
  843.   if Result then
  844.   begin
  845.     FreeMem(FFormat);
  846.     FFormat := nil;
  847.     FFormatSize := 0;
  848.     if IBuffer.GetFormat(PWaveFormatEx(nil)^, 0, DWORD(FFormatSize))=DS_OK then
  849.     begin
  850.       GetMem(FFormat, FFormatSize);
  851.       IBuffer.GetFormat(FFormat^, FFormatSize, PDWORD(nil)^);
  852.     end;            
  853.   end;
  854. end;
  855.  
  856. procedure TDirectSoundBuffer.SetFrequency(Value: Integer);
  857. begin
  858.   DXResult := IBuffer.SetFrequency(Value);
  859. end;
  860.  
  861. procedure TDirectSoundBuffer.SetIDSBuffer(Value: IDirectSoundBuffer);
  862. begin
  863.   if FIDSBuffer=Value then Exit;
  864.  
  865.   FIDSBuffer := Value;
  866.   FillChar(FCaps, SizeOf(FCaps), 0);
  867.   FreeMem(FFormat);
  868.   FFormat := nil;
  869.   FFormatSize := 0;
  870.   FLockCount := 0;
  871.  
  872.   if FIDSBuffer<>nil then
  873.   begin
  874.     FCaps.dwSize := SizeOf(FCaps);
  875.     IBuffer.GetCaps(FCaps);
  876.  
  877.     if IBuffer.GetFormat(PWaveFormatEx(nil)^, 0, DWORD(FFormatSize))=DS_OK then
  878.     begin
  879.       GetMem(FFormat, FFormatSize);
  880.       IBuffer.GetFormat(FFormat^, FFormatSize, PDWORD(nil)^);
  881.     end;                
  882.   end;
  883. end;
  884.  
  885. procedure TDirectSoundBuffer.SetPan(Value: Integer);
  886. begin
  887.   DXResult := IBuffer.SetPan(Value);
  888. end;
  889.  
  890. procedure TDirectSoundBuffer.SetPosition(Value: Longint);
  891. begin
  892.   DXResult := IBuffer.SetCurrentPosition(Value);
  893. end;
  894.  
  895. procedure TDirectSoundBuffer.SetSize(const Format: TWaveFormatEx; Size: Integer);
  896. var
  897.   BufferDesc: TDSBufferDesc;
  898. begin
  899.   {  IDirectSoundBuffer made.  }
  900.   FillChar(BufferDesc, SizeOf(BufferDesc), 0);
  901.  
  902.   with BufferDesc do
  903.   begin
  904.     dwSize := SizeOf(TDSBufferDesc);
  905.     dwFlags := DSBCAPS_CTRLDEFAULT;
  906.     if DSound.FStickyFocus then
  907.       dwFlags := dwFlags or DSBCAPS_STICKYFOCUS
  908.     else if DSound.FGlobalFocus then
  909.       dwFlags := dwFlags or DSBCAPS_GLOBALFOCUS;
  910.     dwBufferBytes := Size;
  911.     lpwfxFormat := @Format;
  912.   end;
  913.  
  914.   if not CreateBuffer(BufferDesc) then
  915.     raise EDirectSoundBufferError.CreateFmt(SCannotMade, [SDirectSoundBuffer]);
  916. end;
  917.  
  918. procedure TDirectSoundBuffer.SetVolume(Value: Integer);
  919. begin
  920.   DXResult := IBuffer.SetVolume(Value);
  921. end;
  922.  
  923. procedure TDirectSoundBuffer.Stop;
  924. begin
  925.   DXResult := IBuffer.Stop;
  926. end;
  927.  
  928. procedure TDirectSoundBuffer.Unlock;
  929. begin
  930.   if IDSBuffer=nil then Exit;
  931.   if FLockCount=0 then Exit;
  932.  
  933.   Dec(FLockCount);
  934.   DXResult := IBuffer.UnLock(FLockAudioPtr1[FLockCount], FLockAudioSize1[FLockCount],
  935.     FLockAudioPtr2[FLockCount], FLockAudioSize2[FLockCount]);
  936. end;
  937.  
  938. {  TAudioStream  }
  939.  
  940. type
  941.   TAudioStreamNotify = class(TThread)
  942.   private
  943.     FAudio: TAudioStream;
  944.     FSleepTime: Integer;
  945.     FStopOnTerminate: Boolean;
  946.     constructor Create(Audio: TAudioStream);
  947.     destructor Destroy; override;
  948.     procedure Execute; override;
  949.     procedure Update;
  950.     procedure ThreadTerminate(Sender: TObject);
  951.   end;
  952.  
  953. constructor TAudioStreamNotify.Create(Audio: TAudioStream);
  954. begin
  955.   FAudio := Audio;
  956.  
  957.   OnTerminate := ThreadTerminate;
  958.  
  959.   FAudio.FNotifyEvent := CreateEvent(nil, False, False, nil);
  960.   FAudio.FNotifyThread := Self;
  961.  
  962.   FSleepTime := Min(FAudio.FBufferLength div 4, 1000 div 20);
  963.   FStopOnTerminate := True;
  964.  
  965.   FreeOnTerminate := True;
  966.   inherited Create(False);
  967. end;
  968.  
  969. destructor TAudioStreamNotify.Destroy;
  970. begin
  971.   FreeOnTerminate := False;
  972.  
  973.   SetEvent(FAudio.FNotifyEvent);
  974.   inherited Destroy;
  975.   CloseHandle(FAudio.FNotifyEvent);
  976.  
  977.   FAudio.FNotifyThread := nil;
  978. end;
  979.  
  980. procedure TAudioStreamNotify.ThreadTerminate(Sender: TObject);
  981. begin
  982.   FAudio.FNotifyThread := nil;
  983.   if FStopOnTerminate then FAudio.Stop;
  984. end;
  985.  
  986. procedure TAudioStreamNotify.Execute;
  987. begin
  988.   while WaitForSingleObject(FAudio.FNotifyEvent, FSleepTime)=WAIT_TIMEOUT do
  989.     Synchronize(Update);
  990. end;
  991.  
  992. procedure TAudioStreamNotify.Update;
  993. begin
  994.   if not FAudio.Playing then
  995.   begin
  996.     SetEvent(FAudio.FNotifyEvent);
  997.     EXit;
  998.   end;
  999.  
  1000.   try
  1001.     FAudio.Update2(True);
  1002.   except
  1003.     on E: Exception do
  1004.     begin
  1005.       Application.HandleException(E);
  1006.       SetEvent(FAudio.FNotifyEvent);
  1007.     end;
  1008.   end;
  1009. end;
  1010.  
  1011. constructor TAudioStream.Create(ADirectSound: TDirectSound);
  1012. begin
  1013.   inherited Create;
  1014.   FDSound := ADirectSound;
  1015.   FAutoUpdate := True;
  1016.   FBuffer := TDirectSoundBuffer.Create(FDSound);
  1017.   FBufferLength := 1000;
  1018. end;
  1019.  
  1020. destructor TAudioStream.Destroy;
  1021. begin
  1022.   Stop;
  1023.   WaveStream := nil;
  1024.   FBuffer.Free;
  1025.   inherited Destroy;
  1026. end;
  1027.  
  1028. function TAudioStream.GetFormat: PWaveFormatEX;
  1029. begin
  1030.   if WaveStream=nil then
  1031.     raise EAudioStreamError.Create(SWaveStreamNotSet);
  1032.   Result := WaveStream.Format;
  1033. end;
  1034.  
  1035. function TAudioStream.GetFormatSize: Integer;
  1036. begin
  1037.   if WaveStream=nil then
  1038.     raise EAudioStreamError.Create(SWaveStreamNotSet);
  1039.   Result := WaveStream.FormatSize;
  1040. end;
  1041.  
  1042. function TAudioStream.GetFrequency: Integer;
  1043. begin
  1044.   Result := FBuffer.Frequency;
  1045. end;
  1046.  
  1047. function TAudioStream.GetPan: Integer;
  1048. begin
  1049.   Result := FBuffer.Pan;
  1050. end;
  1051.  
  1052. function TAudioStream.GetPlayedSize: Integer;
  1053. begin
  1054.   if Playing then UpdatePlayedSize;
  1055.   Result := FPlayedSize;
  1056. end;
  1057.  
  1058. function TAudioStream.GetSize: Integer;
  1059. begin
  1060.   if WaveStream<>nil then
  1061.     Result := WaveStream.Size
  1062.   else
  1063.     Result := 0;
  1064. end;
  1065.  
  1066. function TAudioStream.GetVolume: Integer;
  1067. begin
  1068.   Result := FBuffer.Volume;
  1069. end;
  1070.  
  1071. procedure TAudioStream.UpdatePlayedSize;
  1072. var
  1073.   PlayPosition, PlayedSize: DWORD;
  1074. begin
  1075.   PlayPosition := FBuffer.Position;
  1076.  
  1077.   if FPlayBufferPos <= PlayPosition then
  1078.   begin
  1079.     PlayedSize := PlayPosition - FPlayBufferPos
  1080.   end else
  1081.   begin
  1082.     PlayedSize := PlayPosition + (FBufferSize - FPlayBufferPos);
  1083.   end;
  1084.  
  1085.   Inc(FPlayedSize, PlayedSize);
  1086.  
  1087.   FPlayBufferPos := PlayPosition;
  1088. end;
  1089.  
  1090. function TAudioStream.GetWriteSize: Integer;
  1091. var
  1092.   PlayPosition: DWORD;
  1093.   i: Integer;
  1094. begin
  1095.   PlayPosition := FBuffer.Position;
  1096.  
  1097.   if FBufferPos <= PlayPosition then
  1098.   begin
  1099.     Result := PlayPosition - FBufferPos
  1100.   end else
  1101.   begin
  1102.     Result := PlayPosition + (FBufferSize - FBufferPos);
  1103.   end;
  1104.  
  1105.   i := WaveStream.FilledSize;
  1106.   if i>=0 then Result := Min(Result, i);
  1107. end;
  1108.  
  1109. procedure TAudioStream.Play;
  1110. begin
  1111.   if not FPlaying then
  1112.   begin
  1113.     if WaveStream=nil then
  1114.       raise EAudioStreamError.Create(SWaveStreamNotSet);
  1115.  
  1116.     if Size=0 then Exit;
  1117.  
  1118.     FPlaying := True;
  1119.     try
  1120.       SetPosition(FPosition);
  1121.       if FAutoUpdate then
  1122.         FNotifyThread := TAudioStreamNotify.Create(Self);
  1123.     except
  1124.       Stop;
  1125.       raise;
  1126.     end;
  1127.   end;
  1128. end;
  1129.  
  1130. procedure TAudioStream.RecreateBuf;
  1131. var
  1132.   APlaying: Boolean;
  1133.   APosition: Integer;
  1134.   AFrequency: Integer;
  1135.   APan: Integer;
  1136.   AVolume: Integer;
  1137. begin
  1138.   APlaying := Playing;
  1139.      
  1140.   APosition := Position;
  1141.   AFrequency := Frequency;
  1142.   APan := Pan;
  1143.   AVolume := Volume;
  1144.                        
  1145.   SetWaveStream(WaveStream);
  1146.  
  1147.   Position := APosition;
  1148.   Frequency := AFrequency;
  1149.   Pan := APan;
  1150.   Volume := AVolume;
  1151.                  
  1152.   if APlaying then Play;
  1153. end;
  1154.  
  1155. procedure TAudioStream.SetAutoUpdate(Value: Boolean);
  1156. begin
  1157.   if FAutoUpdate<>Value then
  1158.   begin
  1159.     FAutoUpdate := Value;
  1160.     if FPlaying then
  1161.     begin
  1162.       if FNotifyThread<>nil then
  1163.       begin
  1164.         (FNotifyThread as TAudioStreamNotify).FStopOnTerminate := False;
  1165.         FNotifyThread.Free;
  1166.       end;
  1167.  
  1168.       if FAutoUpdate then
  1169.         FNotifyThread := TAudioStreamNotify.Create(Self);
  1170.     end;
  1171.   end;
  1172. end;
  1173.  
  1174. procedure TAudioStream.SetBufferLength(Value: Integer);
  1175. begin
  1176.   if Value<10 then Value := 10;
  1177.   if FBufferLength<>Value then
  1178.   begin
  1179.     FBufferLength := Value;
  1180.     if WaveStream<>nil then RecreateBuf;
  1181.   end;
  1182. end;
  1183.  
  1184. procedure TAudioStream.SetFrequency(Value: Integer);
  1185. begin
  1186.   FBuffer.Frequency := Value;
  1187. end;
  1188.  
  1189. procedure TAudioStream.SetLooped(Value: Boolean);
  1190. begin
  1191.   if FLooped<>Value then
  1192.   begin
  1193.     FLooped := Value;
  1194.     Position := Position;
  1195.   end;
  1196. end;
  1197.  
  1198. procedure TAudioStream.SetPan(Value: Integer);
  1199. begin
  1200.   FBuffer.Pan := Value;
  1201. end;
  1202.  
  1203. procedure TAudioStream.SetPlayedSize(Value: Integer);
  1204. begin
  1205.   if Playing then UpdatePlayedSize;
  1206.   FPlayedSize := Value;
  1207. end;
  1208.  
  1209. procedure TAudioStream.SetPosition(Value: Integer);
  1210. begin
  1211.   if WaveStream=nil then
  1212.     raise EAudioStreamError.Create(SWaveStreamNotSet);
  1213.  
  1214.   Value := Max(Min(Value, Size-1), 0);
  1215.   Value := Value div Format^.nBlockAlign * Format^.nBlockAlign;
  1216.  
  1217.   FPosition := Value;
  1218.  
  1219.   if Playing then
  1220.   begin
  1221.     try
  1222.       FBuffer.Stop;
  1223.  
  1224.       FBufferPos := 0;
  1225.       FPlayBufferPos := 0;
  1226.       FWritePosition := Value;
  1227.  
  1228.       WriteWave(FBufferSize);
  1229.  
  1230.       FBuffer.Position := 0;
  1231.       FBuffer.Play(True);
  1232.     except
  1233.       Stop;
  1234.       raise;
  1235.     end;
  1236.   end;
  1237. end;
  1238.  
  1239. procedure TAudioStream.SetVolume(Value: Integer);
  1240. begin
  1241.   FBuffer.Volume := Value;
  1242. end;
  1243.  
  1244. procedure TAudioStream.SetWaveStream(Value: TCustomWaveStream);
  1245. var
  1246.   BufferDesc: TDSBufferDesc;
  1247. begin
  1248.   Stop;
  1249.  
  1250.   FWaveStream := nil;
  1251.   FBufferPos := 0;
  1252.   FPosition := 0;
  1253.   FWritePosition := 0;
  1254.  
  1255.   if (Value<>nil) and (FBufferLength>0) then
  1256.   begin
  1257.     FBufferSize := FBufferLength * Integer(Value.Format^.nAvgBytesPerSec) div 1000;
  1258.  
  1259.     FillChar(BufferDesc, SizeOf(BufferDesc), 0);
  1260.     with BufferDesc do
  1261.     begin
  1262.       dwSize := SizeOf(TDSBufferDesc);
  1263.       dwFlags := DSBCAPS_CTRLDEFAULT or DSBCAPS_GETCURRENTPOSITION2;
  1264.       if FDSound.FStickyFocus then
  1265.         dwFlags := dwFlags or DSBCAPS_STICKYFOCUS
  1266.       else if FDSound.FGlobalFocus then
  1267.         dwFlags := dwFlags or DSBCAPS_GLOBALFOCUS;
  1268.       dwBufferBytes := FBufferSize;
  1269.       lpwfxFormat := Value.Format;
  1270.     end;
  1271.  
  1272.     if not FBuffer.CreateBuffer(BufferDesc) then
  1273.       raise EDirectSoundBufferError.CreateFmt(SCannotMade, [SDirectSoundBuffer]);
  1274.   end else
  1275.   begin
  1276.     FBuffer.IDSBuffer := nil;
  1277.     FBufferSize := 0;
  1278.   end;
  1279.  
  1280.   FWaveStream := Value;
  1281. end;
  1282.  
  1283. procedure TAudioStream.Stop;
  1284. begin
  1285.   if FPlaying then
  1286.   begin
  1287.     FPlaying := False;
  1288.     FBuffer.Stop;
  1289.     FNotifyThread.Free;
  1290.   end;
  1291. end;
  1292.  
  1293. procedure TAudioStream.Update;
  1294. begin
  1295.   Update2(False);
  1296. end;
  1297.  
  1298. procedure TAudioStream.Update2(InThread: Boolean);
  1299. var
  1300.   WriteSize: Integer;
  1301. begin
  1302.   if not FPlaying then Exit;
  1303.  
  1304.   try
  1305.     UpdatePlayedSize;
  1306.  
  1307.     if Size<0 then
  1308.     begin
  1309.       WriteSize := GetWriteSize;
  1310.       if WriteSize>0 then
  1311.       begin
  1312.         WriteSize := WriteWave(WriteSize);
  1313.         FPosition := FPosition + WriteSize;
  1314.       end;
  1315.     end else
  1316.     begin
  1317.       if FLooped then
  1318.       begin
  1319.         WriteSize := GetWriteSize;
  1320.         if WriteSize>0 then
  1321.         begin
  1322.           WriteWave(WriteSize);
  1323.           FPosition := (FPosition + WriteSize) mod Size;
  1324.         end;
  1325.       end else
  1326.       begin
  1327.         if FPosition<Size then
  1328.         begin
  1329.           WriteSize := GetWriteSize;
  1330.           if WriteSize>0 then
  1331.           begin
  1332.             WriteWave(WriteSize);
  1333.             FPosition := FPosition + WriteSize;
  1334.             if FPosition>Size then FPosition := Size;
  1335.           end;
  1336.         end else
  1337.         begin
  1338.           if InThread then
  1339.             SetEvent(FNotifyEvent)
  1340.           else
  1341.             Stop;
  1342.         end;
  1343.       end;
  1344.     end;
  1345.   except
  1346.     if InThread then
  1347.       SetEvent(FNotifyEvent)
  1348.     else
  1349.       Stop;
  1350.     raise;
  1351.   end;
  1352. end;
  1353.  
  1354. function TAudioStream.WriteWave(WriteSize: Integer): Integer;
  1355.  
  1356.   procedure WriteData(Size: Integer);
  1357.   var
  1358.     Data1, Data2: Pointer;
  1359.     Data1Size, Data2Size: Longint;
  1360.   begin
  1361.     if FBuffer.Lock(FBufferPos, Size, Data1, Data1Size, Data2, Data2Size) then
  1362.     begin
  1363.       try
  1364.         FWaveStream.Position := FWritePosition;
  1365.         FWaveStream.ReadBuffer(Data1^, Data1Size);
  1366.         FWritePosition := FWritePosition + Data1Size;
  1367.  
  1368.         if Data2<>nil then
  1369.         begin
  1370.           FWaveStream.ReadBuffer(Data2^, Data2Size);
  1371.           FWritePosition := FWritePosition + Data2Size;
  1372.         end;
  1373.  
  1374.         FBufferPos := (FBufferPos + DWORD(Data1Size) + DWORD(Data2Size)) mod FBufferSize;
  1375.       finally
  1376.         FBuffer.UnLock;
  1377.       end;
  1378.     end;
  1379.   end;
  1380.  
  1381.   procedure WriteData2(Size: Integer);
  1382.   var
  1383.     Data1, Data2: Pointer;
  1384.     Data1Size, Data2Size, s1, s2: Longint;
  1385.   begin
  1386.     if FBuffer.Lock(FBufferPos, Size, Data1, Data1Size, Data2, Data2Size) then
  1387.     begin
  1388.       try
  1389.         FWaveStream.Position := FWritePosition;
  1390.         s1 := FWaveStream.Read(Data1^, Data1Size);
  1391.         FWritePosition := FWritePosition + s1;
  1392.         FBufferPos := (FBufferPos + DWORD(s1)) mod FBufferSize;
  1393.         Inc(Result, s1);
  1394.  
  1395.         if (Data2<>nil) and (s1=Data1Size) then
  1396.         begin
  1397.           s2 := FWaveStream.Read(Data2^, Data2Size);
  1398.           FWritePosition := FWritePosition + s2;
  1399.           FBufferPos := (FBufferPos + DWORD(s2)) mod FBufferSize;
  1400.           Inc(Result, s2);
  1401.         end;
  1402.       finally
  1403.         FBuffer.UnLock;
  1404.       end;
  1405.     end;
  1406.   end;
  1407.  
  1408.   procedure WriteSilence(Size: Integer);
  1409.   var
  1410.     C: Byte;
  1411.     Data1, Data2: Pointer;
  1412.     Data1Size, Data2Size: Longint;
  1413.   begin
  1414.     if Format^.wBitsPerSample=8 then C := $80 else C := 0;
  1415.  
  1416.     if FBuffer.Lock(FBufferPos, Size, Data1, Data1Size, Data2, Data2Size) then
  1417.     begin
  1418.       try
  1419.         FillChar(Data1^, Data1Size, C);
  1420.  
  1421.         if Data2<>nil then
  1422.           FillChar(Data2^, Data2Size, C);
  1423.       finally
  1424.         FBuffer.UnLock;
  1425.       end;
  1426.       FBufferPos := (FBufferPos + DWORD(Data1Size) + DWORD(Data2Size)) mod FBufferSize;
  1427.       FWritePosition := FWritePosition + Data1Size + Data2Size;
  1428.     end;
  1429.   end;
  1430.  
  1431. var
  1432.   DataSize: Integer;
  1433. begin
  1434.   if Size>=0 then
  1435.   begin
  1436.     Result := WriteSize;
  1437.     if FLooped then
  1438.     begin
  1439.       while WriteSize>0 do
  1440.       begin
  1441.         DataSize := Min(Size-FWritePosition, WriteSize);
  1442.  
  1443.         WriteData(DataSize);
  1444.         FWritePosition := FWritePosition mod Size;
  1445.  
  1446.         Dec(WriteSize, DataSize);
  1447.       end;
  1448.     end else
  1449.     begin
  1450.       DataSize := Size-FWritePosition;
  1451.  
  1452.       if DataSize<=0 then
  1453.       begin
  1454.         WriteSilence(WriteSize);
  1455.       end else
  1456.       if DataSize>=WriteSize then
  1457.       begin
  1458.         WriteData(WriteSize);
  1459.       end else
  1460.       begin
  1461.         WriteData(DataSize);
  1462.         WriteSilence(WriteSize-DataSize);
  1463.       end;
  1464.     end;
  1465.   end else
  1466.   begin
  1467.     Result := 0;
  1468.     WriteData2(WriteSize);
  1469.   end;
  1470. end;
  1471.  
  1472. {  TAudioFileStream  }
  1473.  
  1474. destructor TAudioFileStream.Destroy;
  1475. begin
  1476.   inherited Destroy;
  1477.   FWaveFileStream.Free;
  1478. end;
  1479.  
  1480. procedure TAudioFileStream.SetFileName(const Value: string);
  1481. begin
  1482.   if FFileName=Value then Exit;
  1483.  
  1484.   FFileName := Value;
  1485.  
  1486.   if FWaveFileStream<>nil then
  1487.   begin
  1488.     WaveStream := nil;
  1489.     FWaveFileStream.Free;
  1490.     FWaveFileStream := nil;
  1491.   end;
  1492.  
  1493.   if Value<>'' then
  1494.   begin
  1495.     try
  1496.       FWaveFileStream := TWaveFileStream.Create(Value, fmOpenRead or fmShareDenyWrite);
  1497.       FWaveFileStream.Open(False);
  1498.       WaveStream := FWaveFileStream;
  1499.     except
  1500.       WaveStream := nil;
  1501.       FFileName := '';
  1502.       raise;
  1503.     end;
  1504.   end;
  1505. end;
  1506.  
  1507. {  TSoundCaptureFormats  }
  1508.  
  1509. constructor TSoundCaptureFormats.Create;
  1510. begin
  1511.   inherited Create(TSoundCaptureFormat);
  1512. end;
  1513.  
  1514. function TSoundCaptureFormats.GetItem(Index: Integer): TSoundCaptureFormat;
  1515. begin
  1516.   Result := TSoundCaptureFormat(inherited Items[Index]);
  1517. end;
  1518.  
  1519. function TSoundCaptureFormats.IndexOf(ASamplesPerSec, ABitsPerSample, AChannels: Integer): Integer;
  1520. var
  1521.   i: Integer;
  1522. begin
  1523.   Result := -1;
  1524.   for i:=0 to Count-1 do
  1525.     with Items[i] do
  1526.       if (FSamplesPerSec=ASamplesPerSec) and (FBitsPerSample=ABitsPerSample) and (FChannels=AChannels) then
  1527.       begin
  1528.         Result := i;
  1529.         Break;
  1530.       end;
  1531. end;
  1532.  
  1533. {  TSoundCaptureStream  }
  1534.  
  1535. type
  1536.   TSoundCaptureStreamNotify = class(TThread)
  1537.   private
  1538.     FCapture: TSoundCaptureStream;
  1539.     FSleepTime: Integer;
  1540.     constructor Create(Capture: TSoundCaptureStream);
  1541.     destructor Destroy; override;
  1542.     procedure Execute; override;
  1543.     procedure Update;
  1544.   end;
  1545.  
  1546. constructor TSoundCaptureStreamNotify.Create(Capture: TSoundCaptureStream);
  1547. begin
  1548.   FCapture := Capture;
  1549.  
  1550.   FCapture.FNotifyEvent := CreateEvent(nil, False, False, nil);
  1551.   FSleepTime := Min(FCapture.FBufferLength div 4, 1000 div 20);
  1552.  
  1553.   FreeOnTerminate := True;
  1554.   inherited Create(True);
  1555. end;
  1556.  
  1557. destructor TSoundCaptureStreamNotify.Destroy;
  1558. begin
  1559.   FreeOnTerminate := False;
  1560.   SetEvent(FCapture.FNotifyEvent);
  1561.  
  1562.   inherited Destroy;
  1563.  
  1564.   CloseHandle(FCapture.FNotifyEvent);
  1565.   FCapture.FNotifyThread := nil;
  1566.  
  1567.   if Assigned(FCapture.FOnFilledBuffer) then FCapture.Stop;
  1568. end;
  1569.  
  1570. procedure TSoundCaptureStreamNotify.Execute;
  1571. begin
  1572.   while WaitForSingleObject(FCapture.FNotifyEvent, FSleepTime)=WAIT_TIMEOUT do
  1573.   begin
  1574.     Synchronize(Update);
  1575.   end;
  1576. end;
  1577.  
  1578. procedure TSoundCaptureStreamNotify.Update;
  1579. begin
  1580.   if FCapture.FilledSize>0 then
  1581.   begin
  1582.     try
  1583.       FCapture.DoFilledBuffer;
  1584.     except
  1585.       on E: Exception do
  1586.       begin
  1587.         Application.HandleException(E);
  1588.         SetEvent(FCapture.FNotifyEvent);
  1589.       end;
  1590.     end;
  1591.   end;
  1592. end;
  1593.  
  1594. constructor TSoundCaptureStream.Create(GUID: PGUID);
  1595. const
  1596.   SamplesPerSecList: array[0..6] of Integer = (8000, 11025, 22050, 33075, 44100, 48000, 96000);
  1597.   BitsPerSampleList: array[0..3] of Integer = (8, 16, 24, 32);
  1598.   ChannelsList: array[0..1] of Integer = (1, 2);
  1599. var
  1600.   ASamplesPerSec, ABitsPerSample, AChannels: Integer;
  1601.   dscbd: TDSCBufferDesc;
  1602.   TempBuffer: IDirectSoundCaptureBuffer;
  1603.   Format: TWaveFormatEx;
  1604. begin
  1605.   inherited Create;
  1606.   FBufferLength := 1000;
  1607.   FSupportedFormats := TSoundCaptureFormats.Create;
  1608.  
  1609.   if DXDirectSoundCaptureCreate(GUID, FCapture, nil)<>DS_OK then
  1610.     raise ESoundCaptureStreamError.CreateFmt(SCannotInitialized, [SDirectSoundCapture]);
  1611.  
  1612.   {  The supported format list is acquired.  }
  1613.   for ASamplesPerSec:=Low(SamplesPerSecList) to High(SamplesPerSecList) do
  1614.     for ABitsPerSample:=Low(BitsPerSampleList) to High(BitsPerSampleList) do
  1615.       for AChannels:=Low(ChannelsList) to High(ChannelsList) do
  1616.       begin
  1617.         {  Test  }
  1618.         MakePCMWaveFormatEx(Format, SamplesPerSecList[ASamplesPerSec], BitsPerSampleList[ABitsPerSample], ChannelsList[AChannels]);
  1619.  
  1620.         FillChar(dscbd, SizeOf(dscbd), 0);
  1621.         dscbd.dwSize := SizeOf(dscbd);
  1622.         dscbd.dwBufferBytes := Format.nAvgBytesPerSec;
  1623.         dscbd.lpwfxFormat := @Format;
  1624.  
  1625.         {  If the buffer can be made,  the format of present can be used.  }
  1626.         if FCapture.CreateCaptureBuffer(dscbd, TempBuffer, nil)=DS_OK then
  1627.         begin
  1628.           TempBuffer := nil;
  1629.           with TSoundCaptureFormat.Create(FSupportedFormats) do
  1630.           begin
  1631.             FSamplesPerSec := Format.nSamplesPerSec;
  1632.             FBitsPerSample := Format.wBitsPerSample;
  1633.             FChannels := Format.nChannels;
  1634.           end;
  1635.         end;
  1636.       end;
  1637. end;
  1638.  
  1639. destructor TSoundCaptureStream.Destroy;
  1640. begin
  1641.   Stop;
  1642.   FSupportedFormats.Free;
  1643.   inherited Destroy;
  1644. end;
  1645.  
  1646. procedure TSoundCaptureStream.DoFilledBuffer;
  1647. begin
  1648.   if Assigned(FOnFilledBuffer) then FOnFilledBuffer(Self);
  1649. end;
  1650.  
  1651. class function TSoundCaptureStream.Drivers: TDirectXDrivers;
  1652. begin
  1653.   Result := EnumDirectSoundCaptureDrivers;
  1654. end;
  1655.  
  1656. function TSoundCaptureStream.GetFilledSize: Integer;
  1657. begin
  1658.   Result := GetReadSize;
  1659. end;
  1660.  
  1661. function TSoundCaptureStream.GetReadSize: Integer;
  1662. var
  1663.   CapturePosition, ReadPosition: DWORD;
  1664. begin
  1665.   if FBuffer.GetCurrentPosition(CapturePosition, ReadPosition)=DS_OK then
  1666.   begin
  1667.     if FBufferPos<=ReadPosition then
  1668.       Result := ReadPosition - FBufferPos
  1669.     else
  1670.       Result := FBufferSize - FBufferPos + ReadPosition;
  1671.   end else
  1672.     Result := 0;
  1673. end;
  1674.  
  1675. function TSoundCaptureStream.ReadWave(var Buffer; Count: Integer): Integer;
  1676. var
  1677.   Size: Integer;
  1678.   Data1, Data2: Pointer;
  1679.   Data1Size, Data2Size: DWORD;
  1680.   C: Byte;
  1681. begin
  1682.   if not FCapturing then
  1683.     Start;
  1684.  
  1685.   Result := 0;
  1686.   while Result<Count do
  1687.   begin
  1688.     Size := Min(Count-Result, GetReadSize);
  1689.     if Size>0 then
  1690.     begin
  1691.       if FBuffer.Lock(FBufferPos, Size, Data1, Data1Size, Data2, Data2Size, 0)=DS_OK then
  1692.       begin
  1693.         Move(Data1^, Pointer(Integer(@Buffer)+Result)^, Data1Size);
  1694.         Result := Result + Integer(Data1Size);
  1695.  
  1696.         if Data2<>nil then
  1697.         begin
  1698.           Move(Data2^, Pointer(Integer(@Buffer)+Result)^, Data2Size);
  1699.           Result := Result + Integer(Data1Size);
  1700.         end;
  1701.  
  1702.         FBuffer.UnLock(Data1, Data1Size, Data2, Data2Size);
  1703.         FBufferPos := (FBufferPos + Data1Size + Data2Size) mod FBufferSize;
  1704.       end else
  1705.         Break;
  1706.     end;
  1707.     if Result<Count then Sleep(50);
  1708.   end;
  1709.  
  1710.   case Format^.wBitsPerSample of
  1711.      8: C := $80;
  1712.     16: C := $00;
  1713.   else
  1714.     C := $00;
  1715.   end;
  1716.  
  1717.   FillChar(Pointer(Integer(@Buffer)+Result)^, Count-Result, C);
  1718.   Result := Count;
  1719. end;
  1720.  
  1721. procedure TSoundCaptureStream.SetBufferLength(Value: Integer);
  1722. begin
  1723.   FBufferLength := Max(Value, 0);
  1724. end;
  1725.  
  1726. procedure TSoundCaptureStream.SetOnFilledBuffer(Value: TNotifyEvent);
  1727. begin
  1728.   if CompareMem(@TMethod(FOnFilledBuffer), @TMethod(Value), SizeOf(TMethod)) then Exit;
  1729.  
  1730.   if FCapturing then
  1731.   begin
  1732.     if Assigned(FOnFilledBuffer) then
  1733.       FNotifyThread.Free;
  1734.  
  1735.     FOnFilledBuffer := Value;
  1736.  
  1737.     if Assigned(FOnFilledBuffer) then
  1738.     begin
  1739.       FNotifyThread := TSoundCaptureStreamNotify.Create(Self);
  1740.       FNotifyThread.Resume;
  1741.     end;
  1742.   end else
  1743.     FOnFilledBuffer := Value;
  1744. end;
  1745.  
  1746. procedure TSoundCaptureStream.Start;
  1747. var
  1748.   dscbd: TDSCBufferDesc;
  1749. begin
  1750.   Stop;
  1751.   try
  1752.     FCapturing := True;
  1753.  
  1754.     FormatSize := SizeOf(TWaveFormatEx);
  1755.     with FSupportedFormats[CaptureFormat] do
  1756.       MakePCMWaveFormatEx(Format^, SamplesPerSec, BitsPerSample, Channels);
  1757.  
  1758.     FBufferSize := Max(MulDiv(Format^.nAvgBytesPerSec, FBufferLength, 1000), 8000);
  1759.  
  1760.     FillChar(dscbd, SizeOf(dscbd), 0);
  1761.     dscbd.dwSize := SizeOf(dscbd);
  1762.     dscbd.dwBufferBytes := FBufferSize;
  1763.     dscbd.lpwfxFormat := Format;
  1764.  
  1765.     if FCapture.CreateCaptureBuffer(dscbd, FBuffer, nil)<>DS_OK then
  1766.       raise ESoundCaptureStreamError.CreateFmt(SCannotMade, [SDirectSoundCaptureBuffer]);
  1767.  
  1768.     FBufferPos := 0;
  1769.  
  1770.     FBuffer.Start(DSCBSTART_LOOPING);
  1771.  
  1772.     if Assigned(FOnFilledBuffer) then
  1773.     begin
  1774.       FNotifyThread := TSoundCaptureStreamNotify.Create(Self);
  1775.       FNotifyThread.Resume;
  1776.     end;
  1777.   except
  1778.     Stop;
  1779.     raise;
  1780.   end;
  1781. end;
  1782.  
  1783. procedure TSoundCaptureStream.Stop;
  1784. begin
  1785.   if FCapturing then
  1786.   begin
  1787.     FNotifyThread.Free;
  1788.     FCapturing := False;
  1789.     if FBuffer<>nil then
  1790.       FBuffer.Stop;
  1791.     FBuffer := nil;
  1792.   end;
  1793. end;
  1794.  
  1795. {  TSoundEngine  }
  1796.  
  1797. constructor TSoundEngine.Create(ADSound: TDirectSound);
  1798. begin
  1799.   inherited Create;
  1800.   FDSound := ADSound;
  1801.   FEnabled := True;
  1802.  
  1803.  
  1804.   FEffectList := TList.Create;
  1805.   FTimer := TTimer.Create(nil);
  1806.   FTimer.Interval := 500;
  1807.   FTimer.OnTimer := TimerEvent;
  1808. end;
  1809.  
  1810. destructor TSoundEngine.Destroy;
  1811. begin
  1812.   Clear;
  1813.   FTimer.Free;
  1814.   FEffectList.Free;
  1815.   inherited Destroy;
  1816. end;
  1817.  
  1818. procedure TSoundEngine.Clear;
  1819. var
  1820.   i: Integer;
  1821. begin
  1822.   for i:=EffectCount-1 downto 0 do
  1823.     Effects[i].Free;
  1824.   FEffectList.Clear;
  1825. end;
  1826.  
  1827. procedure TSoundEngine.EffectFile(const Filename: string; Loop, Wait: Boolean);
  1828. var
  1829.   Stream : TFileStream;
  1830. begin
  1831.   Stream :=TFileStream.Create(Filename, fmOpenRead);
  1832.   try
  1833.     EffectStream(Stream, Loop, Wait);
  1834.   finally
  1835.     Stream.Free;
  1836.   end;
  1837. end;
  1838.  
  1839. procedure TSoundEngine.EffectStream(Stream: TStream; Loop, Wait: Boolean);
  1840. var
  1841.   Wave: TWave;
  1842. begin
  1843.   Wave := TWave.Create;
  1844.   try
  1845.     Wave.LoadfromStream(Stream);
  1846.     EffectWave(Wave, Loop, Wait);
  1847.   finally
  1848.     Wave.Free;
  1849.   end;
  1850. end;
  1851.  
  1852. procedure TSoundEngine.EffectWave(Wave: TWave; Loop, Wait: Boolean);
  1853. var
  1854.   Buffer: TDirectSoundBuffer;
  1855. begin
  1856.   if not FEnabled then Exit;
  1857.  
  1858.   if Wait then
  1859.   begin
  1860.     Buffer := TDirectSoundBuffer.Create(FDSound);
  1861.     try
  1862.       Buffer.LoadFromWave(Wave);
  1863.       Buffer.Play(False);
  1864.       while Buffer.Playing do
  1865.         Sleep(1);
  1866.     finally
  1867.       Buffer.Free;
  1868.     end;
  1869.   end else
  1870.   begin
  1871.     Buffer := TDirectSoundBuffer.Create(FDSound);
  1872.     try
  1873.       Buffer.LoadFromWave(Wave);
  1874.       Buffer.Play(Loop);
  1875.     except
  1876.       Buffer.Free;
  1877.       raise;
  1878.     end;
  1879.     FEffectList.Add(Buffer);
  1880.   end;
  1881. end;
  1882.  
  1883. function TSoundEngine.GetEffect(Index: Integer): TDirectSoundBuffer;
  1884. begin
  1885.   Result := TDirectSoundBuffer(FEffectList[Index]);
  1886. end;
  1887.  
  1888. function TSoundEngine.GetEffectCount: Integer;
  1889. begin
  1890.   Result := FEffectList.Count;
  1891. end;
  1892.  
  1893. procedure TSoundEngine.SetEnabled(Value: Boolean);
  1894. var
  1895.   i: Integer;
  1896. begin
  1897.   for i:=EffectCount-1 downto 0 do
  1898.     Effects[i].Free;
  1899.   FEffectList.Clear;
  1900.  
  1901.   FEnabled := Value;
  1902.   FTimer.Enabled := Value;
  1903. end;
  1904.  
  1905. procedure TSoundEngine.TimerEvent(Sender: TObject);
  1906. var
  1907.   i: Integer;
  1908. begin
  1909.   for i:=EffectCount-1 downto 0 do
  1910.     if not TDirectSoundBuffer(FEffectList[i]).Playing then
  1911.     begin
  1912.       TDirectSoundBuffer(FEffectList[i]).Free;
  1913.       FEffectList.Delete(i);
  1914.     end;
  1915. end;
  1916.  
  1917. {  TCustomDXSound  }
  1918.  
  1919. type
  1920.   TDXSoundDirectSound = class(TDirectSound)
  1921.   private
  1922.     FDXSound: TCustomDXSound;
  1923.   protected
  1924.     procedure DoRestoreBuffer; override;
  1925.   end;
  1926.  
  1927. procedure TDXSoundDirectSound.DoRestoreBuffer;
  1928. begin
  1929.   inherited DoRestoreBuffer;
  1930.   FDXSound.Restore;
  1931. end;
  1932.  
  1933. constructor TCustomDXSound.Create(AOwner: TComponent);
  1934. begin
  1935.   FNotifyEventList := TList.Create;
  1936.   inherited Create(AOwner);
  1937.   FAutoInitialize := True;
  1938.   Options := [];
  1939. end;
  1940.  
  1941. destructor TCustomDXSound.Destroy;
  1942. begin
  1943.   Finalize;
  1944.   NotifyEventList(dsntDestroying);
  1945.   FNotifyEventList.Free;
  1946.   inherited Destroy;
  1947. end;
  1948.  
  1949. type
  1950.   PDXSoundNotifyEvent = ^TDXSoundNotifyEvent;
  1951.  
  1952. procedure TCustomDXSound.RegisterNotifyEvent(NotifyEvent: TDXSoundNotifyEvent);
  1953. var
  1954.   Event: PDXSoundNotifyEvent;
  1955. begin
  1956.   UnRegisterNotifyEvent(NotifyEvent);
  1957.  
  1958.   New(Event);
  1959.   Event^ := NotifyEvent;
  1960.   FNotifyEventList.Add(Event);
  1961.  
  1962.   if Initialized then
  1963.   begin
  1964.     NotifyEvent(Self, dsntInitialize);
  1965.     NotifyEvent(Self, dsntRestore);
  1966.   end;
  1967. end;
  1968.  
  1969. procedure TCustomDXSound.UnRegisterNotifyEvent(NotifyEvent: TDXSoundNotifyEvent);
  1970. var
  1971.   Event: PDXSoundNotifyEvent;
  1972.   i: Integer;
  1973. begin
  1974.   for i:=0 to FNotifyEventList.Count-1 do
  1975.   begin
  1976.     Event := FNotifyEventList[i];
  1977.     if (TMethod(Event^).Code = TMethod(NotifyEvent).Code) and
  1978.       (TMethod(Event^).Data = TMethod(NotifyEvent).Data) then
  1979.     begin
  1980.       Dispose(Event);
  1981.       FNotifyEventList.Delete(i);
  1982.  
  1983.       if Initialized then
  1984.         NotifyEvent(Self, dsntFinalize);
  1985.  
  1986.       Break;
  1987.     end;
  1988.   end;
  1989. end;
  1990.  
  1991. procedure TCustomDXSound.NotifyEventList(NotifyType: TDXSoundNotifyType);
  1992. var
  1993.   i: Integer;
  1994. begin
  1995.   for i:=FNotifyEventList.Count-1 downto 0 do
  1996.     PDXSoundNotifyEvent(FNotifyEventList[i])^(Self, NotifyType);
  1997. end;
  1998.  
  1999. procedure TCustomDXSound.FormWndProc(var Message: TMessage; DefWindowProc: TWndMethod);
  2000. begin
  2001.   case Message.Msg of
  2002.     WM_CREATE:
  2003.         begin
  2004.           DefWindowProc(Message);
  2005.           SetForm(FForm);
  2006.           Exit;
  2007.         end;
  2008.   end;
  2009.   DefWindowProc(Message);
  2010. end;
  2011.  
  2012. class function TCustomDXSound.Drivers: TDirectXDrivers;
  2013. begin
  2014.   Result := EnumDirectSoundDrivers;
  2015. end;
  2016.  
  2017. procedure TCustomDXSound.DoFinalize;
  2018. begin
  2019.   if Assigned(FOnFinalize) then FOnFinalize(Self);
  2020. end;
  2021.  
  2022. procedure TCustomDXSound.DoInitialize;
  2023. begin
  2024.   if Assigned(FOnInitialize) then FOnInitialize(Self);
  2025. end;
  2026.  
  2027. procedure TCustomDXSound.DoInitializing;
  2028. begin
  2029.   if Assigned(FOnInitializing) then FOnInitializing(Self);
  2030. end;
  2031.  
  2032. procedure TCustomDXSound.DoRestore;
  2033. begin
  2034.   if Assigned(FOnRestore) then FOnRestore(Self);
  2035. end;
  2036.  
  2037. procedure TCustomDXSound.Finalize;
  2038. begin
  2039.   if FInternalInitialized then
  2040.   begin
  2041.     try
  2042.       FSubClass.Free; FSubClass := nil;
  2043.  
  2044.       try
  2045.         if FCalledDoInitialize then
  2046.         begin
  2047.           FCalledDoInitialize := False;
  2048.           DoFinalize;
  2049.         end;
  2050.       finally
  2051.         NotifyEventList(dsntFinalize);
  2052.       end;
  2053.     finally
  2054.       FInitialized := False;
  2055.       FInternalInitialized := False;
  2056.  
  2057.       SetOptions(FOptions);
  2058.  
  2059.       FPrimary.Free; FPrimary := nil;
  2060.       FDSound.Free;  FDSound := nil;
  2061.     end;
  2062.   end;
  2063. end;
  2064.  
  2065. procedure TCustomDXSound.Initialize;
  2066. const
  2067.   PrimaryDesc: TDSBufferDesc = (
  2068.       dwSize: SizeOf (PrimaryDesc);
  2069.       dwFlags: DSBCAPS_PRIMARYBUFFER);
  2070. var
  2071.   Component: TComponent;
  2072. begin
  2073.   Finalize;
  2074.  
  2075.   Component := Owner;
  2076.   while (Component<>nil) and (not (Component is TCustomForm)) do
  2077.     Component := Component.Owner;
  2078.   if Component=nil then
  2079.     raise EDXSoundError.Create(SNoForm);
  2080.  
  2081.   NotifyEventList(dsntInitializing);
  2082.   DoInitializing;
  2083.  
  2084.   FInternalInitialized := True;
  2085.   try
  2086.     {  DirectSound initialization.  }
  2087.     FDSound := TDXSoundDirectSound.Create(Driver);
  2088.     TDXSoundDirectSound(FDSound).FDXSound := Self;
  2089.  
  2090.     FDSound.FGlobalFocus := soGlobalFocus in FNowOptions;
  2091.  
  2092.     {  Primary buffer made.  }
  2093.     FPrimary := TDirectSoundBuffer.Create(FDSound);
  2094.     if not FPrimary.CreateBuffer(PrimaryDesc) then
  2095.       raise EDXSoundError.CreateFmt(SCannotMade, [SDirectSoundPrimaryBuffer]);
  2096.  
  2097.     FInitialized := True;
  2098.  
  2099.     SetForm(TCustomForm(Component));
  2100.   except
  2101.     Finalize;
  2102.     raise;
  2103.   end;
  2104.  
  2105.   NotifyEventList(dsntInitialize);
  2106.  
  2107.   FCalledDoInitialize := True; DoInitialize;
  2108.  
  2109.   Restore;
  2110. end;
  2111.  
  2112. procedure TCustomDXSound.Loaded;
  2113. begin
  2114.   inherited Loaded;
  2115.  
  2116.   if FAutoInitialize and (not (csDesigning in ComponentState)) then
  2117.   begin
  2118.     try
  2119.       Initialize;
  2120.     except
  2121.       on E: EDirectSoundError do ;
  2122.       else raise;
  2123.     end;
  2124.   end;
  2125. end;
  2126.  
  2127. procedure TCustomDXSound.Restore;
  2128. begin
  2129.   if FInitialized then
  2130.   begin
  2131.     NotifyEventList(dsntRestore);
  2132.     DoRestore;
  2133.   end;
  2134. end;
  2135.  
  2136. procedure TCustomDXSound.SetDriver(Value: PGUID);
  2137. begin
  2138.   if not IsBadHugeReadPtr(Value, SizeOf(TGUID)) then
  2139.   begin
  2140.     FDriverGUID := Value^;
  2141.     FDriver := @FDriverGUID;
  2142.   end else
  2143.     FDriver := Value;
  2144. end;
  2145.  
  2146. procedure TCustomDXSound.SetForm(Value: TCustomForm);
  2147. var
  2148.   Level: Integer;
  2149. begin
  2150.   FForm := Value;
  2151.  
  2152.   FSubClass.Free;
  2153.   FSubClass := TControlSubClass.Create(FForm, FormWndProc);
  2154.  
  2155.   if FInitialized then
  2156.   begin
  2157.     if soExclusive in FNowOptions then
  2158.       Level := DSSCL_EXCLUSIVE
  2159.     else
  2160.       Level := DSSCL_NORMAL;
  2161.  
  2162.     FDSound.DXResult := FDSound.ISound.SetCooperativeLevel(FForm.Handle, Level);
  2163.   end;
  2164. end;
  2165.  
  2166. procedure TCustomDXSound.SetOptions(Value: TDXSoundOptions);
  2167. const
  2168.   DXSoundOptions = [soGlobalFocus, soStickyFocus, soExclusive];
  2169.   InitOptions: TDXSoundOptions = [soExclusive];
  2170. var
  2171.   OldOptions: TDXSoundOptions;
  2172. begin
  2173.   FOptions := Value;
  2174.  
  2175.   if Initialized then
  2176.   begin
  2177.     OldOptions := FNowOptions;
  2178.  
  2179.     FNowOptions := (FNowOptions - (DXSoundOptions - InitOptions)) +
  2180.       (Value - InitOptions);
  2181.  
  2182.     FDSound.FGlobalFocus := soGlobalFocus in FNowOptions;
  2183.     FDSound.FStickyFocus := soStickyFocus in FNowOptions;
  2184.   end else
  2185.     FNowOptions := FOptions;
  2186. end;
  2187.  
  2188. {  TWaveCollectionItem  }
  2189.  
  2190. constructor TWaveCollectionItem.Create(Collection: TCollection);
  2191. begin
  2192.   inherited Create(Collection);
  2193.   FWave := TWave.Create;
  2194.   FBufferList := TList.Create;
  2195. end;
  2196.  
  2197. destructor TWaveCollectionItem.Destroy;
  2198. begin
  2199.   Finalize;
  2200.   FWave.Free;
  2201.   FBufferList.Free;
  2202.   inherited Destroy;
  2203. end;
  2204.  
  2205. procedure TWaveCollectionItem.Assign(Source: TPersistent);
  2206. var
  2207.   PrevInitialized: Boolean;
  2208. begin
  2209.   if Source is TWaveCollectionItem then
  2210.   begin
  2211.     PrevInitialized := Initialized;
  2212.     Finalize;
  2213.  
  2214.     FLooped := TWaveCollectionItem(Source).FLooped;
  2215.     Name := TWaveCollectionItem(Source).Name;
  2216.     FMaxPlayingCount := TWaveCollectionItem(Source).FMaxPlayingCount;
  2217.  
  2218.     FFrequency := TWaveCollectionItem(Source).FFrequency;
  2219.     FPan := TWaveCollectionItem(Source).FPan;
  2220.     FVolume := TWaveCollectionItem(Source).FVolume;
  2221.  
  2222.     FWave.Assign(TWaveCollectionItem(Source).FWave);
  2223.  
  2224.     if PrevInitialized then
  2225.       Restore;
  2226.   end else
  2227.     inherited Assign(Source);
  2228. end;                        
  2229.  
  2230. function TWaveCollectionItem.GetBuffer: TDirectSoundBuffer;
  2231. begin
  2232.   if FInitialized and (FBuffer=nil) then
  2233.     Restore;
  2234.   Result := FBuffer;
  2235. end;
  2236.  
  2237. function TWaveCollectionItem.GetWaveCollection: TWaveCollection;
  2238. begin
  2239.   Result := Collection as TWaveCollection;
  2240. end;
  2241.  
  2242. procedure TWaveCollectionItem.Finalize;
  2243. var
  2244.   i: Integer;
  2245. begin
  2246.   if not FInitialized then Exit;
  2247.   FInitialized := False;
  2248.  
  2249.   for i:=0 to FBufferList.Count-1 do
  2250.     TDirectSoundBuffer(FBufferList[i]).Free;
  2251.   FBufferList.Clear;
  2252.   FBuffer.Free; FBuffer := nil;
  2253. end;
  2254.  
  2255. procedure TWaveCollectionItem.Initialize;
  2256. begin
  2257.   Finalize;
  2258.   FInitialized := WaveCollection.Initialized;
  2259. end;
  2260.  
  2261. function TWaveCollectionItem.CreateBuffer: TDirectSoundBuffer;
  2262. begin
  2263.   Result := nil;
  2264.   if GetBuffer=nil then Exit;
  2265.  
  2266.   Result := TDirectSoundBuffer.Create(WaveCollection.DXSound.DSound);
  2267.   try
  2268.     Result.Assign(GetBuffer);
  2269.   except
  2270.     Result.Free;
  2271.     raise;
  2272.   end;
  2273. end;
  2274.  
  2275. procedure TWaveCollectionItem.Play(Wait: Boolean);
  2276. var
  2277.   NewBuffer: TDirectSoundBuffer;
  2278.   i: Integer;
  2279. begin
  2280.   if not FInitialized then Exit;
  2281.  
  2282.   if FLooped then
  2283.   begin
  2284.     GetBuffer.Stop;
  2285.     GetBuffer.Position := 0;
  2286.     GetBuffer.Play(True);
  2287.   end else
  2288.   begin
  2289.     NewBuffer := nil;
  2290.     for i:=0 to FBufferList.Count-1  do
  2291.       if not TDirectSoundBuffer(FBufferList[i]).Playing then
  2292.       begin
  2293.         NewBuffer := FBufferList[i];
  2294.         Break;
  2295.       end;
  2296.                  
  2297.     if NewBuffer=nil then
  2298.     begin
  2299.       if FMaxPlayingCount=0 then
  2300.       begin
  2301.         NewBuffer := CreateBuffer;
  2302.         if NewBuffer=nil then Exit;
  2303.  
  2304.         FBufferList.Add(NewBuffer);
  2305.       end else
  2306.       begin
  2307.         if FBufferList.Count<FMaxPlayingCount then
  2308.         begin
  2309.           NewBuffer := CreateBuffer;
  2310.           if NewBuffer=nil then Exit;
  2311.  
  2312.           FBufferList.Add(NewBuffer);
  2313.         end else
  2314.         begin
  2315.           NewBuffer := FBufferList[0];
  2316.           FBufferList.Move(0, FBufferList.Count-1);
  2317.         end;
  2318.       end;
  2319.     end;
  2320.  
  2321.     NewBuffer.Stop;
  2322.     NewBuffer.Position := 0;
  2323.     NewBuffer.Frequency := FFrequency;
  2324.     NewBuffer.Pan := FPan;
  2325.     NewBuffer.Volume := FVolume;
  2326.     NewBuffer.Play(False);
  2327.  
  2328.     if Wait then
  2329.     begin
  2330.       while NewBuffer.Playing do
  2331.         Sleep(10);
  2332.     end;
  2333.   end;
  2334. end;
  2335.  
  2336. procedure TWaveCollectionItem.Restore;
  2337. begin
  2338.   if FWave.Size=0 then Exit;
  2339.  
  2340.   if not FInitialized then
  2341.   begin
  2342.     if WaveCollection.Initialized then
  2343.       Initialize;
  2344.     if not FInitialized then Exit;
  2345.   end;
  2346.  
  2347.   if FBuffer=nil then
  2348.     FBuffer := TDirectSoundBuffer.Create(WaveCollection.DXSound.DSound);
  2349.  
  2350.   FBuffer.LoadFromWave(FWave);
  2351.   FBuffer.Frequency := FFrequency;
  2352.   FBuffer.Pan := FPan;
  2353.   FBuffer.Volume := FVolume;
  2354. end;
  2355.  
  2356. procedure TWaveCollectionItem.Stop;
  2357. var
  2358.   i: Integer;
  2359. begin
  2360.   if not FInitialized then Exit;
  2361.  
  2362.   FBuffer.Stop;
  2363.   for i:=0 to FBufferList.Count-1  do
  2364.     TDirectSoundBuffer(FBufferList[i]).Stop;
  2365. end;
  2366.  
  2367. procedure TWaveCollectionItem.SetFrequency(Value: Integer);
  2368. begin
  2369.   FFrequency := Value;
  2370.   if FInitialized then
  2371.     GetBuffer.Frequency := Value;
  2372. end;
  2373.  
  2374. procedure TWaveCollectionItem.SetLooped(Value: Boolean);
  2375. begin
  2376.   if FLooped<>Value then
  2377.   begin
  2378.     Stop;
  2379.     FLooped := Value;
  2380.   end;
  2381. end;
  2382.  
  2383. procedure TWaveCollectionItem.SetMaxPlayingCount(Value: Integer);
  2384. var
  2385.   i: Integer;
  2386. begin
  2387.   if Value<0 then Value := 0;
  2388.  
  2389.   if FMaxPlayingCount<>Value then
  2390.   begin
  2391.     FMaxPlayingCount := Value;
  2392.  
  2393.     if FInitialized then
  2394.     begin
  2395.       for i:=0 to FBufferList.Count-1 do
  2396.         TDirectSoundBuffer(FBufferList[i]).Free;
  2397.       FBufferList.Clear;
  2398.     end;
  2399.   end;
  2400. end;
  2401.  
  2402. procedure TWaveCollectionItem.SetPan(Value: Integer);
  2403. begin
  2404.   FPan := Value;
  2405.   if FInitialized then
  2406.     GetBuffer.Pan := Value;
  2407. end;
  2408.  
  2409. procedure TWaveCollectionItem.SetVolume(Value: Integer);
  2410. begin
  2411.   FVolume := Value;
  2412.   if FInitialized then
  2413.     GetBuffer.Volume := Value;
  2414. end;
  2415.  
  2416. procedure TWaveCollectionItem.SetWave(Value: TWave);
  2417. begin
  2418.   FWave.Assign(Value);
  2419. end;
  2420.  
  2421. {  TWaveCollection  }
  2422.  
  2423. constructor TWaveCollection.Create(AOwner: TPersistent);
  2424. begin
  2425.   inherited Create(TWaveCollectionItem);
  2426.   FOwner := AOwner;
  2427. end;
  2428.  
  2429. function TWaveCollection.GetItem(Index: Integer): TWaveCollectionItem;
  2430. begin
  2431.   Result := TWaveCollectionItem(inherited Items[Index]);
  2432. end;
  2433.  
  2434. function TWaveCollection.GetOwner: TPersistent;
  2435. begin
  2436.   Result := FOwner;
  2437. end;
  2438.  
  2439. function TWaveCollection.Find(const Name: string): TWaveCollectionItem;
  2440. var
  2441.   i: Integer;
  2442. begin
  2443.   i := IndexOf(Name);
  2444.   if i=-1 then
  2445.     raise EWaveCollectionError.CreateFmt(SWaveNotFound, [Name]);
  2446.   Result := Items[i];
  2447. end;
  2448.  
  2449. procedure TWaveCollection.Finalize;
  2450. var
  2451.   i: Integer;
  2452. begin
  2453.   for i:=0 to Count-1 do
  2454.     Items[i].Finalize;
  2455.   FDXSound := nil;
  2456. end;
  2457.  
  2458. procedure TWaveCollection.Initialize(DXSound: TCustomDXSound);
  2459. var
  2460.   i: Integer;
  2461. begin
  2462.   Finalize;
  2463.   FDXSound := DXSound;
  2464.   for i:=0 to Count-1 do
  2465.     Items[i].Initialize;
  2466. end;
  2467.  
  2468. function TWaveCollection.Initialized: Boolean;
  2469. begin
  2470.   Result := (FDXSound<>nil) and (FDXSound.Initialized);
  2471. end;
  2472.  
  2473. procedure TWaveCollection.Restore;
  2474. var
  2475.   i: Integer;
  2476. begin
  2477.   for i:=0 to Count-1 do
  2478.     Items[i].Restore;
  2479. end;
  2480.  
  2481. type
  2482.   TWaveCollectionComponent = class(TComponent)
  2483.   private
  2484.     FList: TWaveCollection;
  2485.   published
  2486.     property List: TWaveCollection read FList write FList;
  2487.   end;
  2488.  
  2489. procedure TWaveCollection.LoadFromFile(const FileName: string);
  2490. var
  2491.   Stream: TFileStream;
  2492. begin
  2493.   Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  2494.   try
  2495.     LoadFromStream(Stream);
  2496.   finally
  2497.     Stream.Free;
  2498.   end;
  2499. end;
  2500.  
  2501. procedure TWaveCollection.LoadFromStream(Stream: TStream);
  2502. var
  2503.   Component: TWaveCollectionComponent;
  2504. begin
  2505.   Clear;
  2506.   Component := TWaveCollectionComponent.Create(nil);
  2507.   try
  2508.     Component.FList := Self;
  2509.     Stream.ReadComponentRes(Component);
  2510.  
  2511.     if Initialized then
  2512.     begin
  2513.       Initialize(FDXSound);
  2514.       Restore;
  2515.     end;
  2516.   finally
  2517.     Component.Free;
  2518.   end;
  2519. end;
  2520.  
  2521. procedure TWaveCollection.SaveToFile(const FileName: string);
  2522. var
  2523.   Stream: TFileStream;
  2524. begin
  2525.   Stream := TFileStream.Create(FileName, fmCreate);
  2526.   try
  2527.     SaveToStream(Stream);
  2528.   finally
  2529.     Stream.Free;
  2530.   end;
  2531. end;
  2532.  
  2533. procedure TWaveCollection.SaveToStream(Stream: TStream);
  2534. var
  2535.   Component: TWaveCollectionComponent;
  2536. begin
  2537.   Component := TWaveCollectionComponent.Create(nil);
  2538.   try
  2539.     Component.FList := Self;
  2540.     Stream.WriteComponentRes('DelphiXWaveCollection', Component);
  2541.   finally
  2542.     Component.Free;
  2543.   end;
  2544. end;
  2545.  
  2546. {  TCustomDXWaveList  }
  2547.  
  2548. constructor TCustomDXWaveList.Create(AOwner: TComponent);
  2549. begin
  2550.   inherited Create(AOwner);
  2551.   FItems := TWaveCollection.Create(Self);
  2552. end;
  2553.  
  2554. destructor TCustomDXWaveList.Destroy;
  2555. begin
  2556.   DXSound := nil;
  2557.   FItems.Free;
  2558.   inherited Destroy;
  2559. end;
  2560.  
  2561. procedure TCustomDXWaveList.Notification(AComponent: TComponent; Operation: TOperation);
  2562. begin
  2563.   inherited Notification(AComponent, Operation);
  2564.   if (Operation=opRemove) and (DXSound=AComponent) then
  2565.     DXSound := nil;
  2566. end;
  2567.  
  2568. procedure TCustomDXWaveList.DXSoundNotifyEvent(Sender: TCustomDXSound;
  2569.   NotifyType: TDXSoundNotifyType);
  2570. begin
  2571.   case NotifyType of
  2572.     dsntDestroying: DXSound := nil;
  2573.     dsntInitialize: FItems.Initialize(Sender);
  2574.     dsntFinalize  : FItems.Finalize;
  2575.     dsntRestore   : FItems.Restore;
  2576.   end;
  2577. end;
  2578.  
  2579. procedure TCustomDXWaveList.SetDXSound(Value: TCustomDXSound);
  2580. begin
  2581.   if FDXSound<>nil then
  2582.     FDXSound.UnRegisterNotifyEvent(DXSoundNotifyEvent);
  2583.  
  2584.   FDXSound := Value;
  2585.  
  2586.   if FDXSound<>nil then
  2587.     FDXSound.RegisterNotifyEvent(DXSoundNotifyEvent);
  2588. end;
  2589.  
  2590. procedure TCustomDXWaveList.SetItems(Value: TWaveCollection);
  2591. begin
  2592.   FItems.Assign(Value);
  2593. end;
  2594.  
  2595. initialization
  2596. finalization
  2597.   DirectSoundDrivers.Free;
  2598.   DirectSoundCaptureDrivers.Free;
  2599. end.
  2600.