WiMamp Vision Effect Plugin DIY

zhaozj2021-02-11  195

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 /plugin.ini.

/ / 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 nch; y ) // There are several wavages in several channels.

{

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 nch; y ) // There are several wavages in several channels.

{

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 /plugin.ini form .ini file name

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.

转载请注明原文地址:https://www.9cbs.com/read-5365.html

New Post(0)