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

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: 15.09.98 - 16:09:44 $                                        =}
  24. {========================================================================}
  25. unit MMDSPObj;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29. {$IFDEF WIN32}
  30.     Windows,
  31. {$ELSE}
  32.     WinTypes,
  33.     WinProcs,
  34. {$ENDIF}
  35.     SysUtils,
  36.     Messages,
  37.     Classes,
  38.     Controls,
  39.     Forms,
  40.     MMSystem,
  41.     MMObj,
  42.     MMRegs,
  43.     MMWaveIO,
  44.     MMUtils,
  45.     MMString;
  46. const
  47.    QUEUE_READ_SIZE : Longint = 2*32768; { used for queue-auto-read operations  }
  48.    QUEUE_WRITE_SIZE: Longint = 2*32768; { used for queue-auto-write operations }
  49. type
  50.    TMMBufferEvent     = procedure(Sender: TObject; lpWaveHdr: PWaveHdr) of object;
  51.    TMMBufferLoadEvent = procedure(Sender: TObject; lpWaveHdr: PWaveHdr; var MoreBuffers: Boolean) of object;
  52.    TMMPort            = (poInput,poOutput);
  53.    TPropString        = string[20];
  54.    {$IFDEF WIN32}
  55.    {-- TMMDSPThread -----------------------------------------------------------}
  56.    TMMDSPThread = class(TMMThreadEx)
  57.    public
  58.       Owner: TComponent;
  59.       constructor CreateSuspended(aOwner: TComponent); virtual;
  60.       destructor  Destroy; override;
  61.    end;
  62.    {$ENDIF}
  63.    TMMCustomDSPComponent = class(TMMNonVisualComponent)
  64.    end;
  65.    {-- TMMDSPComponent --------------------------------------------------------}
  66.    TMMDSPComponent = class(TMMCustomDSPComponent)
  67.    private
  68.       FInput         : TMMDSPComponent;
  69.       FOutput        : TMMDSPComponent;
  70.       FPWaveFormat   : PWaveFormatEx;
  71.       FOrigBufferSize: Longint;
  72.       FBufferSize    : Longint;
  73.       FOpen          : Boolean;
  74.       FStarted       : Boolean;
  75.       FPaused        : Boolean;
  76.       FOnBufferReady : TMMBufferEvent;
  77.       FOnBufferLoad  : TMMBufferLoadEvent;
  78.       FOnBufferFilled: TMMBufferEvent;
  79.    protected
  80.       FInputValid    : Boolean;
  81.       FOutputValid   : Boolean;
  82.       FInpPropName   : TPropString;
  83.       FOutPropName   : TPropString;
  84.       procedure UpdateParams; virtual;
  85.       procedure Loaded; override;
  86.       procedure DeconnectNotification(C: TComponent; Port: TMMPort; PortName: string); virtual;
  87.       procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  88.       procedure SetInput(aValue: TMMDSPComponent); virtual;
  89.       function  GetInput: TMMDSPComponent; virtual;
  90.       procedure SetOutput(aValue: TMMDSPComponent); virtual;
  91.       function  GetOutput: TMMDSPComponent; virtual;
  92.       procedure SetPWaveFormat(aValue: PWaveFormatEx); virtual;
  93.       function  GetPWaveFormat: PWaveFormatEx; virtual;
  94.       function  GetBufferSize: Longint; virtual;
  95.       procedure SetBufferSize(aValue: Longint); virtual;
  96.       property  OnBufferReady: TMMBufferEvent read FOnBufferReady write FOnBufferReady;
  97.       property  OnBufferLoad: TMMBufferLoadEvent read FOnBufferLoad write FOnBufferLoad;
  98.       property  OnBufferFilled: TMMBufferEvent read FOnBufferFilled write FOnBufferFilled;
  99.    public
  100.       FPreloaded: Boolean;
  101.       constructor Create(aOwner: TComponent); override;
  102.       destructor  Destroy; override;
  103.       procedure ChangePWaveFormat(aValue: PWaveFormatEx); virtual;
  104.       procedure Opened; virtual;
  105.       procedure Closed; virtual;
  106.       procedure Started; virtual;
  107.       procedure Paused; virtual;
  108.       procedure Restarted; virtual;
  109.       procedure Stopped; virtual;
  110.       procedure Reseting; virtual;
  111.       procedure Looped; virtual;
  112.       procedure BufferReady(lpwh: PWaveHdr); virtual;
  113.       procedure BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean); virtual;
  114.       procedure SetInputPort(aValue: TMMDSPComponent; PropName: TPropString); virtual;
  115.       procedure SetOutputPort(aValue: TMMDSPComponent; PropName: TPropString); virtual;
  116.       function CanConnectInput(aComponent: TComponent): Boolean; virtual;
  117.       function CanConnectOutput(aComponent: TComponent): Boolean; virtual;
  118.       property IsOpen: Boolean read FOpen;
  119.       property IsStarted: Boolean read FStarted;
  120.       property IsPaused: Boolean read FPaused;
  121.       property Input : TMMDSPComponent read GetInput write SetInput;
  122.       property Output: TMMDSPComponent read GetOutput write SetOutput;
  123.       property PWaveFormat: PWaveFormatEx read GetPWaveFormat write SetPWaveFormat;
  124.       property BufferSize: Longint read GetBufferSize write SetBufferSize default 2048;
  125.     end;
  126.    {-- TMMDSPInterface --------------------------------------------------------}
  127.    TMMDSPInterface = class(TMMDSPComponent)
  128.    private
  129.       FOnOpen    : TNotifyEvent;
  130.       FOnStart   : TNotifyEvent;
  131.       FOnPause   : TNotifyEvent;
  132.       FOnRestart : TNotifyEvent;
  133.       FOnLooped  : TNotifyEvent;
  134.       FOnStop    : TNotifyEvent;
  135.       FOnClose   : TNotifyEvent;
  136.    published
  137.       procedure Opened; override;
  138.       procedure Closed; override;
  139.       procedure Started; override;
  140.       procedure Paused; override;
  141.       procedure Restarted; override;
  142.       procedure Stopped; override;
  143.       property  OnOpen: TNotifyEvent read FOnOpen write FOnOpen;
  144.       property  OnStart: TNotifyEvent read FOnStart write FOnStart;
  145.       property  OnPause: TNotifyEvent read FOnPause write FOnPause;
  146.       property  OnRestart: TNotifyEvent read FOnRestart write FOnRestart;
  147.       property  OnLooped: TNotifyEvent read FOnLooped write FOnLooped;
  148.       property  OnStop: TNotifyEvent read FOnStop write FOnStop;
  149.       property  OnClose: TNotifyEvent read FOnClose write FOnClose;
  150.       property  OnBufferReady;
  151.       property  OnBufferLoad;
  152.       property  OnBufferFilled;
  153.       property  Input;
  154.       property  Output;
  155.    end;
  156.    {-- internal for loop handling ---------------------------------------------}
  157.    PMMLoopRec = ^TMMLoopRec;
  158.    TMMLoopRec = packed record
  159.       dwLoop      : LongBool;       { is Loop enabled ?                  }
  160.       dwLoopCnt   : Longint;        { number of loops required           }
  161.       dwLoopTmpCnt: Longint;        { temp loop counter                  }
  162.       dwLooping   : LongBool;       { End is reached Loop it or not      }
  163.    end;
  164.    {-- internal WaveHdr -------------------------------------------------------}
  165.    PMMWaveHdr = ^TMMWaveHdr;
  166.    TMMWaveHdr = packed record
  167.       wh           : TWaveHdr;
  168.       dwUser1      : Longint;       { private user data                  }
  169.       dwUser2      : Longint;       { private user data                  }
  170.       lpNext       : PWaveHdr;      { internal for buffer handling       }
  171.       LoopRec      : TMMLoopRec;    { internal for loop handling         }
  172.    end;
  173.    {-- TMMCustomSoundComponent ------------------------------------------------}
  174.    TMMCustomSoundComponent = class(TMMDSPComponent)
  175.    protected
  176.       FFullDuplex : Boolean;
  177.       procedure SetNumBuffers(aValue: integer); virtual; abstract;
  178.       function  GetNumBuffers: integer; virtual; abstract;
  179.       procedure SetDeviceID(aValue: TMMDeviceID); virtual; abstract;
  180.       function  GetDeviceID: TMMDeviceID; virtual; abstract;
  181.       procedure SetProductName(aValue: string); virtual; abstract;
  182.       function  GetProductName: string; virtual; abstract;
  183.       procedure SetCallBackMode(aValue: TMMCBMode); virtual; abstract;
  184.       function  GetCallBackMode: TMMCBMode; virtual; abstract;
  185.    public
  186.       constructor Create(AOwner: TComponent); override;
  187.       destructor  Destroy; override;
  188.       procedure Opened; override;
  189.       procedure Closed; override;
  190.       procedure Started; override;
  191.       procedure Paused; override;
  192.       procedure Restarted; override;
  193.       procedure Stopped; override;
  194.       procedure Reseting; override;
  195.       procedure Looped; override;
  196.       property NumBuffers: integer read GetNumBuffers write SetNumBuffers default 10;
  197.       property DeviceID: TMMDeviceID read GetDeviceID write SetDeviceID default 0;
  198.       property ProductName: String read GetProductName write SetProductName stored False;
  199.       property CallBackMode: TMMCBMode read GetCallBackMode write SetCallBackMode default cmWindow;
  200.    end;
  201.    {-- TMMCustomWaveOutCommponent ---------------------------------------------}
  202.    TMMCustomWaveOutComponent = class(TMMCustomSoundComponent)
  203.    protected
  204.       function GetPosition: MM_int64; virtual; abstract;
  205.    public
  206.       procedure Open; virtual; abstract;
  207.       procedure Close; virtual; abstract;
  208.       procedure Reset; virtual; abstract;
  209.       procedure Start; virtual; abstract;
  210.       procedure Pause; virtual; abstract;
  211.       procedure Restart; virtual; abstract;
  212.       procedure Stop; virtual; abstract;
  213.       property Position: MM_int64 read GetPosition;
  214.    end;
  215. function DSPOutConnectCheck(C1, C2: TComponent): Boolean; far;
  216. function DSPInpConnectCheck(C1, C2: TComponent): Boolean; far;
  217. procedure GlobalDeconnectNotification(C: TComponent; Port: TMMPort; PortName: string);
  218. procedure GlobalSynchronize(VCLProc: TThreadMethod);
  219. const
  220.      DSPList   : TList = nil;
  221.      ThreadList: TList = nil;
  222. implementation
  223. uses TypInfo;
  224. {------------------------------------------------------------------------------}
  225. procedure GlobalSynchronize(VCLProc: TThreadMethod);
  226. var
  227.    i: integer;
  228.    CurID: THandle;
  229. begin
  230.    {$IFDEF WIN32}
  231.    if (ThreadList <> nil) then
  232.    begin
  233.       CurID := GetCurrentThreadID;
  234.       if (CurID <> MainThreadID) then
  235.       for i := 0 to ThreadList.Count-1 do
  236.       with TMMDSPThread(ThreadList[i]) do
  237.       begin
  238.          if ThreadID = CurID then
  239.          begin
  240.             Synchronize(VCLProc);
  241.             exit;
  242.          end;
  243.       end;
  244.    end;
  245.    {$ENDIF}
  246.    VCLProc;
  247. end;
  248. {$IFDEF WIN32}
  249. {== TMMDSPThread ==============================================================}
  250. constructor TMMDSPThread.CreateSuspended(aOwner: TComponent);
  251. begin
  252.    Owner := aOwner;
  253.    Create(True);
  254.    if ThreadList = nil then
  255.       ThreadList := TList.Create;
  256.    ThreadList.Add(Self);
  257. end;
  258. {-- TMMDSPThread --------------------------------------------------------------}
  259. destructor TMMDSPThread.Destroy;
  260. begin
  261.    ThreadList.Remove(Self);
  262.    if ThreadList.Count = 0 then
  263.    begin
  264.       ThreadList.Free;
  265.       ThreadList := nil;
  266.    end;
  267.    inherited Destroy;
  268. end;
  269. {$ENDIF}
  270. {------------------------------------------------------------------------------}
  271. function DSPOutConnectCheck(C1, C2: TComponent): Boolean;
  272. begin
  273.    Result := (C1 as TMMDSPComponent).CanConnectOutput(C2);
  274. end;
  275. {------------------------------------------------------------------------------}
  276. function DSPInpConnectCheck(C1, C2: TComponent): Boolean;
  277. begin
  278.    Result := (C2 as TMMDSPComponent).CanConnectInput(C1);
  279. end;
  280. {------------------------------------------------------------------------------}
  281. procedure GlobalDeconnectNotification(C: TComponent; Port: TMMPort; PortName: string);
  282. var
  283.    i: integer;
  284. begin
  285.    for i := 0 to DSPList.Count-1 do
  286.    begin
  287.       TMMDSPComponent(DSPList[i]).DeconnectNotification(C,Port,PortName);
  288.    end;
  289. end;
  290. {== TMMDSPComponent ===========================================================}
  291. constructor TMMDSPComponent.Create(AOwner: TComponent);
  292. begin
  293.    inherited Create(AOwner);
  294.    FInput          := nil;
  295.    FOutput         := nil;
  296.    FInputValid     := False;
  297.    FOutputValid    := False;
  298.    FInpPropName    := '';
  299.    FOutPropName    := '';
  300.    FOrigBufferSize := 2048;
  301.    FBufferSize     := FOrigBufferSize;
  302.    FOpen           := False;
  303.    FStarted        := False;
  304.    FPaused         := False;
  305.    
  306.    if DSPList = nil then
  307.       DSPList := TList.Create;
  308.    DSPList.Add(Self);
  309.    ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
  310.    if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
  311. end;
  312. {-- TMMDSPComponent -----------------------------------------------------------}
  313. destructor TMMDSPComponent.Destroy;
  314. begin
  315.    Input       := nil;
  316.    Output      := nil;
  317.    PWaveFormat := nil;
  318.    DSPList.Remove(Self);
  319.    if DSPList.Count = 0 then
  320.    begin
  321.       DSPList.Free;
  322.       DSPList := nil;
  323.    end;
  324.    inherited Destroy;
  325. end;
  326. {-- TMMDSPComponent -----------------------------------------------------------}
  327. procedure TMMDSPComponent.Notification(AComponent: TComponent; Operation: TOperation);
  328. begin
  329.    inherited Notification(AComponent, Operation);
  330.    if Operation = opRemove then
  331.    begin
  332.       if AComponent = FInput then
  333.          Input := nil
  334.       else if AComponent = FOutput then
  335.          Output := nil;
  336.    end;
  337. end;
  338. {-- TMMDSPComponent -----------------------------------------------------------}
  339. function TMMDSPComponent.CanConnectInput(aComponent: TComponent): Boolean;
  340. begin
  341.    Result := False;
  342.    if (aComponent <> Self) and (aComponent is TMMDSPComponent) and
  343.       ((GetPropInfo(TMMDSPComponent(aComponent).ClassInfo, 'Output') <> nil) or
  344.         TMMDSPComponent(aComponent).FOutputValid) then
  345.    begin
  346.       { don't allow ring connection }
  347.       if (Output <> nil) then
  348.           Result := Output.CanConnectInput(aComponent)
  349.       else
  350.           Result := True;
  351.    end;
  352. end;
  353. {-- TMMDSPComponent -----------------------------------------------------------}
  354. function TMMDSPComponent.CanConnectOutput(aComponent: TComponent): Boolean;
  355. begin
  356.    Result := False;
  357.    if (aComponent <> Self) and (aComponent is TMMDSPComponent) and
  358.       ((GetPropInfo(TMMDSPComponent(aComponent).ClassInfo, 'Input') <> nil) or
  359.         TMMDSPComponent(aComponent).FInputValid) then
  360.    begin
  361.       { don't allow ring connection }
  362.       if (Input <> nil) then
  363.           Result := Input.CanConnectOutput(aComponent)
  364.       else
  365.           Result := True;
  366.    end;
  367. end;
  368. {-- TMMDSPComponent -----------------------------------------------------------}
  369. procedure TMMDSPComponent.DeconnectNotification(C: TComponent; Port: TMMPort; PortName: string);
  370. var
  371.    PropInfo: PPropInfo;
  372. begin
  373.    if (Port = poInput) then
  374.    begin
  375.       if (Output = C) and (FOutPropName = PortName) then
  376.       begin
  377.          PropInfo := GetPropInfo(C.ClassInfo, FOutPropName);
  378.          if (PropInfo <> nil) and (GetOrdProp(C,PropInfo) = Longint(Self)) then
  379.              SetOutputPort(nil,'');
  380.       end;
  381.    end
  382.    else
  383.    begin
  384.       if (Input = C) and (FInpPropName = PortName) then
  385.       begin
  386.          PropInfo := GetPropInfo(C.ClassInfo, FInpPropName);
  387.          if (PropInfo <> nil) and (GetOrdProp(C,PropInfo) = Longint(Self)) then
  388.              SetInputPort(nil,'');
  389.       end;
  390.    end;
  391. end;
  392. {-- TMMDSPComponent -----------------------------------------------------------}
  393. procedure TMMDSPComponent.SetInputPort(aValue: TMMDSPComponent; PropName: TPropString);
  394. begin
  395.    FInput := aValue;
  396.    FInpPropName := PropName;
  397. end;
  398. {-- TMMDSPComponent -----------------------------------------------------------}
  399. procedure TMMDSPComponent.SetOutputPort(aValue: TMMDSPComponent; PropName: TPropString);
  400. begin
  401.    FOutput := aValue;
  402.    FOutPropName := PropName;
  403. end;
  404. {-- TMMDSPComponent -----------------------------------------------------------}
  405. procedure TMMDSPComponent.SetInput(aValue: TMMDSPComponent);
  406. begin
  407.    if (aValue <> FInput) and ((aValue = nil) or CanConnectInput(aValue)) then
  408.    begin
  409.       Stopped;
  410.       if (FInput <> nil) then
  411.       begin
  412.          GlobalDeconnectNotification(Self,poInput,'Input');
  413.          SetInputPort(nil,'');
  414.          ChangePWaveFormat(nil);
  415.       end;
  416.       if (aValue <> nil) then
  417.       begin
  418.          GlobalDeconnectNotification(aValue,poOutput,'Output');
  419.          SetInputPort(aValue,'Output');
  420.          FInput.SetOutputPort(Self,'Input');
  421.          UpdateParams;
  422.       end;
  423.    end;
  424.    {$IFDEF WIN32}
  425.    {$IFDEF TRIAL}
  426.    {$DEFINE _HACK1}
  427.    {$I MMHACK.INC}
  428.    {$ENDIF}
  429.    {$ENDIF}
  430. end;
  431. {-- TMMDSPComponent -----------------------------------------------------------}
  432. function TMMDSPComponent.GetInput: TMMDSPComponent;
  433. begin
  434.    Result := FInput;
  435. end;
  436. {-- TMMDSPComponent -----------------------------------------------------------}
  437. procedure TMMDSPComponent.SetOutput(aValue: TMMDSPComponent);
  438. begin
  439.    if (aValue <> FOutput) and ((aValue = nil) or CanConnectOutput(aValue)) then
  440.    begin
  441.       Stopped;
  442.       if (FOutput <> nil) then
  443.       begin
  444.          GlobalDeconnectNotification(Self,poOutput,'Output');
  445.          FOutput.ChangePWaveFormat(nil);
  446.          SetOutputPort(nil,'');
  447.       end;
  448.       if (aValue <> nil) then
  449.       begin
  450.          GlobalDeconnectNotification(aValue,poInput,'Input');
  451.          SetOutputPort(aValue,'Input');
  452.          FOutput.SetInputPort(Self,'Output');
  453.          UpdateParams;
  454.       end;
  455.    end;
  456.    {$IFDEF WIN32}
  457.    {$IFDEF TRIAL}
  458.    {$DEFINE _HACK2}
  459.    {$I MMHACK.INC}
  460.    {$ENDIF}
  461.    {$ENDIF}
  462. end;
  463. {-- TMMDSPComponent -----------------------------------------------------------}
  464. function TMMDSPComponent.GetOutput: TMMDSPComponent;
  465. begin
  466.    Result := FOutput;
  467. end;
  468. {-- TMMDSPComponent -----------------------------------------------------------}
  469. procedure TMMDSPComponent.UpdateParams;
  470. begin
  471.    if (csLoading in ComponentState) or
  472.       (csReading in ComponentState) or
  473.       (csDestroying in ComponentState) then exit;
  474.    if (Input <> nil) then
  475.    begin
  476.       ChangePWaveFormat(Input.PWaveFormat);
  477.    end
  478.    else if (Output <> nil) then
  479.    begin
  480.       Output.ChangePWaveFormat(PWaveFormat);
  481.    end;
  482. end;
  483. {-- TMMDSPComponent -----------------------------------------------------------}
  484. procedure TMMDSPComponent.Loaded;
  485. begin
  486.    inherited Loaded;
  487.    PWaveFormat := FPWaveFormat;
  488. end;
  489. {-- TMMDSPComponent -----------------------------------------------------------}
  490. procedure TMMDSPComponent.ChangePWaveFormat(aValue: PWaveFormatEx);
  491. begin
  492.    PWaveFormat := aValue;
  493. end;
  494. {-- TMMDSPComponent -----------------------------------------------------------}
  495. procedure TMMDSPComponent.SetPWaveFormat(aValue: PWaveFormatEx);
  496. begin
  497.    if (aValue <> FPWaveFormat) then
  498.    begin
  499.       if FStarted then Stopped;
  500.       GlobalFreeMem(Pointer(FPWaveFormat));
  501.       FPWaveFormat := wioCopyWaveFormat(aValue);
  502.    end;
  503.    if not (csLoading in ComponentState) and
  504.       not (csReading in ComponentState) and
  505.       not (csDestroying in ComponentState) then
  506.       if (Output <> nil) then
  507.           Output.ChangePWaveFormat(PWaveFormat);
  508. end;
  509. {-- TMMDSPComponent -----------------------------------------------------------}
  510. function TMMDSPComponent.GetPWaveFormat: PWaveFormatEx;
  511. begin
  512.    Result := FPWaveFormat;
  513. end;
  514. {-- TMMDSPComponent -----------------------------------------------------------}
  515. Procedure TMMDSPComponent.SetBufferSize(aValue: Longint);
  516. begin
  517.    if (aValue <> FOrigBufferSize) then
  518.    begin
  519.       if FStarted then Stopped;
  520.       FOrigBufferSize := aValue;
  521.    end;
  522.    {$IFDEF WIN32}
  523.    {$IFDEF TRIAL}
  524.    {$DEFINE _HACK3}
  525.    {$I MMHACK.INC}
  526.    {$ENDIF}
  527.    {$ENDIF}
  528. end;
  529. {-- TMMDSPComponent -----------------------------------------------------------}
  530. function TMMDSPComponent.GetBufferSize: Longint;
  531. begin
  532.    if FOpen then
  533.        Result := FBufferSize
  534.    else
  535.        Result := FOrigBufferSize;
  536. end;
  537. {-- TMMDSPComponent -----------------------------------------------------------}
  538. procedure TMMDSPComponent.Opened;
  539. begin
  540.    if not FOpen then
  541.    begin
  542.       if (PWaveFormat <> nil) then
  543.          { make the wave buffer size a multiple of the block align... }
  544.          FBufferSize := Max(FOrigBufferSize-(FOrigBufferSize mod PWaveFormat^.nBlockAlign),PWaveFormat^.nBlockAlign)
  545.       else
  546.          FBufferSize := FOrigBufferSize;
  547.       FOpen    := True;
  548.       FStarted := False;
  549.       FPaused  := False;
  550.    end;
  551. end;
  552. {-- TMMDSPComponent -----------------------------------------------------------}
  553. procedure TMMDSPComponent.Closed;
  554. begin
  555.    if FOpen then
  556.    begin
  557.       FOpen := False;
  558.    end;
  559. end;
  560. {-- TMMDSPComponent -----------------------------------------------------------}
  561. procedure TMMDSPComponent.Started;
  562. begin
  563.    if not FStarted and FOpen then
  564.    begin
  565.       FStarted := True;
  566.    end;
  567. end;
  568. {-- TMMDSPComponent -----------------------------------------------------------}
  569. procedure TMMDSPComponent.Paused;
  570. begin
  571.    if not FPaused then
  572.       FPaused := True;
  573. end;
  574. {-- TMMDSPComponent -----------------------------------------------------------}
  575. procedure TMMDSPComponent.Restarted;
  576. begin
  577.    if FPaused then
  578.       FPaused := False;
  579. end;
  580. {-- TMMDSPComponent -----------------------------------------------------------}
  581. procedure TMMDSPComponent.Reseting;
  582. begin
  583. end;
  584. {-- TMMDSPComponent -----------------------------------------------------------}
  585. procedure TMMDSPComponent.Looped;
  586. begin
  587. end;
  588. {-- TMMDSPComponent -----------------------------------------------------------}
  589. procedure TMMDSPComponent.Stopped;
  590. begin
  591.    if FStarted then
  592.    begin
  593.       FStarted := False;
  594.       FPaused  := False;
  595.    end;
  596. end;
  597. {-- TMMDSPComponent -----------------------------------------------------------}
  598. procedure TMMDSPComponent.BufferReady(lpwh: PWaveHdr);
  599. begin
  600.    if assigned(FOnBufferReady) then FOnBufferReady(Self, lpwh);
  601.    if (Output <> nil) then Output.BufferReady(lpwh);
  602. end;
  603. {-- TMMDSPComponent -----------------------------------------------------------}
  604. procedure TMMDSPComponent.BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean);
  605. begin
  606.    if assigned(FOnBufferLoad) then FOnBufferLoad(Self, lpwh, MoreBuffers);
  607.    if (Input <> nil) then Input.BufferLoad(lpwh, MoreBuffers);
  608.    if assigned(FOnBufferFilled) and (lpwh^.dwBytesRecorded > 0) then FOnBufferFilled(Self,lpwh);
  609. end;
  610. {== TMMDSPInterface ===========================================================}
  611. procedure TMMDSPInterface.Opened;
  612. begin
  613.    if not FOpen then
  614.    begin
  615.       inherited Opened;
  616.       if assigned(FOnOpen) then FOnOpen(Self);
  617.    end;
  618. end;
  619. {-- TMMDSPInterface -----------------------------------------------------------}
  620. procedure TMMDSPInterface.Closed;
  621. begin
  622.    if FOpen then
  623.    begin
  624.       inherited Closed;
  625.       if assigned(FOnClose) then FOnClose(Self);
  626.    end;
  627. end;
  628. {-- TMMDSPInterface -----------------------------------------------------------}
  629. procedure TMMDSPInterface.Started;
  630. begin
  631.    if not FStarted and FOpen then
  632.    begin
  633.       inherited Started;
  634.       if assigned(FOnStart) then FOnStart(Self);
  635.    end;
  636. end;
  637. {-- TMMDSPInterface -----------------------------------------------------------}
  638. procedure TMMDSPInterface.Paused;
  639. begin
  640.    inherited Paused;
  641.    if assigned(FOnPause) then FOnPause(Self);
  642. end;
  643. {-- TMMDSPInterface -----------------------------------------------------------}
  644. procedure TMMDSPInterface.Restarted;
  645. begin
  646.    inherited Restarted;
  647.    if assigned(FOnRestart) then FOnRestart(Self);
  648. end;
  649. {-- TMMDSPInterface -----------------------------------------------------------}
  650. procedure TMMDSPInterface.Stopped;
  651. begin
  652.    if FStarted then
  653.    begin
  654.       inherited Stopped;
  655.       if assigned(FOnStop) then FOnStop(Self);
  656.    end;
  657. end;
  658. {== TMMCustomSoundComponent ===================================================}
  659. constructor TMMCustomSoundComponent.Create(AOwner: TComponent);
  660. begin
  661.    inherited Create(AOwner);
  662.    FFullDuplex := False;
  663. end;
  664. {-- TMMCustomSoundComponent ---------------------------------------------------}
  665. destructor TMMCustomSoundComponent.Destroy;
  666. begin
  667.    inherited Destroy;
  668. end;
  669. {-- TMMCustomSoundComponent ---------------------------------------------------}
  670. procedure TMMCustomSoundComponent.Opened;
  671. var
  672.    Current: TMMDSPComponent;
  673. begin
  674.    FFullDuplex := False;
  675.    { search the first valid component }
  676.    Current := Self;
  677.    while (Current.Input <> nil) do
  678.    begin
  679.       Current := Current.Input;
  680.       { if we have a preloader it is the first component for us }
  681.       if Current.FPreloaded then break;
  682.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  683.       begin
  684.          { there is another sound component on the left side }
  685.          FFullDuplex := True;
  686.          Current := Self;
  687.          break;
  688.       end;
  689.    end;
  690.    { no go trough all components and notify }
  691.    repeat
  692.       if not (Current is TMMCustomSoundComponent) then
  693.       begin
  694.          Current.BufferSize := BufferSize;
  695.          Current.Opened;
  696.       end
  697.       else if (Current <> Self) then
  698.       begin       { there is another sound component on the right side }
  699.          Current.BufferSize := BufferSize;
  700.          Current.Opened;
  701.          break;
  702.       end;
  703.       Current := Current.Output;
  704.    until (Current = nil);
  705.    inherited Opened;
  706. end;
  707. {-- TMMCustomSoundComponent ---------------------------------------------------}
  708. procedure TMMCustomSoundComponent.Closed;
  709. var
  710.    Current: TMMDSPComponent;
  711. begin
  712.    { search the last component }
  713.    Current := Self;
  714.    while (Current.Output <> nil) do
  715.    begin
  716.       Current := Current.Output;
  717.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  718.       begin
  719.          { there is another sound component on the right side }
  720.          Current.Closed;
  721.          break;
  722.       end;
  723.    end;
  724.    { search the first component }
  725.    Current := Self;
  726.    while (Current.Input <> nil) do
  727.    begin
  728.       Current := Current.Input;
  729.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  730.       begin
  731.          { there is another sound component on the left side }
  732.          Current := Self;
  733.          break;
  734.       end;
  735.    end;
  736.    { no go trough all components and notify }
  737.    repeat
  738.       if not (Current is TMMCustomSoundComponent) then
  739.       begin
  740.          Current.Closed;
  741.       end
  742.       else if (Current <> Self) then
  743.       begin
  744.          { there is another sound component on the right side }
  745.          break;
  746.       end;
  747.       Current := Current.Output;
  748.    until (Current = nil);
  749.    inherited Closed;
  750. end;
  751. {-- TMMCustomSoundComponent ---------------------------------------------------}
  752. procedure TMMCustomSoundComponent.Started;
  753. var
  754.    Current: TMMDSPComponent;
  755. begin
  756.    { search the first component }
  757.    Current := Self;
  758.    while (Current.Input <> nil) do
  759.    begin
  760.       Current := Current.Input;
  761.       { if we have a preloader it is the first component for us }
  762.       if Current.FPreloaded then break;
  763.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  764.       begin
  765.          { there is another sound component on the left side }
  766.          Current := Self;
  767.          break;
  768.       end;
  769.    end;
  770.    { no go trough all components and notify }
  771.    repeat
  772.       if not (Current is TMMCustomSoundComponent) then
  773.       begin
  774.          Current.Started;
  775.       end
  776.       else if (Current <> Self) then
  777.       begin
  778.          Current.Started;
  779.          break;   { there is another sound component on the right side }
  780.       end;
  781.       Current := Current.Output;
  782.    until (Current = nil);
  783.    inherited Started;
  784. end;
  785. {-- TMMCustomSoundComponent ---------------------------------------------------}
  786. procedure TMMCustomSoundComponent.Paused;
  787. var
  788.    Current: TMMDSPComponent;
  789. begin
  790.    { search the first component }
  791.    Current := Self;
  792.    while (Current.Input <> nil) do
  793.    begin
  794.       Current := Current.Input;
  795.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  796.       begin
  797.          { there is another sound component on the left side }
  798.          Current := Self;
  799.          break;
  800.       end;
  801.    end;
  802.    { no go trough all components and notify }
  803.    repeat
  804.       if not (Current is TMMCustomSoundComponent) then
  805.       begin
  806.          Current.Paused;
  807.       end
  808.       else if (Current <> Self) then
  809.       begin
  810.          Current.Paused;
  811.          break;   { there is another sound component on the right side }
  812.       end;
  813.       Current := Current.Output;
  814.    until (Current = nil);
  815.    inherited Paused;
  816. end;
  817. {-- TMMCustomSoundComponent ---------------------------------------------------}
  818. procedure TMMCustomSoundComponent.Restarted;
  819. var
  820.    Current: TMMDSPComponent;
  821. begin
  822.    { search the first component }
  823.    Current := Self;
  824.    while (Current.Input <> nil) do
  825.    begin
  826.       Current := Current.Input;
  827.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  828.       begin
  829.          { there is another sound component on the left side }
  830.          Current := Self;
  831.          break;
  832.       end;
  833.    end;
  834.    { no go trough all components and notify }
  835.    repeat
  836.       if not (Current is TMMCustomSoundComponent) then
  837.       begin
  838.          Current.Restarted;
  839.       end
  840.       else if (Current <> Self) then
  841.       begin
  842.          Current.Restarted;
  843.          break;   { there is another sound component on the right side }
  844.       end;
  845.       Current := Current.Output;
  846.    until (Current = nil);
  847.    inherited Restarted;
  848. end;
  849. {-- TMMCustomSoundComponent ---------------------------------------------------}
  850. procedure TMMCustomSoundComponent.Stopped;
  851. var
  852.    Current: TMMDSPComponent;
  853. begin
  854.    { search the last component }
  855.    Current := Self;
  856.    while (Current.Output <> nil) do
  857.    begin
  858.       Current := Current.Output;
  859.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  860.       begin
  861.          { there is another sound component on the right side }
  862.          Current.Stopped;
  863.          break;
  864.       end;
  865.    end;
  866.    { search the first component }
  867.    Current := Self;
  868.    while (Current.Input <> nil) do
  869.    begin
  870.       Current := Current.Input;
  871.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  872.       begin
  873.          { there is another sound component on the left side }
  874.          Current := Self;
  875.          break;
  876.       end;
  877.    end;
  878.    { no go trough all components and notify }
  879.    repeat
  880.       if not (Current is TMMCustomSoundComponent) then
  881.       begin
  882.          Current.Stopped;
  883.       end
  884.       else if (Current <> Self) then
  885.       begin
  886.          { there is another sound component on the right side }
  887.          break;
  888.       end;
  889.       Current := Current.Output;
  890.    until (Current = nil);
  891.    inherited Stopped;
  892. end;
  893. {-- TMMCustomSoundComponent ---------------------------------------------------}
  894. procedure TMMCustomSoundComponent.Reseting;
  895. var
  896.    Current: TMMDSPComponent;
  897. begin
  898.    { search the first component }
  899.    Current := Self;
  900.    while (Current.Input <> nil) do
  901.    begin
  902.       Current := Current.Input;
  903.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  904.       begin
  905.          { there is another sound component on the left side }
  906.          Current := Self;
  907.          break;
  908.       end;
  909.    end;
  910.    { no go trough all components and notify }
  911.    repeat
  912.       if not (Current is TMMCustomSoundComponent) then
  913.       begin
  914.          Current.Reseting;
  915.       end
  916.       else if (Current <> Self) then
  917.       begin
  918.          Current.Reseting;
  919.          break;   { there is another sound component on the right side }
  920.       end;
  921.       Current := Current.Output;
  922.    until (Current = nil);
  923.    inherited Reseting;
  924. end;
  925. {-- TMMCustomSoundComponent ---------------------------------------------------}
  926. procedure TMMCustomSoundComponent.Looped;
  927. var
  928.    Current: TMMDSPComponent;
  929. begin
  930.    { search the first component }
  931.    Current := Self;
  932.    while (Current.Input <> nil) do
  933.    begin
  934.       Current := Current.Input;
  935.       if (Current is TMMCustomSoundComponent) and (Current <> Self) then
  936.       begin
  937.          { there is another sound component on the left side }
  938.          Current := Self;
  939.          break;
  940.       end;
  941.    end;
  942.    { no go trough all components and notify }
  943.    repeat
  944.       if not (Current is TMMCustomSoundComponent) then
  945.       begin
  946.          Current.Looped;
  947.       end
  948.       else if (Current <> Self) then
  949.       begin
  950.          Current.Looped;
  951.          break;   { there is another sound component on the right side }
  952.       end;
  953.       Current := Current.Output;
  954.    until (Current = nil);
  955.    inherited Looped;
  956. end;
  957. end.