OpenGL (12.) - visualizační plugin pro WinAMP

Pokud jste již někdy viděli jakýkoliv vizualizační plugin pro WinAMP, určitě vám vrtalo hlavou, jak takový plugin vytvořit. V praxi se nejedná o nic jiného než obyčejnou dynamickou knihovnu, ze které si WinAMP bude volat potřebné funkce.

Oficiální stránky jsou na adrese www.winamp.com/nsdn/winamp2x/dev/plugins, kde jsou i příklady v céčku.

První věc, kterou musíte udělat je vytvořit dynamickou knihovnu (File - New - Other... - DLL Wizard). Doporučuji název projektu vis_cokoliv, protože nový WinAMP3beta načte jen knihovny začínající na vis_. WinAMP očekává od DLL exportaci hlavičky:

library vis_plugin_DEMO;

uses
  Windows,
  GLplugin in 'GLplugin.pas',
  setup in 'Setup.pas' {Form1};

{$R *.RES}

exports winampVisGetHeader;

end.

Formulář setup slouží k nastavení pluginu (rozlišení, fullscreen, reakce na špičky, ...), v GLplugin.pas jsou uloženy všechny potřebné funkce. Potom do unity obsahující zbytek zdrojáku musíme přidat strukturu dat:

unit GLplugin;

interface

uses Windows, Messages, OpenGL, setup;


type
  PWinampVisModule = ^TwinampVisModule;
  TwinampVisModule = record
    description : PChar;
    hwndParent  : HWND;
    hDllInstance: HINST;
    sRate       : Cardinal;
    nCh         : Cardinal;
    latencyMs   : Cardinal;
    delayMs     : Cardinal;
    spectrumNCh : Cardinal;
    waveformNCh : Cardinal;
    spectrumData: Array [0..1, 0..575] of Byte;
    waveformData: Array [0..1, 0..575] of Byte;
    Config      : procedure(const PVisModule:PwinampVisModule);cdecl;
    Init        : function(const PVisModule:PwinampVisModule):Integer;cdecl;
    Render      : function(const PVisModule:PwinampVisModule):Integer;cdecl;
    Quit        : procedure(const PVisModule:PwinampVisModule);cdecl;
    userData    : procedure; cdecl;
  end;

  PwinampVisHeader = ^TwinampVisHeader;
  TwinampVisHeader = record
    version      : Integer;
    description  : PChar;
    getModule    : function (Which : Integer) : PwinampVisModule; cdecl;
  end;
Pak je ještě nutné deklarovat hlavičky funkcí volaných WinAMPem:
  function  GetModule(Which :integer) :PWinAMPVisModule; cdecl;
  procedure Config(const PVisModule : PWinAMPVisModule); cdecl;
  function  Init(const   PVisModule : PWinAMPVisModule) : integer; cdecl;
  function  Render(const PVisModule : PWinAMPVisModule) :integer; cdecl;
  procedure Quit(const   PVisModule : PWinAMPVisModule); cdecl;
  function  winampVisGetHeader : PwinampVisHeader; cdecl; export;

Proměnné a konstanty:

implementation

uses IniFiles;

const
  WND_TITLE = 'Spektrální analyzér v OpenGL';
var
  h_Wnd  : HWND;
  h_DC   : HDC;
  h_RC   : HGLRC;
  keys : Array[0..255] of Boolean;      //Stisknuté klávesy
  Active : Boolean = FALSE;

  PluginStart : DWord;
  ElapsedTime : DWord;                  //Čas uplynutý mezi snímky

  Mode, Modul: integer;

  AppFullScreen : Boolean;
  EnableBeat : Boolean;
  BounceBeat : Boolean;
  VUBars : Array[0..17, 1..17] of GLFloat;

A teď nejdůležítější věc. Funkce, které si WinAMP bude z naší knihovny volat:

function WinAMPVisGetHeader :PWinAMPVisHeader;
begin
  Result := @HDR;
end;

Touto funkcí si WinAMP vycucne hlavičku našeho pluginu. Každý plugin může obsahovat víc modulů. WinAMP vybere ten pravý funkcí GetModule, která vrací ukazatel na VisModul:

function GetModule(Which : integer) : PwinampVisModule;
begin
  if which = 0 then
    Result := @VisModule
  else
    Result := nil;
end;

Procedura Config je volána, klikne-li uživatel na tlačítko Config při výběru pluginu. Je zobrazen formulář s konfigurací - rozlišení, fullscreen atd. Tyto hodnoty mohou být uchovány v souboru winamp.ini, který je v adresáři winamp/plugins.

procedure Config(const PVisModule : PWinAMPVisModule);
begin
  Form1 :=TForm1.Create(nil);
  try
    Form1.ShowModal;
  finally
    Form1.Free;
  end;
end;

Inicializační funkce načítá při spuštění pluginu hodnoty z winamp.ini souboru. Všechny globální proměnné by měli být inicializovány zde v této funkci. Zároveň jsem vytvořil glWindow a inicializoval OpenGL:

function Init(const PVisModule :PWinAMPVisModule) :integer;
var Width, Height : Integer;
    PluginIni : TIniFile;
    Path : String;
    P : Integer;
begin
  Path :=ParamStr(0);   //vrátí např. 'c:\program files\winamp\winamp.exe'
  P :=Length(Path);
  while Path[P] <> '\' do Dec(P);
  Path :=Copy(Path, 1, P);
  Path :=Path + 'Plugins\';

  PluginIni := TIniFile.Create(Path + 'plugin.ini');

  //Načteme nastavení okna
  Width :=PluginIni.ReadInteger('WinAmpPlugin', 'Width', 800);
  Height:=PluginIni.ReadInteger('WinAmpPlugin', 'Height', 600);
  AppFullScreen :=PluginIni.ReadBool('WinAmpPlugin', 'FullScreen', FALSE);

  //Načteme vlastnosti
  EnableBeat :=PluginIni.ReadBool('WinAmpPlugin', 'BackgroundBeat', TRUE);
  BounceBeat :=PluginIni.ReadBool('WinAmpPlugin', 'BounceBeat', FALSE);

  PluginIni.Free;

  if not glCreateWnd(PVisModule, Width, Height, 32, AppFullScreen) then
  begin
    glKillWnd(PVisModule, AppFullScreen);
    Result := 1;        //Jestli se okno nevytvořilo, ukončíme to
    exit;
  end;

  PluginStart := GetTickCount();        //Získání času při startu

  Result := 0;
  Active :=TRUE;
end;

Funkce Render je hlavní funkce, ve které se děje to nejdůležitější. Jak často je funkce volána závisí na hodnotě DelayMS ve VisModule. Hodnota 25 znamená, že je funkce volána každých 25 ms. Zde by se měla renderovat scéna a testovat stisknuté klávesy. Nejdůležitější je tedy volání procedury glDraw, která se postará o vykreslení celé scény:

function Render(const PVisModule : PWinAMPVisModule) : Integer;
var LastTime : DWord;
begin
  if Active then
  begin
    LastTime :=ElapsedTime;
    ElapsedTime :=GetTickCount() - PluginStart;     //Spočítá uplynutý čas
    ElapsedTime :=(LastTime + ElapsedTime) DIV 2;

    glDraw(PVisModule);                 //Vykreslí scénu
    SwapBuffers(h_DC);                  //Zobrazí scénu

    if (keys[VK_ESCAPE]) then           //reakce na ESC
    begin
      Active :=FALSE;
      PostQuitMessage(0);
      Result :=1;
      exit;
    end
    else
      ProcessKeys(PVisModule);          //Vyhodnotí ostatní klávesy
  end;
  Result :=0;
end;

A nakonec by měl WinAMP uzavřít okno funkcí close:

procedure Quit(const PVisModule : PWinAMPVisModule);
begin
  glKillWnd(PVisModule, AppFullScreen);
end;

Toto byly jen ty nejdůležitější funkce a procedury. Všechny ostatní už závisí na každé implementaci vlastního pluginu. Pro názornost uvedu ještě funkci glDraw, ze které je možno pochopit, jakým způsobem je možno vykreslit spektrální analyzér s pamětí 18 kroků:

procedure glDraw(const PVisModule : PWinAMPVisModule);
var
  BackgroundBeat : GLFloat;
  Beat : GLFloat;
  X, Y, i : integer;
  
begin
  //Získání velikosti špičky
  BackGroundBeat :=0;
  For i:=0 to 9 do
    BackGroundBeat := BackgroundBeat +
	    PVisModule^.spectrumData[0][i] +
		PVisModule^.spectrumData[1][i];
  BackgroundBeat :=BackgroundBeat /10 /255 ;

  if EnableBeat then
  begin
    //reakce na špičku
  end else begin
    //reakce, když není povolena reakce na špičku
  end;

  glClearColor(0, 0, 0, 0);

  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();
  glTranslatef(0.0, -5.0, -50);
  glRotate(30, 1, 0, 0 );
  //rotace celého analyzéru
  //glRotate(ElapsedTime/100, 0, 1, 0);

  // Posunutí sloupců o jeden dozadu
  for Y := 16 downto 1 do
    for X :=0 to 17 do
      VUBars[X, Y+1] :=VUBars[X, Y];

  // Vynulování první řady
  for X :=0 to 17 do VUBars[X, 1] :=0;

  // Zprůměrovaní 288 sloupců získaných z winampu do 18.
  for X :=0 to 287 do
    VUBars[X DIV 16, 1] := VUBars[X DIV 16, 1] +
	    PVisModule^.spectrumData[0][X]{left} +
		PVisModule^.spectrumData[1,X]{right};

  // Omezení špiček
  for X :=0 to 17 do
  begin
    VUBars[X, 1] :=VUBars[X, 1]/51/2;
    if VUBars[X, 1] > 15 then
      VUBars[X, 1] :=15;
  end;

  // Je-li povolena špička, analyzátor poskočí...
  if BounceBeat then Beat :=BackGroundBeat
  else Beat :=0;

  if (modul=0) then begin
    for Y := 1 to 17 do
      for X :=1 to 17 do ModulVUBox(X, Y, Beat, VUBars[X,Y]);
  end else if (modul=1) then begin ModulPlocha();
  end;
end;

Zbytek funkcí (Vytvoření okna, hlídání a reakce na stisknuté klávesy, vykreslení sloupce nebo plochy atd.) je možno shlédnout ve staženém zdrojáku zde (21kB). Ovládání F2 - změna módu, F3 - změna modulu, šipka nahoru/dolů - hlasitost, šipka vlevo/vpravo - předešlá/další skladba. Změna modulu spočívá ve změně způsobu vykreslování analyzéru. Ten může být buď sloupcový nebo plošný.

Vyšlo 20.05.2002, v blogu: 0 1 2 3 4 5 6 7 8

Děkuji, že jste se rozhodl(a) přečíst tento článek. Budu rád i za komentář. Pokud Vás tento článek zaujal a rádi byste jej doporučili ostatním, podpořte mně prosím tím, že věnujete minutku svého času a uděláte mi reklamu na linkuj.cz, vybrali.sme.sk či jagg.cz. Přeji příjemné čtení

Poslední články

Diskuse k blogu

Zatím nikdo nevložil komentář. Chcete být první? Přidání příspěvku
©PC-guru.cz 2000-2008 | Optimalizováno pro 1024*768