I think: When answering "What Player you use MP3", 90% will answer Winamp! Then you must have used Winamp's plug-in function. It is the diverse plugin that makes this "old" player constantly glow youth. Regardless of the new audio format (MP4, VQF, RM ...), you can play as long as the plugin is fitted. There is also a variety of visual plugins, such as Giess, etc., which makes the rhythm of music can be described as exhausted!
Since the plugin is written in the program, why not come to try his hand, do it in one? ! People who have used WinAmp know that WinAmp plug-in is a DLL (dynamic link library) file placed in the Pulgin folder, so writing WinAMP plugins is actually writing Windows dynamic link libraries. Of course, it is necessary to follow a certain specification (related documents can be downloaded from www.winamp.com), in this respect, Winamp Author Justin Frankel writes a visual plug-in example as us with a good reference. Below we will use this example (of course a writing specification) as a reference, meet the WINAMP visual plug-in writing method.
(The following program can be downloaded from the official website of Winamp, the file name is
VIS_MINISDK.ZIP)
First let's take a look at the data structure used by the visual plugin (in the file Vis.h)
// Note:
// Any plugin window for staying at the front desk should send the button to his father (Winamp) window to ensure
// The user still controls WinAMP (unless the user presses the ESC key or the key specified by the plugin).
// When the configuration is stored, the configuration data should be uniformly stored in the
/ / This plugin routine will be regarded as a framework.
Typedef struct winampvismodule {
Char * description; // module description (appears in the plugin selection list box below to drop the list box)
HWND HWNDPARENT; / / Parent window ------------- (filled by the main debut)
Hinstance HDLLINSTANCE; / / This DLL instance handle - (filled by the main adjustment)
INT SRATE; / / Sample Rate ---------- (fill by the main adjustment)
INT nch; // Number of channels ------------ (filled by the main debut)
INT latencyms; // From calling renderframe to the true draw time (milliseconds)
// (Mainmination Application) This value will be viewed when getting data)
Int delayms; // Interval between multiple calls (milliseconds)
// Data is filled in accordance with the respective NCH (number of channels)
INT spectrumnch;
INT WAVEFORMNCH;
Unsigned char spectrumdata [2] [576]; // spectrum data
Unsigned char WaveformData [2] [576]; // waveform data
Void (* config) (STRUCT WINAMPVISMODULE * THIS_MOD); // Module Configuration Function
INT (* init) (STRUCT WINAMPVISMODULE * THIS_MOD); // Initialization function (creation window, etc.). Success return 0
INT (* render) (STRUCT WINAMPVISMODULE * THIS_MOD); // "Performance" function. Successful returns 0, if returned 1 means that the plugin should be terminated
Void (* quit) (Struct Winampvismodule * this_mod); // Module exits the function. Call after completion
Void * userdata; // user data (optional)
Winampvismodule;
Typedef struct {
INT version; // vid_hdrver (version of the current module) Char * description; // Plug-in description (in the plugin list box in the Select Plug-in dialog)
WINAMPVISMODULE * (* getModule) (int); // Used to get module structure
WinampvisHeader;
/ / Define exported identity
Typedef WinampvisHeader * (* WinampvisgetHeadertype) ();
// The version of the current module (0x101 == 1.01)
#define vis_hdrver 0x101
The above list is a header file that must be included in the visual plugin, which lists the data structure for visual plugins. Before exploring the specific plug-in prior, there are some concepts to be cleared: a visual plugin can contain several modules (each module is a demo effect, you can choose which module to demonstrate in the plugin selection dialog box), These modules have been obtained by Winamp through a method (later will be seen later) to get "performance" opportunities. Briefly, WinAmp uses a unified name of the unified name exported in all plug-in DLL to get a plug-in header data structure, then use a function in this data structure to get information of each module (this process with the queryinterface of COM) Use some appearance, it seems good design ideas to be connected), and then use multithreading (observing by DLL View) to achieve visual plug-ins. Below is the source program of the visual plugin:
// WINAMP test visual plugin V1.0
// Copyright (C) 1997-1998, Justin Frankel / Nullsoft
// Based on this framework, it is free to write any visual plugin ...
#include
#include "vis.h"
Char szappname [] = "simplevis"; // Window class name
// Relevant statement
INT config_x = 50, config_y = 50; // Hand of the window on the screen
Void config_read (STRUCT WINAMPVISMODULE * THIS_MOD); // Read Configuration
Void config_write (STRUCT WINAMPVISMODULE * THIS_MOD); // Write configuration
Void config_getinifn (Struct Winampvismodule * this_mod, char * ini_file); // Generate a .ini file name
// Return to a Winampvismodule when needed, use it in the following HDR. WINAMP can thus know the number of modules in the plugin.
WINAMPVISMODULE * GETMODULE (INT which);
// "Member" function
Void config (STRUCT WINAMPVISMODULE * THIS_MOD); // Module Configuration Function
INT INIT (STRUCT WINAMPVISMODULE * THIS_MOD); // Module Initialization Function
INT render1 (Struct Winampvismodule * this_mod); // The "Performance" function of module 1
INT RENDER2 (STRUCT WINAMPVISMODULE * THIS_MOD); // Module 2 "Performance" function
INT render3 (Struct Winampvismodule * this_mod); // The "Performance" function of module 3
Void quit (STRUCT WINAMPVISMODULE * THIS_MOD); // The cleaning function ends over the module
// Plugin window window handler
LResult Callback WndProc (HWND HWND, UINT MESSAGE, WPARAM WPARAM, LPARAM LPARAM); HWND HMAINWND; // Main Window Handle
// Double buffer data
HDC MEMDC; // Memory DC
Hbitmap membm, // memory bitmap (for MEMDC)
Oldbm; // Old Bitmap (from MEMDC)
// Module head. Including module version, plug-in description (in the plug-in list box of the Plug-in dialog) and module interface functions
WinampvisHeader HDR = {VIS_HDRVER, "Nullsoft Test Visualization Library V1.0", getModule};
// First module (oscilloscope)
Winampvismodule MOD1 =
{
"Oscilliscope",
Null, // hwndparent
Null, // HDLINSTANCE
0, // SRate
0, // nch
25, // latencyms
25, // delayms
0, // spectrumnch
2, // WaveFormnch
{0,}, // Spectrumdata
{0,}, // WaveformData
CONFIG,
INIT,
Render1,
quit
}
// Second module (spectral analysis)
WINAMPVISMODULE MOD2 =
{
Spectrum AnalySer,
Null, // hwndparent
Null, // HDLINSTANCE
0, // SRate
0, // nch
25, // latencyms
25, // delayms
2, // spectrumnch
0, // WaveFormnch
{0,}, // Spectrumdata
{0,}, // WaveformData
CONFIG,
INIT,
Render2,
quit
}
// Third Module (Vu Meter)
Winampvismodule Mod3 =
{
"Vu meter",
Null, // hwndparent
Null, // HDLINSTANCE
0, // SRate
0, // nch
25, // latencyms
25, // delayms
0, // spectrumnch
2, // WaveFormnch
{0,}, // Spectrumdata
{0,}, // WaveformData
CONFIG,
INIT,
Render3,
quit
}
// This is only one export function in the plugin DLL to return to the plug-in header structure pointer to further
// The information of each module in the plugin is known.
// If you are compiling C programs, Extern "C" {is necessary, so we used #ifdef.
#ifdef __cplusplus
Extern "C" {
#ENDIF
__Declspec (dllexport) WinampvisHeader * WinampVisgetHeader ()
{
Return & HDR;
}
#ifdef __cplusplus
}
#ENDIF
// Used to obtain module information after getting the plug-in header structure.
// If an absent module is requested to return null, it will return one of each available module (structural pointer) according to 'Which'.
WINAMPVISMODULE * GETMODULE (INT Which)
{
Switch (which) {
Case 0: Return & MOD1;
Case 1: Return & Mod2;
Case 2: Return & MOD3;
Default: return null;
}
}
// Module configuration function. Which module to configure can be found via this_mod.
// Allows you to share a configuration function.
// (Of course, you don't have to use this name, you can build config1 (), config2 (), etc ...)
Void Config (STRUCT WINAMPVISMODULE * THIS_MOD)
{
MessageBox (this_mod-> hwndparent, "this module is copyright (c) 1997-1998, Justin Frankel / Nullsoft / N"
"- This Is Just A Demonstration Module, IT Really Isn't / N"
"Supposed to Be Enjoyable -", "Configuration", MB_OK;
}
// Module initialization function. Register window classes, create a window, and more.
// This is the work you have to do all modules, but you can also build init1 () and init2 () ...
// Successfully returned 0, failed to return 1.
INT INIT (STRUCT WINAMPVISMODULE * THIS_MOD)
{
INT width = (this_mod == & mod3)? 256: 288; // MOD1 and MOD2 wide level
INTHEIGHT = (this_mod == & mod3)? 32: 256; // But MOD3 with two different different
Config_read (this_mod); // Read configuration information
{// Register window class
WNDCLASS WC;
MEMSET (& WC, 0, SIZEOF (WC));
wc.lpfnwndproc = wndproc; // window processing process
Wc.HINSTANCE = this_mod-> HDLLINSTANCE; // DLL instance handle
wc.lpszclassname = szappname; // Window class name
IF (! RegisterClass (& WC))
{
MessageBox (this_mod-> hwndparent, "Error Registering Window Class", "Blah", MB_OK;
Return 1;
}
}
HmainWnd = CREATEWINDOWEX (
WS_EX_TOOLWINDOW | WS_EX_APPWINDOW, // These extended style build a good-looking small window frame,
/ / But the window has a button on the taskbar
Szappname, // window class name
this_mod-> description, // Window title usage module description
WS_Visible | WS_SYSMENU, // Make the window visible and have a closed button
CONFIG_X, CONFIG_Y, / / Window screen position (read from the configuration)
Width, height, // window is high (need to adjust the customer area size later)
this_mod-> hwndparent, // Father window handle (WinAmp main window)
Null, // No menu
This_MOD-> HDLLINSTANCE, // DLL instance handle
0); // No window Create data
IF (! hmainwnd)
{
MessageBox (this_mod-> hwndparent, "error create", "blah", mb_ok); Return 1;
}
Setwindowlong (hmainwnd, gwl_userdata, (long) this_mod); // Set the window user data as a module structure pointer
{// Adjust the window size to make the customer area equal to the boom
Rect R;
GetClientRect (HmainWnd, & R);
SetWindowPos (HmainWnd, 0,0,0, Width * 2-R.right, Height * 2-R.Bottom, SWP_NOMOVE | SWP_NOZORDER);
}
// Create a double buffer
MEMDC = CREATECOMPATIPLEDC (NULL);
MEMBM = CREATECOMPATIBEBITMAP (MEMDC, Width, Height);
Oldbm = selectObject (MEMDC, MEMBM);
// Display window
ShowWindow (hmainwnd, sw_shownormal);
Return 0;
}
// The "performance" function of the oscilloscope module. Returns 1 successfully, if the plugin should be terminated, then returns 1.
Int Render1 (Struct Winampvismodule * this_mod)
{
INT X, Y;
// Clear background
Rectangle (MEMDC, 0, 0, 288, 256);
// Draw an oscilloscope
For (y = 0; y
{
MoveToex (MEMDC, 0, (Y * 256) >> (this_MOD-> NCH-1), NULL);
FOR (x = 0; x <288; x )
{
LINETO (MEMDC, X, (Y * 256 this_MOD-> WaveformData [Y] [x] ^ 128) >> (this_mod-> nch-1));
}
}
{/ Copy dual buffer to the window
HDC HDC = Getdc (HmainWnd);
Bitblt (HDC, 0, 0, 288, 256, MEMDC, 0, 0, SRCCOPY);
ReleaseDC (HmainWnd, HDC);
}
Return 0;
}
// Spectrum analysis module's "performance" function. Returns 1 successfully, if the plugin should be terminated, then returns 1.
Int Render2 (Struct Winampvismodule * this_mod)
{
INT X, Y;
// Clear background
Rectangle (MEMDC, 0, 0, 288, 256);
// Draw an analyzer
For (y = 0; y
{
FOR (x = 0; x <288; x )
{
MoveToex (MEMDC, X, (Y * 256 256) >> (this_MOD-> NCH-1), NULL);
LINETO (MEMDC, X, (Y * 256 256 - this_mod-> spectrumdata [y]) >> (this_mod-> nch-1));
}
}
{/ Copy dual buffer to the window
HDC HDC = Getdc (HmainWnd);
Bitblt (HDC, 0, 0, 288, 256, MEMDC, 0, 0, SRCCOPY);
ReleaseDC (HmainWnd, HDC);
}
Return 0;
}
// VU table module "Performance" function. Returns 1 successfully, if the plugin should be terminated, then returns 1.
INT render3 (Struct Winampvismodule * this_mod) {
INT X, Y;
// Clear background
Rectangle (MEMDC, 0, 0, 256, 32);
// Draw a VU table
FOR (y = 0; y <2; y )
{
INT LAST = this_mod-> WaveformData [Y] [0];
INT TOTAL = 0;
FOR (x = 1; x <576; x )
{
Total = ABS (Last - this_MOD-> WaveformData [Y]);
Last = this_mod-> WaveformData [Y] [x];
}
Total / = 288;
IF (Total> 127)
Total = 127;
IF (y)
Rectangle (MEMDC, 128, 0, 128 Total, 32);
Else
Rectangle (MEMDC, 128-Total, 0, 128, 32);
}
{/ Copy dual buffer to the window
HDC HDC = Getdc (HmainWnd);
Bitblt (HDC, 0, 0, 256, 32, MEMDC, 0, 0, SRCCOPY);
ReleaseDC (HmainWnd, HDC);
}
Return 0;
}
// Module Clear function (corresponding to init ()). Destroy the window and cancel the registration of the window class.
Void Quit (STRUCT WINAMPVISMODULE * THIS_MOD)
{
Config_write (this_mod); // Write configuration
SelectObject (MEMDC, OLDBM); // Delete double buffer
DeleteObject (MEMDC);
DeleteObject (MEMBM);
DestroyWindow (HmainWnd); // Destroy window
UnregisterClass (Szappname, this_mod-> hdllinstance); // Cancel the window class registration
}
// Plugin window window handler
Lresult Callback WndProc (HWND HWND, UINT MESSAGE, WPARAM WPARAM, LPARAM LPARAM)
{
Switch (Message)
{
Case WM_CREATE: RETURN 0;
Case WM_RASEBKGND: RETURN 0;
Case WM_Paint:
{// Displayed with a double buffer information
Paintstruct PS;
Rect R;
HDC HDC = BeginPaint (HWND, & PS);
GetClientRect (hwnd, & r);
Bitblt (HDC, 0, 0. R.right, R.Bottom, MEMDC, 0, 0, SRCCOPY);
Endpaint (hwnd, & ps);
}
Return 0;
Case WM_DESTROY: PostquitMessage (0); Return 0;
Case WM_KeyDown: // Pass the keyboard message to the WINAMP main window (make it processed)
Case WM_KEYUP:
{// get this_MOD from the user data of the window
Winampvismodule * this_mod = (Winampvismodule *) getWindowlong (hwnd, gwl_userdata);
Postmessage (this_mod-> hwndparent, message, wparam, lparam);
}
Return 0;
Case WM_MOVE:
{// get config_x and config_y from the configuration
Rect R;
GetWindowRect (HmainWnd, & R); config_x = r.L.L;
CONFIG_Y = R.TOP;
}
Return 0;
}
Return DefWindowProc (Hwnd, Message, WPARAM, LPARAM);
}
/ / Generate a
Void config_getinifn (struct winampvismodule * this_mod, char * ini_file)
{
Char * p;
GetModuleFileName (this_mod-> HDLLINSTANCE, INI_FILE, MAX_PATH);
P = INI_FILE STRLEN (INI_FILE);
While (p> = INI_FILE && * p! = '//')
P -;
IF ( p> = ini_file)
* p = 0;
STRCAT (INI_FILE, "Plugin.ini");
}
Void config_read (STRUCT WINAMPVISMODULE * THIS_MOD)
{
CHAR INI_FILE [MAX_PATH];
Config_getinifn (this_mod, ini_file);
Config_x = getPrivatePriVateProfileint (this_mod-> description, "screen_x", config_x, ini_file;
Config_y = getPrivateProfileint (this_mod-> description, "screen_y", config_y, ini_file;
}
Void config_write (STRUCT WINAMPVISMODULE * THIS_MOD)
{
CHAR STRING [32];
CHAR INI_FILE [MAX_PATH];
Config_getinifn (this_mod, ini_file);
WSPrintf (String, "% D", config_x);
WritePrivateProfileString (this_mod-> description, "screen_x", string, ini_file;
WSPrintf (String, "% D", config_y);
WritePrivateProfileString (this_mod-> description, "screen_y", string, ini_file;
}
As we mentioned earlier, the plug-in program and the main program must have a normality to cooperate, such as an approximately function name, and the like. As can be seen from the above program, WinAmp uses a depellent function name to call a unique export function WinampvisGeter () to the plug-in header WINAMPVISHEADER, while the latter is included in a pointer function (* getModule) (int), can expose the interface of the module to the WinAmp in accordance with a given parameter. ^ _ ^ This, all the details of the plugin appear in front of WinAmp. Because the getModule function returns NULL to the module that is not implemented, Winamp can determine the number of modules in the visual plugin by returning values. In fact, the above procedure is a write framework for a visual plug-in. When it is clear, it can put energy in the preparation of the "performance" function after the specification.