⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmptempomap.pas

📁 Delphi的另一款钢琴软件
💻 PAS
字号:
unit cmpTempoMap;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  cmpBarControl, unitMidiGlobals;

const
  MaxTempoChanges = 512;

type
  TTempoChange = object
    fx, fy : Integer;
    fEvent : PMidiEventData;
    selected : boolean;
    procedure Init (x, y : Integer; Event : PMidiEventData; isSelected : boolean);
  end;

  TTempoMap = class(TBarControl)
  private
    fNoTempoChanges : Integer;
    fTempoChangeMap : array [0..MaxTempoChanges - 1] of TTempoChange;
    fPrevY : Integer;
    fMaxTempo: Integer;
    procedure CalcTempoMap;
    procedure SetMaxTempo(const Value: Integer);
  protected
    procedure CalcBarMap; override;
    { Protected declarations }
  public
    constructor Create (AOwner : TComponent); override;
  published
    procedure DisplayBarMapContents; override;
    property MaxTempo : Integer read fMaxTempo write SetMaxTempo default 300;
  end;

procedure Register;

implementation

uses unitMidiTrackStream;

procedure Register;
begin
  RegisterComponents('MIDI', [TTempoMap]);
end;

{ TTempoMap }

procedure TTempoMap.CalcBarMap;
begin
  inherited;
  CalcTempoMap
end;

procedure TTempoMap.CalcTempoMap;
var
  p : PMidiEventData;
  i, idx, h : Integer;
  s : byte;
  tempo : Integer;
  prevTempo : Integer;

  procedure AddTempoChange (tempo : Integer; e : PMidiEventData);
  var
    x, y : Integer;
    selected : boolean;
  begin
    if fNoTempoChanges < MaxTempoChanges then
    begin
      with MidiData.Tracks [Track] do
      begin
        selected := (e^.pos >= SelStartPos) and (e^.pos <= SelEndPos);
        x := CalcPosX (e^.pos);
      end;
      y := h - (tempo + VertScrollbar.Position) * h div MaxTempo + h div 2;
      fTempoChangeMap [fNoTempoChanges].Init (x, y, e, selected);
      Inc (fNoTempoChanges)
    end
  end;

begin
  h := ActiveRect.Bottom - BottomMargin;
  fNoTempoChanges := 0;

  if (Not Assigned (MidiData)) or (not Assigned (MidiData.Tracks [Track])) then Exit;

  idx := MidiData.Tracks [Track].FindEventNo (Iterator.Position, feFirst);
  if idx = -1 then exit;

  i := idx - 1;
  prevTempo := GetBPM (600, Iterator.BeatDiv);
  while i >= 0 do
  begin
    Dec (i);
    if i < 0 then break;
    p := MidiData.Tracks [Track].Event [idx];
    s := p^.data.status;
    if (s = midiMeta) and (byte (p^.data.sysex [0]) = metaTempoChange) then
    begin
      prevTempo :=(LongInt (p^.data.sysex [3]) + 256 * LongInt (p^.data.sysex [2]) + 65536 * LongInt (p^.data.sysex [1])) div 1000;
      prevTempo := GetBPM (prevTempo, Iterator.BeatDiv);
      break
    end
  end;

  fPrevY := h - (prevTempo + VertScrollbar.Position) * h div MaxTempo + h div 2;

  while idx < MidiData.Tracks [Track].EventCount do
  begin
    p := MidiData.Tracks [Track].Event [idx];
    if p^.pos > EndPosition then break;

    s := p^.data.status;
    if (s = midiMeta) and (byte (p^.data.sysex [0]) = metaTempoChange) then
    begin
      tempo :=(LongInt (p^.data.sysex [3]) + 256 * LongInt (p^.data.sysex [2]) + 65536 * LongInt (p^.data.sysex [1])) div 1000;
      tempo := GetBPM (tempo, CalcPosBeatDiv (p^.pos));
      AddTempoChange (tempo, p)
    end;
    Inc (idx);
  end
end;

constructor TTempoMap.Create(AOwner: TComponent);
begin
  inherited Create (AOwner);
  VertScrollBar.LargeChange := 1;
  VertScrollBar.SetParams (150, 0, 300);
  fMaxTempo := 300;
end;

procedure TTempoMap.DisplayBarMapContents;
var
  n : Integer;
  region : HRgn;
  oldColor : TColor;
  prevY : Integer;
begin
  with Canvas do
  begin
    Refresh;
    oldColor := brush.Color;

    region := CreateRectRgn (ActiveRect.left, ActiveRect.Top, ActiveRect.right, ActiveRect.bottom - BottomMargin);
    SelectClipRgn (handle, region);
    DeleteObject (region);

    prevY := fPrevY;
    MoveTo (0, prevY);
    for n := 0 to fNoTempoChanges -1 do
      with fTempoChangeMap [n] do
      begin
        if Selected then
          Brush.Color := clSilver
        else
          Brush.Color := clwhite;
        LineTo (fx, prevY);
        LineTo (fx, fy);
        Rectangle (fx - 3, fy - 3, fx + 3, fy + 3);
        prevY := fy;
      end;
    LineTo (ActiveRect.Right, prevY);
    Brush.Color := oldColor;
  end
end;

procedure TTempoMap.SetMaxTempo(const Value: Integer);
begin
  if fMaxTempo <> Value then
  begin
    fMaxTempo := Value;
    VertScrollBar.SetParams (VertScrollbar.Position, 0, fMaxTempo);
    Refresh
  end
end;

{ TTempoChange }

procedure TTempoChange.Init(x, y: Integer; Event: PMidiEventData;
  isSelected: boolean);
begin
  fx := x;
  fy := y;
  fEvent := Event;
  selected := isSelected
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -