WinAMP Visualization Plugin Tutorial


I decided to put together this tutorial that provides a basic overview of what you need to do to get a winamp visualization plugin to work. If you want to get hold of the official winamp plugins SDK, you can get it at There are quite a few C examples in the SDK.

Data Structures

First off you have to create a DLL. winamp expects your DLL to export winampVisGetHeader

 exports winampVisGetHeader;

Then in the unit containing the rest of the code add the following data structures. Winamp will use this record to pas information to and execute the functions it needs.

  PWinampVisModule = ^TwinampVisModule;
  TwinampVisModule = record
    description  : PChar;        // description of module
    hwndParent   : HWND;         // parent window (filled in by calling app)
    hDllInstance : HINST;        // instance handle to this DLL (filled in by calling app)
    sRate        : Cardinal;     // sample rate (filled in by calling app)
    nCh          : Cardinal;     // number of channels (filled in...)
    latencyMs    : Cardinal;     // latency from call to Render to actual drawing
    delayMs      : Cardinal;     // delay between calls to Render (in ms)

    // the data is filled in according to the respective Nch entry
    spectrumNCh  : Cardinal;     // Number of channels
    waveformNCh  : Cardinal;     // Number of channels
    spectrumData : Array [0..1, 0..575] of Byte;     // waveform data   (values from 0-255)
    waveformData : Array [0..1, 0..575] of Byte;     // spectrum data   (values from 0-255)

    // functions that winamp calls to configure the plugin, initialise ...
    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;  // user data, optional
  PwinampVisHeader = ^TwinampVisHeader;
  TwinampVisHeader = record
    version      : Integer;
    description  : PChar;  // description of library
    getModule    : function (Which : Integer) : PwinampVisModule; cdecl;

I then also added a forward declaration of the functions that will be called by winamp.

  // forward declaration of the procedures
  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;

 You also need to add the function that will be exported before you get to the implementation

function winampVisGetHeader : PwinampVisHeader; cdecl; export;

Global Variables

This section might change depending on your implementation of the plugin. For my plugin I created the window using API calls. You could do it using the standard Delphi Forms.


  WND_TITLE = 'Jan OpenGL WinAMP Plugin';
  h_Wnd  : HWND;                     // Global window handle
  h_DC   : HDC;                      // Global device context
  h_RC   : HGLRC;                    // OpenGL rendering context
  keys : Array[0..255] of Boolean;   // Holds keystrokes
  Active : Boolean = FALSE;          // State of the plugin

Functions called by Winamp

This is a list of the functions called by winamp and what they are for.

WinAMPVisGetHeader : Return as pointer to the WinAMPVisHeader

function WinAMPVisGetHeader :PWinAMPVisHeader;
  Result := @HDR;    //  Return the main header

GetModule : Returns a pointer to the WinampVisModule. A variable containing the plugin information and functions.

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

Config : This function gets called when the user got to the plugin configuration section on winamp. It should display the plugin options like screensize and any other display options. These options should then be stored in the "plugin.ini" file in the winamp plugins folder.

procedure Config(const PVisModule : PWinAMPVisModule);
  Form1 :=TForm1.Create(nil);

Init : The initialisation function should get the plugin display options from the "plugin.ini" file in the winamp\plugins folder. All global variable get initialised here. In the code that I use, I create the glWindow here and initialise OpenGL

function Init(const PVisModule :PWinAMPVisModule) :integer;
  // Get plugin config details
  // create and initialise the window

Render : This is the main function where everything happens. The number of times that this function gets called depends on the DelayMS value in the VisModule. A value of 25 will tell winamp to call this function every 25 milliseconds.
Here you would render the image and check for any key presses.

function Render(const PVisModule : PWinAMPVisModule) : Integer;
var LastTime : DWord;
  if Active then
    glDraw(PVisModule);                 // Draw the scene
    SwapBuffers(h_DC);                  // Display the scene

    if (keys[VK_ESCAPE]) then           // If user pressed ESC then set finised TRUE
      Active :=FALSE;
      Result :=1;
      ProcessKeys(PVisModule);          // Check for any other key Pressed
  Result :=0;

Quit : Closes the window.

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

That's it. The other functions in my code are there to create the OpenGL window, watch for key presses and to render the GL scene. They were copied from my OpenGL template.

If you want to download the code for the winamp plugin that I created, you can get it here.