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

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Tel.: +0351-8012255                   =}
  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: 1/29/98 - 5:37:12 PM $                                      =}
  24. {========================================================================}
  25. unit MMReverb;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29. {$IFDEF WIN32}
  30.     Windows,
  31. {$ELSE}
  32.     WinTypes,
  33.     WinProcs,
  34. {$ENDIF}
  35.     SysUtils,
  36.     Classes,
  37.     Controls,
  38.     MMSystem,
  39.     MMRegs,
  40.     MMObj,
  41.     MMDSPObj,
  42.     MMObjLst,
  43.     MMUtils,
  44.     MMWaveIO,
  45.     MMPCMSup,
  46.     MMFX;
  47. type
  48.    TMMEchoIndex = 0..MaxEchos-1;
  49.    EMMReverbError = class(Exception);
  50.    TMMReverb = class;
  51.    {-- TMMEcho ----------------------------------------------------------}
  52.    TMMEcho = class(TObject)
  53.    private
  54.       FDelay   : Longint;          { delay (ms) for this echo line       }
  55.       FGain    : Longint;          { mix volume (%) for this echo        }
  56.       FOnChange: TNotifyEvent;
  57.       procedure SetDelay(aValue: Longint);
  58.       procedure SetGain(aValue: Longint);
  59.       procedure Store(S: TStream); virtual;
  60.       procedure Load(S: TStream); virtual;
  61.    protected
  62.       procedure Changed; virtual;
  63.    public
  64.       constructor Create;
  65.       procedure Assign(Source: TObject);
  66.       procedure SetParams(aDelay, aGain: Longint);
  67.       property OnChange: TNotifyEvent read FOnChange write FOnChange;
  68.       property Delay: Longint read FDelay write SetDelay default 0;
  69.       property Gain: Longint read FGain write SetGain default 0;
  70.    end;
  71.    {-- TMMEchoList ------------------------------------------------------}
  72.    TMMEchoList = class(TObjectList)
  73.    private
  74.       FReverb: TMMReverb;
  75.       procedure SetEcho(Index: TMMEchoIndex; Echo: TMMEcho);
  76.       function  GetEcho(Index: TMMEchoIndex): TMMEcho;
  77.    protected
  78.       procedure ReadData(S: TStream); override;
  79.       procedure WriteData(S: TStream); override;
  80.    public
  81.       function  AddObject(Item: TObject): TOLSize; override;
  82.       procedure Assign(Source: TPersistent); override;
  83.       property Items[Index: TMMEchoIndex]: TMMEcho read GetEcho write SetEcho; default;
  84.    end;
  85.    {-- TMMReverb --------------------------------------------------------}
  86.    TMMReverb = class(TMMDSPComponent)
  87.    private
  88.       FEnabled       : Boolean;
  89.       FOpen          : Boolean;
  90.       FPReverb       : PReverb;
  91.       FDescription   : String;
  92.       FMaxDelay      : integer;
  93.       FInputGain     : TMMEffectVolume;
  94.       FInputPan      : TMMEffectVolume;
  95.       FOutputGain    : TMMEffectVolume;
  96.       FFeedBack      : TMMFeedBack;
  97.       FFilter        : Boolean;
  98.       FEchos         : TMMEchoList;
  99.       FUpdating      : Boolean;
  100.       FCleanup       : Longint;
  101.       FOnChange      : TNotifyEvent;
  102.       FOnPcmOverflow : TNotifyEvent;
  103.       procedure SetEnabled(aValue: Boolean);
  104.       procedure SetDescription(aValue: String);
  105.       procedure SetMaxDelay(aValue: integer);
  106.       procedure SetGains(index: integer; aValue: TMMEffectVolume);
  107.       procedure SetFeedBack(aValue: TMMFeedBack);
  108.       procedure SetFilter(aValue: Boolean);
  109.       procedure SetEchos(aValue: TMMEchoList);
  110.       procedure EchosChanged(Sender: TObject);
  111.    protected
  112.       procedure SetPWaveFormat(aValue: PWaveFormatEx); override;
  113.       procedure Assign(Source: TPersistent); override;
  114.       procedure Change; dynamic;
  115.       procedure Update; virtual;
  116.       procedure Opened; override;
  117.       procedure Closed; override;
  118.       procedure Started; override;
  119.       procedure PcmOverflow; dynamic;
  120.       procedure BufferReady(lpwh: PWaveHdr); override;
  121.       procedure BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean); override;
  122.    public
  123.       constructor Create(aOwner: TComponent); override;
  124.       destructor Destroy; override;
  125.       procedure Open;
  126.       procedure Close;
  127.       procedure Process(Buffer: PChar; Length: integer);
  128.       function  CleanUp(Buffer: PChar; Length: integer): Longint;
  129.       procedure SaveToIniFile(IniFile: TFileName; Section: string);
  130.       procedure ReadFromIniFile(IniFile: TFileName; Section: string);
  131.       procedure ReadIniSections(IniFile: TFileName; Strings: TStrings);
  132.       procedure DeleteSection(IniFile: TFileName; Section: string);
  133.    published
  134.       property OnChange: TNotifyEvent read FOnChange write FOnChange;
  135.       property OnPcmOverflow: TNotifyEvent read FOnPcmOverflow write FOnPcmOverflow;
  136.       property Input;
  137.       property Output;
  138.       property Enabled: Boolean read FEnabled write SetEnabled default True;
  139.       property Description: String read FDescription write SetDescription stored False;
  140.       property MaxDelay: integer read FMaxDelay write SetMaxDelay stored False;
  141.       property InputGain: TMMEffectVolume index 0 read FInputGain write SetGains stored False;
  142.       property InputPan: TMMEffectVolume index 1 read FInputPan write SetGains stored False;
  143.       property OutputGain: TMMEffectVolume index 2 read FOutputGain write SetGains stored False;
  144.       property FeedBack: TMMFeedBack read FFeedback write SetFeedBack stored False;
  145.       property Filter: Boolean read FFilter write SetFilter stored False;
  146.       property Echos: TMMEchoList read FEchos write SetEchos;
  147.    end;
  148. implementation
  149. uses IniFiles;
  150. const
  151.    STREAMKENNUNG : Longint = $00425652; { 'RVB ' }
  152. {== TMMEcho =============================================================}
  153. constructor TMMEcho.Create;
  154. begin
  155.    inherited Create;
  156.    FDelay := 0;
  157.    FGain  := 0;
  158.    FOnChange := nil;
  159. end;
  160. {-- TMMEcho -------------------------------------------------------------}
  161. procedure TMMEcho.Changed;
  162. begin
  163.    if assigned(FOnChange) then FOnChange(Self);
  164. end;
  165. {-- TMMEcho -------------------------------------------------------------}
  166. procedure TMMEcho.SetParams(aDelay, aGain: Longint);
  167. begin
  168.    if (aDelay <> FDelay) or (aGain <> FGain) then
  169.    begin
  170.       FDelay := aDelay;
  171.       FGain := aGain;
  172.       Changed;
  173.    end;
  174. end;
  175. {-- TMMEcho -------------------------------------------------------------}
  176. procedure TMMEcho.SetDelay(aValue: Longint);
  177. begin
  178.    SetParams(aValue, FGain);
  179. end;
  180. {-- TMMEcho -------------------------------------------------------------}
  181. procedure TMMEcho.SetGain(aValue: Longint);
  182. begin
  183.    SetParams(FDelay, aValue);
  184. end;
  185. {-- TMMEcho -------------------------------------------------------------}
  186. procedure TMMEcho.Store(S: TStream);
  187. begin
  188.    S.WriteBuffer(FDelay,SizeOf(FDelay));
  189.    S.WriteBuffer(FGain,SizeOf(FGain));
  190. end;
  191. {-- TMMEcho -------------------------------------------------------------}
  192. procedure TMMEcho.Load(S: TStream);
  193. var
  194.    aDelay,aGain: Longint;
  195. begin
  196.    S.ReadBuffer(aDelay,SizeOf(aDelay));
  197.    S.ReadBuffer(aGain,SizeOf(aGain));
  198.    SetParams(aDelay,aGain);
  199. end;
  200. {-- TMMEcho -------------------------------------------------------------}
  201. procedure TMMEcho.Assign(Source: TObject);
  202. begin
  203.    if Source is TMMEcho then
  204.    begin
  205.       SetParams(TMMEcho(Source).Delay,TMMEcho(Source).Gain);
  206.    end;
  207. end;
  208. {== TMMEchoList =========================================================}
  209. procedure TMMEchoList.SetEcho(Index: TMMEchoIndex; Echo: TMMEcho);
  210. begin
  211.    Put(Index, Echo);
  212. end;
  213. {-- TMMEchoList ---------------------------------------------------------}
  214. function TMMEchoList.GetEcho(Index: TMMEchoIndex): TMMEcho;
  215. begin
  216.    Result := TMMEcho(Get(Index));
  217. end;
  218. {-- TMMEchoList ---------------------------------------------------------}
  219. function TMMEchoList.AddObject(Item: TObject): TOLSize;
  220. begin
  221.    Result := inherited AddObject(Item);
  222.    (Item as TMMEcho).OnChange := OnChange;
  223. end;
  224. {-- TMMEchoList ---------------------------------------------------------}
  225. procedure TMMEchoList.Assign(Source: TPersistent);
  226. var
  227.    i: integer;
  228.    Echo: TMMEcho;
  229. begin
  230.    if (Source is TMMEchoList) or (Source = nil) then
  231.    begin
  232.       BeginUpdate;
  233.       try
  234.          FReverb.FUpdating := True;
  235.          FreeAll;
  236.          if (Source <> nil) then
  237.          for i := 0 to TMMEchoList(Source).Count-1 do
  238.          begin
  239.             Echo := TMMEcho.Create;
  240.             Echo.Assign(TMMEchoList(Source)[i]);
  241.             AddObject(Echo);
  242.          end;
  243.       finally
  244.          FReverb.FUpdating := False;
  245.          EndUpdate;
  246.       end;
  247.       exit;
  248.    end;
  249.    inherited assign(Source);
  250. end;
  251. {-- TMMEchoList ---------------------------------------------------------}
  252. procedure TMMEchoList.ReadData(S: TStream);
  253. Var
  254.    pBuf: PChar;
  255.    Kennung: Longint;
  256.    ObjCount,
  257.    Index: TOLSize;
  258.    Destroy: Boolean;
  259.    Value: Longint;
  260. begin
  261.    BeginUpdate;
  262.    try
  263.       FReverb.FUpdating := True;
  264.       S.ReadBuffer(Kennung,sizeOf(STREAMKENNUNG));
  265.       if (Kennung <> STREAMKENNUNG) then
  266.          raise EStreamError.Create('Invalid Object stream');
  267.       FreeAll;
  268.       { load stream items }
  269.       S.ReadBuffer(Destroy,SizeOf(Destroy));
  270.       DestroyObjects := Destroy;
  271.       { read string length }
  272.       S.ReadBuffer(Value,SizeOf(Value));
  273.       if Value > 0 then
  274.       begin
  275.          pBuf := StrAlloc(Value+1);
  276.          try
  277.             FillChar(pBuf^, Value+1, 0);
  278.             S.ReadBuffer(pBuf^, Value);
  279.             FReverb.Description := StrPas(pBuf);
  280.          finally
  281.             StrDispose(pBuf);
  282.          end;
  283.       end;
  284.       S.ReadBuffer(Value,SizeOf(Value));
  285.       FReverb.FMaxDelay := Value;
  286.       S.ReadBuffer(Value,SizeOf(Value));
  287.       FReverb.FInputGain := Value;
  288.       S.ReadBuffer(Value,SizeOf(Value));
  289.       FReverb.FInputPan := Value;
  290.       S.ReadBuffer(Value,SizeOf(Value));
  291.       FReverb.FOutputGain := Value;
  292.       S.ReadBuffer(Value,SizeOf(Value));
  293.       FReverb.FFeedBack := Value;
  294.       S.ReadBuffer(ObjCount,SizeOf(Objcount));  { Read in Object count }
  295.       ObjCount := Min(ObjCount,MAXECHOS);
  296.       if Capacity-Count < ObjCount then Capacity := Count+ObjCount;
  297.       { Read in Object Count }
  298.       for Index := 0 to ObjCount-1 do
  299.           AddObject(ReadObjectFromStream(S));
  300.    finally
  301.       FReverb.FUpdating := False;
  302.       EndUpdate;
  303.    end;
  304. end;
  305. {-- TMMEchoList ---------------------------------------------------------}
  306. procedure TMMEchoList.WriteData(S: TStream);
  307. var
  308.    Index,ObjCount: TOlSize;
  309.    Destroy: Boolean;
  310.    Value: Longint;
  311. begin
  312.    { Write list to Stream }
  313.    S.WriteBuffer(STREAMKENNUNG,SizeOf(STREAMKENNUNG));
  314.    Destroy := DestroyObjects;
  315.    S.WriteBuffer(Destroy,SizeOf(Destroy));
  316.    { write string length }
  317.    Value := Length(FReverb.FDescription);
  318.    S.WriteBuffer(Value, SizeOf(Value));
  319. {$IFDEF WIN32}
  320.    S.WriteBuffer(PChar(FReverb.FDescription)^, Length(FReverb.FDescription));
  321. {$ELSE}
  322.    S.WriteBuffer(FReverb.FDescription[1], Length(FReverb.FDescription));
  323. {$ENDIF}
  324.    Value := FReverb.FMaxDelay;
  325.    S.WriteBuffer(Value, SizeOf(Value));
  326.    Value := FReverb.FInputGain;
  327.    S.WriteBuffer(Value, SizeOf(Value));
  328.    Value := FReverb.FInputPan;
  329.    S.WriteBuffer(Value, SizeOf(Value));
  330.    Value := FReverb.FOutputGain;
  331.    S.WriteBuffer(Value, SizeOf(Value));
  332.    Value := FReverb.FFeedBack;
  333.    S.WriteBuffer(Value, SizeOf(Value));
  334.    ObjCount := Count;
  335.    S.WriteBuffer(ObjCount,SizeOf(ObjCount));
  336.    for Index := 0 to Count-1 do
  337.        WriteObjectToStream(Items[Index],S);
  338. end;
  339. {== TMMReverb ===========================================================}
  340. constructor TMMReverb.Create(aOwner: TComponent);
  341. var
  342.    i: integer;
  343. begin
  344.    inherited Create(aOwner);
  345.    FEchos := TMMEchoList.Create;
  346.    FEchos.OnChange := EchosChanged;
  347.    FEchos.FReverb  := Self;
  348.    for i := 0 to MAXECHOS-1 do FEchos.AddObject(TMMEcho.Create);
  349.    FPReverb    := nil;
  350.    FDescription:= 'Untitled';
  351.    FEnabled    := True;
  352.    FOpen       := False;
  353.    FUpdating   := False;
  354.    FMaxDelay   := 250;
  355.    FInputGain  := 80;
  356.    FInputPan   := 0;
  357.    FOutputGain := 100;
  358.    FFeedBack   := 0;
  359.    FFilter     := False;
  360. end;
  361. {-- TMMReverb -----------------------------------------------------------}
  362. destructor TMMReverb.Destroy;
  363. begin
  364.    Close;
  365.    FEchos.Free;
  366.    inherited Destroy;
  367. end;
  368. {-- TMMReverb -----------------------------------------------------------}
  369. procedure TMMReverb.PcmOverflow;
  370. begin
  371.    if assigned(FOnPcmOverflow) then FOnPcmOverflow(Self);
  372. end;
  373. {-- TMMReverb -----------------------------------------------------------}
  374. procedure TMMReverb.Change;
  375. begin
  376.    if assigned(FOnChange) then FOnChange(Self);
  377. end;
  378. {-- TMMReverb -----------------------------------------------------------}
  379. procedure TMMReverb.SetEchos(aValue: TMMEchoList);
  380. begin
  381.    if (aValue <> FEchos) then FEchos.Assign(aValue);
  382. end;
  383. {-- TMMReverb -----------------------------------------------------------}
  384. procedure TMMReverb.EchosChanged(Sender: TObject);
  385. begin
  386.    if not FUpdating then
  387.    begin
  388.       Update;
  389.       Change;
  390.    end;
  391. end;
  392. {-- TMMReverb -----------------------------------------------------------}
  393. procedure TMMReverb.SetPWaveFormat(aValue: PWaveFormatEx);
  394. begin
  395.    if (aValue <> nil) then
  396.    begin
  397.       if not (csDesigning in ComponentState) then
  398.          if not pcmIsValidFormat(aValue) then
  399.             raise EMMReverbError.Create(LoadResStr(IDS_INVALIDFORMAT));
  400.    end;
  401.    inherited SetPWaveFormat(aValue);
  402. end;
  403. {-- TMMReverb -----------------------------------------------------------}
  404. procedure TMMReverb.SaveToIniFile(IniFile: TFileName; Section: string);
  405. var
  406.    i,j: integer;
  407. begin
  408.    if (IniFile <> '') then
  409.    begin
  410.       with TIniFile.Create(IniFile) do
  411.       try
  412.          if Pos('Reverb.',Section) = 0 then Section := 'Reverb.'+Section;
  413.          WriteInteger(Section, 'MaxDelay', MaxDelay);
  414.          WriteInteger(Section, 'InputGain', InputGain);
  415.          WriteInteger(Section, 'InputPan', InputPan);
  416.          WriteInteger(Section, 'OutputGain', OutputGain);
  417.          WriteInteger(Section, 'FeedBack', FeedBack);
  418.          WriteBool(Section, 'Filter', Filter);
  419.          j := 0;
  420.          for i := 0 to Echos.Count-1 do
  421.          with Echos[i] do
  422.          begin
  423.             if (Gain <> 0) then
  424.             begin
  425.                WriteInteger(Section, 'Delay'+IntToStr(j), Delay);
  426.                WriteInteger(Section, 'Gain'+IntToStr(j), Gain);
  427.                inc(j);
  428.             end;
  429.          end;
  430.       finally
  431.          Free;
  432.       end;
  433.    end;
  434. end;
  435. {-- TMMReverb -----------------------------------------------------------}
  436. procedure TMMReverb.ReadFromIniFile(IniFile: TFileName; Section: string);
  437. var
  438.    i,P: integer;
  439. begin
  440.    if (IniFile <> '') then
  441.    begin
  442.       with TIniFile.Create(IniFile) do
  443.       try
  444.          if Pos('Reverb.',Section) = 0 then Section := 'Reverb.'+Section;
  445.          i := ReadInteger(Section, 'MaxDelay', -1);
  446.          if (i > 0) then
  447.          try
  448.             FUpdating := True;
  449.             MaxDelay    := ReadInteger(Section, 'MaxDelay', 1000);
  450.             InputGain   := ReadInteger(Section, 'InputGain', 50);
  451.             InputPan    := ReadInteger(Section, 'InputPan', 50);
  452.             OutputGain  := ReadInteger(Section, 'OutputGain', 50);
  453.             FeedBack    := ReadInteger(Section, 'FeedBack', 0);
  454.             Filter      := ReadBool(Section, 'Filter', True);
  455.             for i := 0 to MAXECHOS-1 do
  456.             with Echos[i] do
  457.             begin
  458.                Delay := ReadInteger(Section, 'Delay'+IntToStr(i), 0);
  459.                Gain  := ReadInteger(Section, 'Gain'+IntToStr(i), 0);
  460.             end;
  461.             P := Pos('.',Section);
  462.             if (P <> 0) then Section := Copy(Section,P+1,MaxInt);
  463.             Description := Section;
  464.          finally
  465.             FUpdating := False;
  466.             Update;
  467.             Change;
  468.          end;
  469.       finally
  470.          Free;
  471.       end;
  472.    end;
  473. end;
  474. {-- TMMReverb -----------------------------------------------------------}
  475. procedure TMMReverb.ReadIniSections(IniFile: TFileName; Strings: TStrings);
  476. var
  477.    i, P: integer;
  478.    Sections: TStringList;
  479. begin
  480.    if (IniFile <> '') and (Strings <> nil) then
  481.    begin
  482.       with TIniFile.Create(IniFile) do
  483.       try
  484.          Sections := TStringList.Create;
  485.          try
  486.             ReadSections(Sections);
  487.             Strings.BeginUpdate;
  488.             try
  489.                Strings.Clear;
  490.                for i := 0 to Sections.Count-1 do
  491.                begin
  492.                   P := Pos('.',Sections[i]);
  493.                   if (P <> 0) then Strings.Add(Copy(Sections[i],P+1,MaxInt));
  494.                end;
  495.             finally
  496.                Strings.EndUpdate;
  497.             end;
  498.          finally
  499.             Sections.Free;
  500.          end;
  501.       finally
  502.          Free;
  503.       end;
  504.    end;
  505. end;
  506. {-- TMMReverb -----------------------------------------------------------}
  507. procedure TMMReverb.DeleteSection(IniFile: TFileName; Section: string);
  508. begin
  509.    if (IniFile <> '') then
  510.    begin
  511.       with TIniFile.Create(IniFile) do
  512.       try
  513.          if Pos('Reverb.',Section) = 0 then Section := 'Reverb.'+Section;
  514.          EraseSection(Section);
  515.       finally
  516.          Free;
  517.       end;
  518.    end;
  519. end;
  520. {-- TMMReverb -----------------------------------------------------------}
  521. procedure TMMReverb.Assign(Source: TPersistent);
  522. begin
  523.    if (Source is TMMReverb) then
  524.    begin
  525.       if (Source <> nil) then
  526.       begin
  527.          Enabled    := TMMReverb(Source).Enabled;
  528.          Description:= TMMReverb(Source).Description;
  529.          MaxDelay   := TMMReverb(Source).MaxDelay;
  530.          InputGain  := TMMReverb(Source).InputGain;
  531.          InputPan   := TMMReverb(Source).InputPan;
  532.          OutputGain := TMMReverb(Source).OutputGain;
  533.          FeedBack   := TMMReverb(Source).FeedBack;
  534.          Filter     := TMMReverb(Source).Filter;
  535.          Echos      := TMMReverb(Source).Echos;
  536.       end;
  537.    end;
  538. end;
  539. {-- TMMReverb -----------------------------------------------------------}
  540. procedure TMMReverb.SetDescription(aValue: String);
  541. begin
  542.    if (aValue <> FDescription) then
  543.    begin
  544.       FDescription := aValue;
  545.       Change;
  546.    end;
  547. end;
  548. {-- TMMReverb -----------------------------------------------------------}
  549. procedure TMMReverb.SetMaxDelay(aValue: integer);
  550. begin
  551.    if (aValue <> FMaxDelay) then
  552.    begin
  553.       FMaxDelay := aValue;
  554.    end;
  555. end;
  556. {-- TMMReverb -----------------------------------------------------------}
  557. procedure TMMReverb.SetEnabled(aValue: Boolean);
  558. begin
  559.    if (aValue <> FEnabled) then
  560.    begin
  561.       FEnabled := aValue;
  562.       if FEnabled then Update;
  563.    end;
  564. end;
  565. {-- TMMReverb -----------------------------------------------------------}
  566. procedure TMMReverb.SetGains(index: integer; aValue: TMMEffectVolume);
  567. begin
  568.    case index of
  569.        0: if (aValue = FInputGain) then exit
  570.           else
  571.           begin
  572.              FInputGain := aValue;
  573.              if FOpen then FPReverb^.InputGain := MulDiv(aValue,256,100);
  574.           end;
  575.        1: if (aValue = FInputPan) then exit
  576.           else
  577.           begin
  578.              FInputPan := aValue;
  579.              if FOpen then FPReverb^.InputPan := MulDiv(aValue,256,100);
  580.           end;
  581.        2: if (aValue = FOutputGain) then exit
  582.           else
  583.           begin
  584.              FOutputGain := aValue;
  585.              if FOpen then FPReverb^.OutputGain := MulDiv(aValue,256,100);
  586.           end;
  587.    end;
  588.    Change;
  589. end;
  590. {-- TMMReverb -----------------------------------------------------------}
  591. procedure TMMReverb.SetFeedBack(aValue: TMMFeedBack);
  592. begin
  593.    if (aValue <> FFeedBack) then
  594.    begin
  595.       FFeedBack := aValue;
  596.       if FOpen then FPReverb^.FeedBack := MulDiv(aValue,256,100);
  597.       Change;
  598.    end;
  599. end;
  600. {-- TMMReverb -----------------------------------------------------------}
  601. procedure TMMReverb.SetFilter(aValue: Boolean);
  602. begin
  603.    if (aValue <> FFilter) then
  604.    begin
  605.       FFilter := aValue;
  606.       if FOpen then FPReverb^.OutputFilter := FFilter;
  607.       Change;
  608.    end;
  609. end;
  610. {-- TMMReverb -----------------------------------------------------------}
  611. procedure TMMReverb.Open;
  612. begin
  613.    if not FOpen then
  614.    begin
  615.       if pcmIsValidFormat(PWaveFormat) then
  616.       begin
  617.          FPReverb := InitReverb(PWaveFormat, FMaxDelay);
  618.          if (FPReverb = nil) then OutOfMemoryError
  619.          else
  620.          begin
  621.             FOpen := True;
  622.             Update;
  623.          end;
  624.       end;
  625.    end;
  626. end;
  627. {-- TMMReverb -----------------------------------------------------------}
  628. procedure TMMReverb.Close;
  629. begin
  630.    if FOpen then
  631.    begin
  632.       FOpen := False;
  633.       DoneReverb(FPReverb);
  634.    end;
  635. end;
  636. {-- TMMReverb -----------------------------------------------------------}
  637. procedure TMMReverb.Process(Buffer: PChar; Length: integer);
  638. begin
  639.    { process the buffer trough the reverb engine }
  640.    if (FPReverb <> nil) then
  641.       if DoReverb(FPReverb, Buffer, Length) then
  642.          GlobalSynchronize(PcmOverflow);
  643. end;
  644. {-- TMMReverb -----------------------------------------------------------}
  645. function TMMReverb.CleanUp(Buffer: PChar; Length: integer): Longint;
  646. begin
  647.    { process the remaining delayed bytes in the delay lines }
  648.    if (FPReverb <> nil) and (FCleanup > 0) then
  649.    begin
  650.       FCleanup := Max(FCleanup - Length,0);
  651.       FillChar(Buffer^, Length, 0);
  652.       if DoReverb(FPReverb, Buffer, Length) then
  653.          GlobalSynchronize(PcmOverflow);
  654.    end;
  655.    { return the remaining bytes to process }
  656.    Result := FCleanup;
  657. end;
  658. {-- TMMReverb -----------------------------------------------------------}
  659. procedure TMMReverb.Update;
  660. var
  661.    i: integer;
  662.    _Echos: TEchoArray;
  663.    NumEchos: integer;
  664. begin
  665.    { setup the reverb engine with the params }
  666.    if FOpen then
  667.    begin
  668.       NumEchos := 0;
  669.       FCleanup := 0;
  670.       for i := 0 to Echos.Count-1 do
  671.       begin
  672.          if (Echos[i].Gain <> 0) then
  673.          begin
  674.             { copy in temp record }
  675.             _Echos[NumEchos].Delay := Echos[i].Delay;
  676.             _Echos[NumEchos].Gain := Echos[i].Gain;
  677.             inc(NumEchos);
  678.             if Echos[i].Delay > FCleanup then FCleanup := Echos[i].Delay;
  679.          end;
  680.       end;
  681.       if (FCleanup > 0) then
  682.       begin
  683.          { convert cleanup time to bytes }
  684.          FCleanup := wioTimeToSamples(PWaveFormat,FCleanup*abs(FFeedBack));
  685.       end;
  686.       { now update the reverb params }
  687.       SetReverb(FPReverb, FFilter, FInputGain, FInputPan,
  688.                 FOutputGain, FFeedBack, NumEchos, @_Echos);
  689.    end;
  690. end;
  691. {-- TMMReverb -----------------------------------------------------------}
  692. procedure TMMReverb.Opened;
  693. begin
  694.    Open;
  695.    inherited Opened;
  696. end;
  697. {-- TMMReverb -----------------------------------------------------------}
  698. procedure TMMReverb.Closed;
  699. begin
  700.    Close;
  701.    inherited Closed;
  702. end;
  703. {-- TMMReverb -----------------------------------------------------------}
  704. procedure TMMReverb.Started;
  705. begin
  706.    Update;
  707.    inherited Started;
  708. end;
  709. {-- TMMReverb -----------------------------------------------------------}
  710. procedure TMMReverb.BufferReady(lpwh: PWaveHdr);
  711. begin
  712.    if Enabled and FOpen then
  713.    begin
  714.       Process(lpwh^.lpData, lpwh^.dwBytesRecorded);
  715.    end;
  716.    inherited BufferReady(lpwh);
  717. end;
  718. {-- TMMReverb -----------------------------------------------------------}
  719. procedure TMMReverb.BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean);
  720. var
  721.    aLength: Longint;
  722. begin
  723.    inherited BufferLoad(lpwh, MoreBuffers);
  724.    if Enabled and FOpen then
  725.    begin
  726.       if not MoreBuffers then
  727.       begin
  728.          aLength := lpwh^.dwBufferLength;
  729.          if Cleanup(lpwh^.lpData, aLength) > 0 then MoreBuffers := True;
  730.          lpwh^.dwBytesRecorded := aLength;
  731.       end
  732.       else Process(lpwh^.lpData, lpwh^.dwBytesRecorded);
  733.    end;
  734. end;
  735. Initialization
  736.    { register echo class for streaming ! }
  737.    DoRegisterClass(@TMMEcho.Load,
  738.                    @TMMEcho.Store,
  739.                    TMMEcho);
  740. end.