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

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Fax.: +49(0)351-8037944               =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/index.html               =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 01.11.98 - 03:53:31 $                                        =}
  24. {========================================================================}
  25. unit MMFade;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29. {$IFDEF WIN32}
  30.   Windows,
  31. {$ELSE}
  32.   WinProcs,
  33.   WinTypes,
  34. {$ENDIF}
  35.   SysUtils,
  36.   Messages,
  37.   Classes,
  38.   Controls,
  39.   MMSystem,
  40.   MMObj,
  41.   MMutils,
  42.   MMMulDiv,
  43.   MMRegs,
  44.   MMPCMSup;
  45. const
  46.     Overflow  : Boolean = False;
  47. type
  48.     PMMFadePoint = ^TMMFadePoint;
  49.     TMMFadePoint = record
  50.        Offset    : Longint;
  51.        Volume    : Longint;
  52.        VolumeL   : Longint;
  53.        VolumeR   : Longint;
  54.        Selected  : LongBool;
  55.     end;
  56.     PMMFadeSeg   = ^TMMFadeSeg;
  57.     TMMFadeSeg   = record
  58.        ptStart   : TMMFadePoint;
  59.        ptEnd     : TMMFadePoint;
  60.     end;
  61. const
  62.     { Maximum List size }
  63.     MaxFadeListSize   = Maxint div (sizeOf(TMMFadePoint)*sizeOf(TMMFadePoint));
  64. type
  65.     PMMFadeArray = ^TMMFadeArray;
  66.     TMMFadeArray = array[0..MaxFadeListSize-1] of TMMFadePoint;
  67.     {-- TMMFadeList -----------------------------------------------------}
  68.     TMMFadeList = class(TMMObject)
  69.     private
  70.        FList        : PMMFadeArray;
  71.        FCount       : Integer;
  72.        FCapacity    : Integer;
  73.        FCurIndex    : Longint;
  74.        FStartOffset : Longint;
  75.        FStartVolume : Longint;
  76.        FStartVolumeL: Longint;
  77.        FStartVolumeR: Longint;
  78.     protected
  79.        procedure Error; virtual;
  80.        procedure Grow; virtual;
  81.        function  Get(Index: Integer): PMMFadePoint;
  82.        procedure Put(Index: Integer; Point: PMMFadePoint);
  83.        procedure SetCapacity(NewCapacity: Integer);
  84.        procedure SetCount(NewCount: Integer);
  85.     public
  86.         destructor  Destroy; override;
  87.         procedure Clear;
  88.         procedure Sort;
  89.         function  Add(Point: TMMFadePoint): Integer;
  90.         procedure Insert(Index: Integer; Point: TMMFadePoint);
  91.         procedure Delete(Index: Integer);
  92.         function  Selected(Index: Integer): Boolean;
  93.         function  QueryFadePoint(Point: TMMFadePoint): Boolean;
  94.         function  AddFadePoint(Point: TMMFadePoint; Align: Boolean): Boolean;
  95.         function  LocateFadePoint(Offset: Longint): integer;
  96.         function  FindFadePoint(Offset: Longint): integer;
  97.         function  CalcFadeVolume(Offset: Longint): Longint;
  98.         procedure Assign(Source: TPersistent); override;
  99.         procedure AssignEnvelope(Source: TPersistent); virtual;
  100.         procedure AssignToEnvelope(Dest: TPersistent); virtual;
  101.         function  First: PMMFadePoint;
  102.         function  Last: PMMFadePoint;
  103.         function  Expand: TMMFadeList;
  104.         property  Capacity: Integer read FCapacity write SetCapacity;
  105.         property  Count: Integer read FCount write SetCount;
  106.         property  Points[Index: Integer]: PMMFadePoint read Get write Put; default;
  107.         property  List: PMMFadeArray read FList;
  108.         property  CurIndex: Longint read FCurIndex write FCurIndex;
  109.         property  StartOffset: Longint read FStartOffset write FStartOffset;
  110.         property  StartVolumeL: Longint read FStartVolumeL write FStartVolumeL;
  111.         property  StartVolumeR: Longint read FStartVolumeR write FStartVolumeR;
  112.     end;
  113. function pcmVolumeFade(pwfx: PWaveFormatEx; lpData: PChar;
  114.                        dwSrcLen: TDataSize; FadeList: TMMFadeList): Boolean;
  115. function pcmVolumeFade8(pwfx: PWaveFormatEx; lpData: PChar;
  116.                         dwSrcLen: TDataSize; FadeList: TMMFadeList): Boolean;
  117. function pcmVolumeFade16(pwfx: PWaveFormatEx; lpData: PChar;
  118.                          dwSrcLen: TDataSize; FadeList: TMMFadeList): Boolean;
  119. implementation
  120. uses
  121.     Consts,
  122.     {$IFDEF DELPHI6}
  123.     RTLConsts,
  124.     {$ENDIF}
  125.     MMEnvelp;
  126. {------------------------------------------------------------------------}
  127. {$IFDEF DELPHI3}
  128. procedure ListError(const Ident: string);
  129. begin
  130.    raise EListError.Create(Ident);
  131. end;
  132. {$ELSE}
  133. procedure ListError(Ident: Word);
  134. begin
  135.    raise EListError.CreateRes(Ident);
  136. end;
  137. {$ENDIF}
  138. {------------------------------------------------------------------------}
  139. procedure ListIndexError;
  140. begin
  141.    ListError(SListIndexError);
  142. end;
  143. {== TMMFadeList =========================================================}
  144. destructor TMMFadeList.Destroy;
  145. begin
  146.    FStartVolume := 0;
  147.    Clear;
  148. end;
  149. {-- TMMFadeList ---------------------------------------------------------}
  150. procedure TMMFadeList.Error;
  151. begin
  152.    ListIndexError;
  153. end;
  154. {-- TMMFadeList ---------------------------------------------------------}
  155. procedure TMMFadeList.Clear;
  156. begin
  157.    SetCount(0);
  158.    SetCapacity(0);
  159. end;
  160. {-- TMMFadeList ---------------------------------------------------------}
  161. { QueryPoint sagt, ob dieser punkt eingefuegt werden kann.                    }
  162. function TMMFadeList.QueryFadePoint(Point: TMMFadePoint): Boolean;
  163. var
  164.    i: integer;
  165. begin
  166.    Result := True;
  167.    for i := 0 to Count-1 do
  168.    begin
  169.       if ((i = 0) and (Point.Offset <= Points[i]^.Offset)) or
  170.          ((i = Count-1) and (Point.Offset >= Points[i]^.Offset)) or
  171.          (Points[i]^.Offset = Point.Offset) then
  172.       begin
  173.          Result := False;
  174.          exit;
  175.       end;
  176.    end;
  177. end;
  178. {-- TMMFadeList ---------------------------------------------------------}
  179. function TMMFadeList.AddFadePoint(Point: TMMFadePoint; Align: Boolean): Boolean;
  180. var
  181.   i: integer;
  182. begin
  183.    Result := False;
  184.    if QueryFadePoint(Point) then     { passt hier Punkt ueberhaupt hin ? }
  185.    begin
  186.       i := LocateFadePoint(Point.Offset);
  187.       if (i < 1) or (i >= Count) then Add(Point)
  188.       else
  189.       begin
  190.          { neuen Punkt genau auf Linie zwischen zwei Punken einf黦en }
  191.          if Align then
  192.          with Point do
  193.          begin
  194.             Volume := CalcFadeVolume(Offset);
  195.          end;
  196.          Insert(i, Point);
  197.       end;
  198.       Result := True;
  199.    end;
  200. end;
  201. {-- TMMFadeList ---------------------------------------------------------}
  202. function TMMFadeList.Add(Point: TMMFadePoint): Integer;
  203. begin
  204.    Result := FCount;
  205.    if Result = FCapacity then Grow;
  206.    FList^[Result] := Point;
  207.    inc(FCount);
  208. end;
  209. {-- TMMFadeList ---------------------------------------------------------}
  210. procedure TMMFadeList.Insert(Index: Integer; Point: TMMFadePoint);
  211. begin
  212.    if (Index < 0) or (Index > FCount) then Error;
  213.    if FCount = FCapacity then Grow;
  214.    if Index < FCount then
  215.       System.Move(FList^[Index], FList^[Index + 1],
  216.                  (FCount - Index) * SizeOf(TMMFadePoint));
  217.    FList^[Index] := Point;
  218.    Inc(FCount);
  219. end;
  220. {-- TMMFadeList ---------------------------------------------------------}
  221. procedure TMMFadeList.Delete(Index: Integer);
  222. begin
  223.    if (Index < 0) or (Index >= FCount) then Error;
  224.    Dec(FCount);
  225.    if Index < FCount then
  226.       System.Move(FList^[Index + 1], FList^[Index],
  227.                  (FCount - Index) * SizeOf(TMMFadePoint));
  228. end;
  229. {-- TMMFadeList ---------------------------------------------------------}
  230. function TMMFadeList.Selected(Index: Integer): Boolean;
  231. begin
  232.    if (Index < 0) or (Index >= FCount) then Error;
  233.    Result := FList^[Index].Selected;
  234. end;
  235. {-- TMMFadeList ---------------------------------------------------------}
  236. function TMMFadeList.First: PMMFadePoint;
  237. begin
  238.    Result := Get(0);
  239. end;
  240. {-- TMMFadeList ---------------------------------------------------------}
  241. function TMMFadeList.Last: PMMFadePoint;
  242. begin
  243.    Result := Get(FCount-1);
  244. end;
  245. {-- TMMFadeList ---------------------------------------------------------}
  246. function TMMFadeList.Get(Index: Integer): PMMFadePoint;
  247. begin
  248.    if (Index < 0) or (Index >= FCount) then Error;
  249.    Result := @FList^[Index];
  250. end;
  251. {-- TMMFadeList ---------------------------------------------------------}
  252. procedure TMMFadeList.Put(Index: Integer; Point: PMMFadePoint);
  253. begin
  254.    if (Index < 0) or (Index >= FCount) then Error;
  255.    FList^[Index] := Point^;
  256. end;
  257. {-- TMMFadeList ---------------------------------------------------------}
  258. procedure TMMFadeList.Grow;
  259. var
  260.   Delta: Integer;
  261. begin
  262.    if FCapacity > 8 then
  263.       Delta := 16
  264.    else if FCapacity > 4 then
  265.       Delta := 8
  266.    else
  267.       Delta := 4;
  268.   SetCapacity(FCapacity + Delta);
  269. end;
  270. {-- TMMFadeList ---------------------------------------------------------}
  271. procedure TMMFadeList.SetCapacity(NewCapacity: Integer);
  272. begin
  273.    if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then Error;
  274.    if NewCapacity <> FCapacity then
  275.    begin
  276.      {$IFDEF WIN32}
  277.      ReallocMem(FList, NewCapacity * SizeOf(TMMFadePoint));
  278.      {$ELSE}
  279.      if NewCapacity = 0 then
  280.      begin
  281.         GlobalFreePtr(FList);
  282.         FList := nil;
  283.      end
  284.      else
  285.      begin
  286.         if FCapacity = 0 then
  287.            FList := GlobalAllocPtr(HeapAllocFlags, NewCapacity*sizeOf(TMMFadePoint))
  288.         else
  289.            FList := GlobalReallocPtr(FList, NewCapacity*sizeOf(TMMFadePoint), HeapAllocFlags);
  290.         if FList = nil then
  291.            raise EStreamError.Create(LoadStr(SMemoryStreamError));
  292.      end;
  293.      {$ENDIF}
  294.      FCapacity := NewCapacity;
  295.    end;
  296. end;
  297. {-- TMMFadeList ---------------------------------------------------------}
  298. function TMMFadeList.Expand: TMMFadeList;
  299. begin
  300.    if FCount = FCapacity then Grow;
  301.    Result := Self;
  302. end;
  303. {-- TMMFadeList ---------------------------------------------------------}
  304. procedure TMMFadeList.SetCount(NewCount: Integer);
  305. begin
  306.    if (NewCount < 0) or (NewCount > MaxListSize) then Error;
  307.    if NewCount > FCapacity then SetCapacity(NewCount);
  308.    if NewCount > FCount then
  309.       FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(TMMFadePoint), 0);
  310.    FCount := NewCount;
  311. end;
  312. {-- TMMFadeList ---------------------------------------------------------}
  313. procedure TMMFadeList.Assign(Source: TPersistent);
  314. var
  315.    i: integer;
  316.    p: TMMFadePoint;
  317. begin
  318.    if (Source is TMMFadeList) or (Source = nil) then
  319.    begin
  320.       if (Source <> Self) then
  321.       begin
  322.          Clear;
  323.          if (Source <> nil) then
  324.          begin
  325.             Capacity := TMMFadeList(Source).Count;
  326.             for i := 0 to TMMFadeList(Source).Count-1 do
  327.             begin
  328.                p := TMMFadeList(Source).Points[i]^;
  329.                p.Selected := False;
  330.                Add(p);
  331.             end;
  332.          end;
  333.       end;
  334.    end
  335.    else inherited assign(Source);
  336. end;
  337. {-- TMMFadeList ---------------------------------------------------------}
  338. procedure TMMFadeList.AssignEnvelope(Source: TPersistent);
  339. var
  340.    i: integer;
  341.    p: TMMFadePoint;
  342. begin
  343.    if (Source is TMMEnvelope) or (Source = nil) then
  344.    begin
  345.       Clear;
  346.       if (Source <> nil) then
  347.       begin
  348.          Capacity := TMMEnvelope(Source).Count;
  349.          for i := 0 to TMMEnvelope(Source).Count-1 do
  350.          begin
  351.             p.Offset   := TMMEnvelope(Source).Points[i].X_Value;
  352.             p.Volume   := TMMEnvelope(Source).Points[i].Y_Value;
  353.             p.Selected := False;
  354.             Add(p);
  355.          end;
  356.       end;
  357.    end
  358.    else inherited assign(Source);
  359. end;
  360. {-- TMMFadeList ---------------------------------------------------------}
  361. procedure TMMFadeList.AssignToEnvelope(Dest: TPersistent);
  362. var
  363.    i: integer;
  364.    aPoint: TMMEnvelopePoint;
  365. begin
  366.    if (Dest <> nil) and (Dest is TMMEnvelope) then
  367.    begin
  368.       TMMEnvelope(Dest).Clear;
  369.       aPoint := TMMEnvelopePoint.Create;
  370.       try
  371.          for i := 0 to Count-1 do
  372.          begin
  373.             aPoint.X_Value  := Points[i]^.Offset;
  374.             aPoint.Y_Value  := Points[i]^.Volume;
  375.             aPoint.Selected := False;
  376.             TMMEnvelope(Dest).AddPoint(aPoint,False);
  377.          end;
  378.       finally
  379.         aPoint.Free;
  380.       end;
  381.    end;
  382. end;
  383. {-- TMMFadeList --------------------------------------------------------}
  384. function TMMFadeList.LocateFadePoint(Offset: Longint): integer;
  385. { LocatePoint returns the Index of the first point, which lies right   }
  386. { from Offset. Is the list empty -1, is there no other element Count(!)     }
  387. var
  388.    L, H : integer;
  389. begin
  390.    if (Count = 0) then
  391.    begin
  392.       Result := -1;
  393.    end
  394.    else
  395.    begin
  396.       if Points[Count-1]^.Offset <= Offset then
  397.       begin
  398.          Result := Count;
  399.       end
  400.       else
  401.       begin
  402.          L := 0;
  403.          H := Count-1;
  404.          Result := H shr 1;
  405.          while L < H do
  406.          begin
  407.             if Points[Result]^.Offset <= Offset then
  408.                L := Result+1
  409.             else
  410.                H := Result;
  411.             Result := (L + H) shr 1;
  412.          end;
  413.       end;
  414.    end;
  415. end;
  416. {-- TMMFadeList --------------------------------------------------------}
  417. { FindPoint gibt genau den Index des Punktes zurueck, oder -1 }
  418. function TMMFadeList.FindFadePoint(Offset: Longint): integer;
  419. var
  420.   i : integer;
  421. begin
  422.    Result := -1;
  423.    i := LocateFadePoint(Offset);
  424.    if (i > 0) and (i <= Count) then
  425.    begin
  426.       if Offset = Points[i-1]^.Offset then
  427.       begin
  428.          Result := i-1;
  429.       end;
  430.    end;
  431. end;
  432. {-- TMMFadeList --------------------------------------------------------}
  433. function TMMFadeList.CalcFadeVolume(Offset: Longint): Longint;
  434. var
  435.    i: integer;
  436. begin
  437.    Result := 0;
  438.    i := LocateFadePoint(Offset);
  439.    if (i > 0) then
  440.    begin
  441.       i := Min(i,Count-1);
  442.       if (i > 0) then
  443.           if Points[i]^.Offset > Points[i-1]^.Offset then
  444.              Result := Points[i-1]^.Volume +
  445.                        MulDiv32(Points[i]^.Volume - Points[i-1]^.Volume,
  446.                                 Offset - Points[i-1]^.Offset,
  447.                                 Points[i]^.Offset - Points[i-1]^.Offset);
  448.    end;
  449. end;
  450. {-- TMMFadeList --------------------------------------------------------}
  451. procedure TMMFadeList.Sort;
  452. var
  453.    i,j,h: integer;
  454.    p: TMMFadePoint;
  455. begin          { Start Shell-Sort }
  456.    h := 1;
  457.    while h <= Count div 9 do h := h*3 + 1;
  458.    while h > 0 do
  459.    begin
  460.       for i := h to Count-1 do
  461.       begin
  462.          p := Points[i]^;
  463.          j := i;
  464.          while ( j >= h ) and (Points[j-h]^.Offset > p.Offset) do
  465.          begin
  466.             Points[j]^ := Points[j-h]^;
  467.             dec(j, h);
  468.          end;
  469.          Points[j]^ := p;
  470.       end;
  471.       h := h div 3;
  472.    end;
  473. end;
  474. {*************************************************************************}
  475. {$IFDEF USEASM}
  476. {$IFDEF WIN32}{$L MMFADE32.OBJ}{$ELSE}{$L MMFADE16.OBJ}{$ENDIF}
  477. {$F+}
  478. function pcmFade8(nChannles: integer; lpData: PChar; dwSrcLen: Longint;
  479.                   pFade: PMMFadeSeg): TMMFadePoint;
  480.                   {$IFDEF WIN32}pascal;{$ENDIF}external;
  481. function pcmFade16(nChannels: integer; lpData: PChar; dwSrcLen: Longint;
  482.                    pFade: PMMFadeSeg): TMMFadePoint;
  483.                   {$IFDEF WIN32}pascal;{$ENDIF}external;
  484. {$F-}
  485. {$ELSE}
  486. (*************************************************************************)
  487. function pcmFade8(nChannels: integer; lpData: PChar;
  488.                   dwSrcLen: Longint; pFade: PMMFadeSeg): TMMFadePoint;
  489. Label Loop,Next;
  490. var
  491.    ACC, M, R: Longint; { Hilfsvariablen           }
  492.    Dir      : integer; { kann nur +1 oder -1 sein }
  493.    DY,DX    : Longint;
  494.    sVolume  : Longint;
  495.    eVolume  : Longint;
  496.    Count    : Longint;
  497.    pB       : PByte;
  498.    ch       : integer;
  499. begin
  500.    with pFade^ do
  501.    begin
  502.       pB      := Pointer(lpData);             { start with left channel }
  503.       ch      := 1;
  504.       sVolume := ptStart.VolumeL;
  505.       eVolume := ptEnd.VolumeL;
  506. Loop:
  507.       { nichts zu tun ? }
  508.       if (sVolume = VOLUMEBASE) and (eVolume = VOLUMEBASE) then
  509.           goto next;
  510.       Count := Min(ptEnd.Offset-ptStart.Offset,dwSrcLen)div (nChannels);
  511.       if Count < 1 then
  512.          goto Next;
  513.       { silence ? }
  514.       if (sVolume = 0) and (eVolume = 0) then
  515.       begin
  516.          while (Count > 0) do
  517.          begin
  518.             pB^ := 128;
  519.             inc(pB,nChannels);
  520.             dec(Count);
  521.          end;
  522.          goto Next;
  523.       end;
  524.       { Byte Abstand da Delta-T immer positiv da TB rechts ist }
  525.       DX := (ptEnd.Offset-ptStart.Offset) div nChannels;
  526.       { Fehler Accu wird auf 50% initialisiert }
  527.       ACC := DX shr 1;
  528.       DY := eVolume-sVolume;{ Volume-Diff }
  529.       if DY < 0 then DY := -DY;
  530.       M := DY div DX;                { Steigung abgrundet }
  531.       R := DY mod DX;
  532.       Dir := 1;                      { Vorgabe : Anstieg }
  533.       if (eVolume < sVolume) then
  534.       begin
  535.          Dir := -Dir;                { Abstieg }
  536.          M := -M;
  537.       end;
  538.       if (DY = 0) then
  539.       begin                          { ebene Volumekurve }
  540.          while Count > 0 do
  541.          begin
  542.             pB^ := pcmSampleClip8(((pB^-128) * sVolume) div VOLUMEBASE) + 128;
  543.             inc(pB,nChannels);
  544.             dec(Count);
  545.          end;
  546.       end
  547.       else
  548.       begin
  549.          if (M <> 0) then            { grosse Steigung }
  550.          begin
  551.             while Count > 0 do
  552.             begin
  553.                pB^ := pcmSampleClip8(((pB^-128) * sVolume) div VOLUMEBASE) + 128;
  554.                inc(pB,nChannels);
  555.                Inc(sVolume,M);
  556.                Dec(Acc,R);
  557.                if Acc < 0 then
  558.                begin
  559.                   Inc(Acc, DX);
  560.                   inc(sVolume,Dir);
  561.                end;
  562.                dec(Count);
  563.             end;
  564.          end
  565.          else                        { flache Steigung }
  566.          begin
  567.             while Count > 0 do
  568.             begin
  569.                pB^ := pcmSampleClip8(((pB^-128) * sVolume) div VOLUMEBASE) + 128;
  570.                inc(pB,nChannels);
  571.                Dec(Acc,R);
  572.                if Acc < 0 then
  573.                begin
  574.                   Inc(Acc, DX);
  575.                   Inc(sVolume,Dir);
  576.                end;
  577.                dec(Count);
  578.             end;
  579.          end;
  580.       end;
  581. Next:
  582.       if (ch = 1) then
  583.       begin
  584.          inc(ch);
  585.          Result.VolumeL := sVolume;
  586.          if (nChannels = 2) then
  587.          begin
  588.             { go to right channel }
  589.             pB      := Pointer(lpData+sizeOf(Byte));
  590.             sVolume := ptStart.VolumeR;
  591.             eVolume := ptEnd.VolumeR;
  592.             goto Loop;
  593.          end;
  594.       end
  595.       else
  596.       begin
  597.          Result.VolumeR := sVolume;
  598.       end;
  599.    end;
  600. end;
  601. (*************************************************************************)
  602. function pcmFade16(nChannels: integer; lpData: PChar;
  603.                    dwSrcLen: Longint; pFade: PMMFadeSeg): TMMFadePoint;
  604. Label Loop,Next;
  605. var
  606.    ACC, M, R: Longint; { Hilfsvariablen           }
  607.    Dir      : integer; { kann nur +1 oder -1 sein }
  608.    DY,DX    : Longint;
  609.    sVolume  : Longint;
  610.    eVolume  : Longint;
  611.    Count    : Longint;
  612.    pS       : PSmallint;
  613.    ch       : integer;
  614. begin
  615.    with pFade^ do
  616.    begin
  617.       pS      := Pointer(lpData);             { start with left channel }
  618.       ch      := 1;
  619.       sVolume := ptStart.VolumeL;
  620.       eVolume := ptEnd.VolumeL;
  621. Loop:
  622.       { nothing to do ? }
  623.       if (sVolume = VOLUMEBASE) and (eVolume = VOLUMEBASE) then
  624.           goto Next;
  625.       Count := Min(ptEnd.Offset-ptStart.Offset,dwSrcLen)div (2*nChannels);
  626.       if Count < 1 then
  627.          goto Next;
  628.       { silence ? }
  629.       if (sVolume = 0) and (eVolume = 0) then
  630.       begin
  631.          while (Count > 0) do
  632.          begin
  633.             pS^ := 0;
  634.             inc(pS,nChannels);
  635.             dec(Count);
  636.          end;
  637.          goto Next;
  638.       end;
  639.       { Byte Abstand da Delta-T immer positiv da TB rechts ist }
  640.       DX := (ptEnd.Offset-ptStart.Offset) div (2*nChannels);
  641.       { Fehler Accu wird auf 50% initialisiert }
  642.       ACC := DX shr 1;
  643.       Dir := 1;                      { Vorgabe : Anstieg }
  644.       DY := eVolume-sVolume;         { Volume-Diff }
  645.       if DY < 0 then
  646.       begin
  647.          DY := -DY;
  648.          Dir := -Dir;                { Abstieg }
  649.       end;
  650.       M := DY div DX;                { Steigung abgrundet }
  651.       R := DY mod DX;
  652.       if Dir < 0 then M := -M;
  653.       if (DY = 0) then
  654.       begin                          { ebene Volumekurve }
  655.          while Count > 0 do
  656.          begin
  657.             pS^ := pcmSampleClip16((pS^ * sVolume) div VOLUMEBASE);
  658.             inc(pS,nChannels);
  659.             dec(Count);
  660.          end;
  661.       end
  662.       else
  663.       begin
  664.          if (M <> 0) then            { grosse Steigung }
  665.          begin
  666.             while (Count > 0) do
  667.             begin
  668.                pS^ := pcmSampleClip16((pS^ * sVolume) div VOLUMEBASE);
  669.                inc(pS,nChannels);
  670.                sVolume := sVolume + M;
  671.                Dec(Acc,R);
  672.                if Acc < 0 then
  673.                begin
  674.                   Inc(Acc, DX);
  675.                   sVolume := sVolume - 1;
  676.                end;
  677.                dec(Count);
  678.             end;
  679.          end
  680.          else                        { flache Steigung }
  681.          begin
  682.             while Count > 0 do
  683.             begin
  684.                pS^ := pcmSampleClip16((pS^ * sVolume) div VOLUMEBASE);
  685.                inc(pS,nChannels);
  686.                Dec(Acc,R);
  687.                if Acc < 0 then
  688.                begin
  689.                   Inc(Acc, DX);
  690.                   sVolume := sVolume + Dir;
  691.                end;
  692.                dec(Count);
  693.             end;
  694.          end;
  695.       end;
  696. Next:
  697.       if (ch = 1) then
  698.       begin
  699.          inc(ch);
  700.          Result.VolumeL := sVolume;
  701.          if (nChannels = 2) then
  702.          begin
  703.             { go to right channel }
  704.             pS      := Pointer(lpData+sizeOf(Smallint));
  705.             sVolume := ptStart.VolumeR;
  706.             eVolume := ptEnd.VolumeR;
  707.             goto Loop;
  708.          end;
  709.       end
  710.       else
  711.       begin
  712.          Result.VolumeR := sVolume;
  713.       end;
  714.    end;
  715. end;
  716. {$ENDIF}
  717. (*************************************************************************)
  718. function pcmVolumeFade(pwfx: PWaveFormatEx; lpData: PChar;
  719.                        dwSrcLen: TDataSize; FadeList: TMMFadeList): Boolean;
  720. begin
  721.    Result := False;
  722.    if (pwfx = nil) or (pwfx^.wFormatTag <> WAVE_FORMAT_PCM) then exit;
  723.    if (pwfx^.wBitsPerSample = 8) then
  724.    begin
  725.       Result := pcmVolumeFade8(pwfx, lpData, dwSrcLen, FadeList);
  726.    end
  727.    else
  728.    begin
  729.       Result := pcmVolumeFade16(pwfx, lpData, dwSrcLen, FadeList);
  730.    end;
  731. end;
  732. (*************************************************************************)
  733. function pcmVolumeFade8(pwfx: PWaveFormatEx; lpData: PChar;
  734.                         dwSrcLen: TDataSize; FadeList: TMMFadeList): Boolean;
  735. var
  736.    Fade: TMMFadeSeg;
  737.    p   : TMMFadePoint;
  738.    nBytes: Longint;
  739. begin
  740.    Overflow := False;
  741.    if (pwfx^.wFormatTag = 1) then
  742.    with FadeList do
  743.    begin
  744.       CurIndex := Max(LocateFadePoint(StartOffset)-1,0);
  745.       while (dwSrcLen > 0) and (CurIndex < Count) do
  746.       with Points[CurIndex]^ do
  747.       begin
  748.          nBytes := Min(dwSrcLen,(Offset-StartOffset));
  749.          if (nBytes > 0) then
  750.          begin
  751.             { start point }
  752.             Fade.ptStart.Offset  := StartOffset;
  753.             Fade.ptStart.VolumeL := StartVolumeL;
  754.             Fade.ptStart.VolumeR := StartVolumeR;
  755.             { end point }
  756.             Fade.ptEnd.Offset    := Offset;
  757.             Fade.ptEnd.VolumeL   := VolumeL;
  758.             Fade.ptEnd.VolumeR   := VolumeR;
  759.             p := pcmFade8(pwfx^.nChannels,lpData,nBytes,@Fade);
  760.             StartVolumeL := p.VolumeL;
  761.             StartVolumeR := p.VolumeR;
  762.             {$IFDEF WIN32}
  763.             inc(lpData,nBytes);
  764.             {$ELSE}
  765.             incHuge(lpData,nBytes);
  766.             {$ENDIF}
  767.             dec(dwSrcLen,nBytes);
  768.             StartOffset := StartOffset + nBytes;
  769.          end;
  770.          { aktuall segment done ? }
  771.          if StartOffset >= Offset then
  772.             CurIndex := CurIndex+1;
  773.       end;
  774.    end;
  775.    Result := Overflow;
  776. end;
  777. (*************************************************************************)
  778. function pcmVolumeFade16(pwfx: PWaveFormatEx; lpData: PChar;
  779.                          dwSrcLen: TDataSize; FadeList: TMMFadeList): Boolean;
  780. var
  781.    Fade: TMMFadeSeg;
  782.    p   : TMMFadePoint;
  783.    nBytes: Longint;
  784. begin
  785.    Overflow := False;
  786.    if (pwfx^.wFormatTag = 1) then
  787.    with FadeList do
  788.    begin
  789.       CurIndex := Max(LocateFadePoint(StartOffset)-1,0);
  790.       while (dwSrcLen > 0) and (CurIndex < Count) do
  791.       with Points[CurIndex]^ do
  792.       begin
  793.          nBytes := Min(dwSrcLen,(Offset-StartOffset));
  794.          if (nBytes > 0) then
  795.          begin
  796.             { start point }
  797.             Fade.ptStart.Offset  := StartOffset;
  798.             Fade.ptStart.VolumeL := StartVolumeL;
  799.             Fade.ptStart.VolumeR := StartVolumeR;
  800.             { end point }
  801.             Fade.ptEnd.Offset    := Offset;
  802.             Fade.ptEnd.VolumeL   := VolumeL;
  803.             Fade.ptEnd.VolumeR   := VolumeR;
  804.             p := pcmFade16(pwfx^.nChannels,lpData,nBytes,@Fade);
  805.             StartVolumeL := p.VolumeL;
  806.             StartVolumeR := p.VolumeR;
  807.             {$IFDEF WIN32}
  808.             inc(lpData,nBytes);
  809.             {$ELSE}
  810.             incHuge(lpData,nBytes);
  811.             {$ENDIF}
  812.             dec(dwSrcLen,nBytes);
  813.             StartOffset := StartOffset + nBytes;
  814.          end;
  815.          { aktuall segment done ? }
  816.          if StartOffset >= Offset then
  817.             CurIndex := CurIndex+1;
  818.       end;
  819.    end;
  820.    Result := Overflow;
  821. end;
  822. end.