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
www.winamp.com/nsdn/winamp2x/dev/plugins. 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.
type
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
end;
PwinampVisHeader = ^TwinampVisHeader;
TwinampVisHeader = record
version : Integer;
description : PChar; // description of library
getModule : function (Which : Integer) : PwinampVisModule; cdecl;
end;
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.
implementation
const
WND_TITLE = 'Jan OpenGL WinAMP Plugin';
var
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;
begin
Result := @HDR; // Return the main header
end;
GetModule : Returns a pointer to the WinampVisModule. A variable containing the
plugin information and functions.
function GetModule(Which : integer) : PwinampVisModule;
begin
if which = 0 then
Result := @VisModule
else
Result := nil;
end;
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.
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;
begin
...
// Get plugin config details
...
// create and initialise the window
...
end;
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;
begin
if Active then
begin
glDraw(PVisModule); // Draw the scene
SwapBuffers(h_DC); // Display the scene
if (keys[VK_ESCAPE]) then // If user pressed ESC then set finised TRUE
begin
Active :=FALSE;
PostQuitMessage(0);
Result :=1;
exit;
end
else
ProcessKeys(PVisModule); // Check for any other key Pressed
end;
Result :=0;
end;
Quit : Closes the window.
procedure Quit(const PVisModule : PWinAMPVisModule);
begin
glKillWnd(PVisModule, AppFullScreen);
end;
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.