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

Delphi 結合 Bass.dll 實現音樂區段循環播放:同步回調技術解析

     編輯:Delphi

前言

在 Delphi 開發多媒體播放器時,若需實現「A-B 區段循環」這類進階功能,單靠基礎播放控制已無法滿足。本文將深入解析如何利用 Bass.dll 的同步回調機制(BASS_ChannelSetSync),精準控制播放流在指定位置跳轉,從而實現自定義區段的無縫循環播放。

核心原理

Bass.dll 提供的同步回調允許開發者在音頻流到達特定位置(以字節為單位)時觸發自定義函數。我們利用此特性:

  1. 使用者透過滑鼠在波形圖上標記「起始點」(黃線)與「結束點」(紅線)。
  2. 當播放指針到達結束點時,回調函數 MySyncLoop 被觸發。
  3. 回調內立即將播放位置設回起始點,並繼續播放,形成閉環。

關鍵代碼解析

1. 初始化與資源載入

procedure TForm1.FormCreate(Sender: TObject);
begin
  // 初始化 Bass 庫,檢查版本相容性
  if HiWord(BASS_GetVersion) <> BASSVERSION then
    MessageBox(0, 'Bass.dll 版本不符!', nil, MB_ICONERROR);
  if not BASS_Init(-1, 44100, 0, 0, nil) then
    ShowMessage('初始化失敗');
  // ... 介面元件初始化 ...
end;

2. 開啟音樂檔並提取波形數據

procedure TForm1.Button1Click(Sender: TObject);
var
  Mp3Path: AnsiString;
  hs2: HSTREAM;
  time: Double;
  i: Cardinal;
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);
    // 建立解碼流以提取波形峰值
    hs2 := BASS_StreamCreateFile(False, PAnsiChar(Mp3Path), 0, 0, BASS_STREAM_DECODE);
    time := BASS_ChannelBytes2Seconds(hs2, BASS_ChannelGetLength(hs, BASS_POS_BYTE));
    SetLength(Data, Trunc(time * 50 + 1));
    for i := 0 to Length(Data) - 1 do
      Data[i] := BASS_ChannelGetLevel(hs2);
    BASS_StreamFree(hs2);
    Mp3Len := BASS_ChannelGetLength(hs, BASS_POS_BYTE); // 記錄總字節長度
    Draw; // 繪製波形
  end;
end;

3. 滑鼠標記循環區段並註冊同步回調

procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  PosLoop: Cardinal;
begin
  case Button of
    mbLeft: begin // 左鍵:設定起始點(黃線)
      Shape2.Left := X;
      Shape2.Visible := True;
    end;
    mbRight: begin // 右鍵:設定結束點(紅線)並建立回調
      Shape3.Left := X;
      Shape3.Visible := True;
      // 移除舊的同步回調
      BASS_ChannelRemoveSync(hs, hSyncLoop);
      // 計算結束點對應的字節位置
      PosLoop := Trunc(Shape3.Left / PaintBox1.Width * Mp3Len);
      // 註冊 BASS_SYNC_POS 同步回調
      hSyncLoop := BASS_ChannelSetSync(hs, BASS_SYNC_POS, PosLoop, @MySyncLoop, nil);
    end;
  end;
end;

4. 同步回調函數:實現跳轉循環

procedure MySyncLoop(handle: HSYNC; channel, data, user: DWORD); stdcall;
var
  PosStart: Cardinal;
begin
  // 若未設定起始點,則從 0 開始
  if not Form1.Shape2.Visible then
    PosStart := 0
  else
    PosStart := Trunc(Form1.Shape2.Left / Form1.PaintBox1.Width * Mp3Len);
  // 設定播放位置並繼續播放
  BASS_ChannelSetPosition(hs, PosStart, BASS_POS_BYTE);
  BASS_ChannelPlay(hs, False);
end;

運行效果展示

下圖展示了程式執行時的介面:波形圖上方可拖曳黃、紅兩線標記循環區段,播放指針(白線)在區段內往返移動。

循環播放示意圖

完整單元代碼

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    Timer1: TTimer;
    PaintBox1: TPaintBox;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Shape1: TShape;
    Shape2: TShape;
    Shape3: TShape;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    procedure Draw;
  end;

procedure MySyncLoop(handle: HSYNC; channel, data, user: DWORD); stdcall;

var
  Form1: TForm1;

implementation

{$R *.dfm}

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

{ ... 此處省略前文已解析的各事件處理代碼,完整代碼請參考原始附件 ... }

end.

總結

透過 BASS_ChannelSetSync 註冊位置同步回調,配合 BASS_ChannelSetPosition 即時修改播放指針,即可輕鬆實現音樂的任意區段循環播放。此技術同樣適用於有聲書重聽、語言學習跟讀等場景,極大豐富了播放器的互動體驗。

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