首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 使用 Bass.dll 繪製音頻波形圖:解碼流與峰值提取全解析

     編輯:Delphi

前言

波形圖是音頻播放器的核心視覺元素,能直觀展示音樂動態範圍。本文詳解如何在 Delphi 中利用 Bass.dll 的解碼流(BASS_STREAM_DECODE)提取峰值數據,並繪製雙聲道波形圖,支援自定義前景/背景顏色。

核心流程

  1. 建立普通播放流(hs)供播放使用。
  2. 建立解碼流(hs2,旗標 BASS_STREAM_DECODE)專門用於離線提取峰值,不輸出聲音。
  3. 計算總時長,換算所需峰值點數(每 20ms 一個點)。
  4. 循環調用 BASS_ChannelGetLevel 獲取左右聲道峰值,存入動態陣列 Data。
  5. 釋放解碼流,根據 Data 繪製位圖。

關鍵代碼詳解

1. 開啟檔案並提取波形數據

procedure TForm1.Button1Click(Sender: TObject);
var
  Mp3Path: AnsiString;
  i: Cardinal;
  time: Double;
  hs2: HSTREAM;
begin
  BASS_StreamFree(hs);
  OpenDialog1.Filter := 'Mp3 文件(*.mp3)|*.mp3|Wav 文件(*.wav)|*wav';
  if OpenDialog1.Execute then
    Mp3Path := AnsiString(OpenDialog1.FileName);

  hs := BASS_StreamCreateFile(False, PAnsiChar(Mp3Path), 0, 0, 0);
  if hs < BASS_ERROR_ENDED then
    Caption := '打開失敗'
  else begin
    Caption := string(Mp3Path);
    bit.Free;
    bit := TBitmap.Create;
    PaintBox1.Repaint;

    {關鍵:建立解碼流提取波形}
    hs2 := BASS_StreamCreateFile(False, PAnsiChar(Mp3Path), 0, 0, BASS_STREAM_DECODE);
    time := BASS_ChannelBytes2Seconds(hs2, BASS_ChannelGetLength(hs, BASS_POS_BYTE));
    {每 20ms 一個峰值點,故總點數 = time * 1000 / 20 = time * 50}
    SetLength(Data, Trunc(time * 50 + 1));
    for i := 0 to Length(Data) - 1 do
      Data[i] := BASS_ChannelGetLevel(hs2); {低 16 位左聲道,高 16 位右聲道}
    BASS_StreamFree(hs2);

    Draw;
  end;
end;

2. 繪製波形圖

procedure TForm1.Draw;
var
  i, ch: Integer;
  L, R: SmallInt;
begin
  bit.Width := Length(Data);
  bit.Height := PaintBox1.Height;
  ch := bit.Height div 2; {中心線 Y 座標}

  bit.Canvas.Brush.Color := ColorBox1.Selected; {背景色}
  bit.Canvas.FillRect(Bounds(0, 0, bit.Width, bit.Height));

  bit.Canvas.Pen.Color := ColorBox2.Selected; {前景色}
  for i := 0 to Length(Data) - 1 do begin
    L := LoWord(Data[i]); {左聲道峰值 0..32767}
    R := HiWord(Data[i]); {右聲道峰值 0..32767}
    {以中心線為基準,向上畫左聲道,向下畫右聲道}
    bit.Canvas.MoveTo(i, ch - Trunc(L / 32768 * ch));
    bit.Canvas.LineTo(i, ch + Trunc(R / 32768 * ch));
  end;
  PaintBox1.Repaint;
end;

3. 顏色變更即時重繪

procedure TForm1.ColorBox1Change(Sender: TObject);
begin
  Draw;
end;

procedure TForm1.ColorBox2Change(Sender: TObject);
begin
  Draw;
end;

運行效果

介面提供兩個 TColorBox 分別設定背景與波形顏色,選擇後即時更新波形圖。

波形圖繪製效果

完整單元代碼

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    PaintBox1: TPaintBox;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    ColorBox1: TColorBox;
    ColorBox2: TColorBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure ColorBox1Change(Sender: TObject);
    procedure ColorBox2Change(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject);
  private
    procedure Draw;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses Bass;

var
  hs: HSTREAM;
  Data: array of Cardinal;
  bit: TBitmap;

{ ... 完整實現代碼 ... }

end.

技術要點總結

  • 解碼流與播放流分離:解碼流不佔用輸出設備,可快速掃描全曲峰值。
  • 峰值數據結構:BASS_ChannelGetLevel 返回 32 位整數,低 16 位為左聲道,高 16 位為右聲道,範圍 0~32767。
  • 繪製座標換算:將峰值歸一化至控件高度,中心線對稱繪製雙聲道波形。
  • 記憶體管理:動態陣列 Data 隨檔案長度自適應,TBitmap 重建避免殘留。

延伸應用

可在此基礎上增加:播放進度游標同步、波形圖縮放平移、頻譜圖(FFT)切換等進階功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved