winamp/Src/Plugins/Visualization/vis_milk2/DOCUMENTATION.TXT

1023 lines
56 KiB
Plaintext

-----------------------------------------------------------------------
WINAMP 2.X VISUALIZATION PLUG-IN "MEGA SDK"
('Vis Mega SDK' for short)
('VMS' for shorter)
-----------------------------------------------------------------------
Description: A codebase for rapidly creating robust and feature-rich
DX8-based visualization plug-ins of your own.
Version: custom version based on 1.05 beta 1; upgraded to use DX9.
Released: n/a
Author: Ryan Geiss
Copyright: (c) 2002-2007 Nullsoft, Inc.
VMS HOMEPAGE: http://www.nullsoft.com/free/vms/
VMS AT WINAMP: http://www.winamp.com/nsdn/winamp2x/dev/plugins/vis.jhtml
SUPPORT FORUM: http://forums.winamp.com/forumdisplay.php?forumid=147
-----------------------------------------------------------------------
TABLE OF CONTENTS
-----------------
1. Purpose of this package
2. Features
3. Required software
4. Setting up the build environment
5. Starting Your Own Plugin Based on the Framework
6. Writing your own Plugin: A Brief Tour
7. Order of Function Calls
8. Using Data From the Base Class (CPluginShell)
9. Adding Controls to the Config Panel
10. Enabling Additional Tabs (pages) on the Config Panel
11. Using Visual C++ to Debug your Plugin
12. Releasing a Plugin
13. Tips to pass on the the user, in your documentation
14. Performance Tips for DirectX 8
15. Other Resources
16. Known Bugs
17. Version History
18. License
Purpose of this package
-----------------------
This package is for DEVELOPERS who want to write their own
visualization plugins.
It aims to provide a codebase that enables all developers
(beginning to advanced) to easily build robust Winamp 2.x
visualization plugins whose graphics are to be generated
though the DirectX 8 API. This codebase will 1) drastically
reduce the time it takes to write your plugin, 2) ensure
that it is robust (if you follow directions), and 3) give
you built-in support for many cool features, such as
multiple monitors. (See below for more details.)
Feel free to base any plugins on this "framework".
Features
--------
-DESKTOP MODE. Lets your plugin run as animated wallpaper,
with very little CPU overhead. (Your plugin can also
run in windowed or fullscreen modes, and the user can
switch between all 3 on the fly.)
-SUPERIOR MULTIMON SUPPORT. Your plugin will work on systems
with multiple display adapters, as well as systems with
a multi-head card. For multi-head cards that treat all
screens as one giant display (ie. resolutions like 2048x768
or 1024x1536), your users can even use 'fake' fullscreen mode
to run your plugin fullscreen on just one monitor!
-SOUND ANALYSIS: the framework provides your plugin with a
super-high-quality FFT (fast fourier transform) for doing your
own frequency analysis, or for drawing spectra. Framework also
provides super-simple loudness levels for 3 bands (bass,
mids, and treble) and at varying attenuation (damping) rates.
-A very nice CONFIGURATION PANEL is provided for the plugin.
On the first page (tab) of the config panel are all the
settings that all plugins share in common [handled by VMS];
on subsequent tabs, you add your own controls, for settings
that are specific to your plugin. The example plugin also
shows you how to easily handle the reading/writing of settings
that you add to/from the .INI file that will store your
plugin's settings.
-OTHER PERKS like a runtime help screen and playlist; high-precision
timing (accurate to 10 microseconds, or 0.00001 seconds);
pause-filtering (so your timing code won't got haywire
when Winamp is unpaused); and many others.
-CPU-FRIENDLY: when the window is minimized, or when you're
in fullscreen mode and ALT-TAB out, the plugin sleeps to
preserve CPU. FPS limiting also does its best to preserve
CPU, while at the same time, accurately limiting the FPS.
-ERROR FEEDBACK: provides detailed error messages to the user
on failure, as well as suggestions on how to fix problems.
Required software
-----------------
1. Nullsoft Winamp 2.X (~1 MB)
http://www.winamp.com/
2. Microsoft DirectX 8.0+ - (~11 MB)
http://www.microsoft.com/windows/directx/
3. Microsoft Developer Studio (Visual C++) 6.0
(a retail product)
4. Microsoft DirectX 8.0 SDK (Software Development Kit) - (~173 MB)
http://www.microsoft.com/windows/directx/
(then click the 'msdn' icon in the lower right, under
"info for developers")
*** NOTE that you can use a later SDK, such as 8.1b; but if you
do, then your plugin will only run on systems with that version
(or later) of the DirectX runtime installed! ***
*** You can also install several versions of the SDK into
different directories, and as long as the 8.0 sdk paths are
selected in Dev Studio (see below), your plugin will only
require the 8.0 runtime. ***
5. MSDN (Microsoft Developer Network) help library (OPTIONAL) (~1GB)
(also a retail product; optional, but highly recommended
to have around. If you can't get the CD's, though, you
can always access the help database online at
http://msdn.microsoft.com/library/ )
Setting up the build environment
--------------------------------
[Note: for Visual C++ .Net users, see below]
1. Make sure DirectX 8.0 or later is installed.
2. Make sure the DirectX 8.0 SDK (source development kit) is installed.
** (see notes above & below) **
3. Configure Visual C++ to use the [appropriate] DX8 SDK:
In Visual C++, go to Tools, then Options. Click on the
'Directories' tab. Under 'Show directories for:', select
'Include Files.' Then, below, add the INCLUDE folder
underneath the folder into which you installed the DX8 SDK.
Now highlight your addition and use the fancy-looking 'up'
arrow icon to move it to the top of the list of directories.
Now do the same thing for the LIB folder. Under 'Show
directories for:', select 'Library Files.' Now add the LIB
folder underneath the folder into which you installed the
DX8 SDK. Again, use the fancy-looking 'up' arrow icon
to move it to the top of the list of directories.
*** NOTE that if you have multiple DirectX 8 SDK's (such as 8.0
and 8.1b) installed to different directories, you'll want the
earliest one (hopefully 8.0) to be first in the list; that's
the one that will get used when you compile & link. Otherwise,
your plugin will only run on systems with the other version
(or later) of the DirectX runtime installed! ***
4. (optional) you might want to set Visual C++ up to use
4 spaces instead of symbolic tabs, to keep the formatting
of new code that you write consistent with this code.
If you want to do this, go to menu:Tools->Options, click
the 'Tabs' tab, set the 'Tab Size' to 4 and click on
'Insert Spaces'.
[FOR VISUAL C++ .NET USERS:]
You'll want to start a fresh DLL-based project and manually
add all the source/header files to it. Then go into project
settings and make it **Use MFC in a SHARED DLL**.
Starting Your Own Plugin Based on the Framework
-----------------------------------------------
1. Copy the files in the 'ExPlugin' folder to a new folder,
such as 'MyPlugin' - it can be anything.
2. In the new folder, rename the workspace file ExPlugin.dsw
to MyPlugin.dsw (or equivalent).
3. Open the new workspace file (that you just renamed) in Visual C++.
4. Go to menu:Build->Configurations and select 'plugin - Win32 Debug'.
5. Go to menu:Project->Settings
a. In the upper-left corner, where it says 'Settings For:',
select 'All Configurations' from the dropdown box.
b. Click the 'debug' tab, and under 'Executable for debug
session', point it to winamp.exe (most likely
c:\program files\winamp\winamp.exe). (This will enable
you to debug your plugin using Visual C++.)
c. Click the 'link' tab, and under 'Output file name',
enter the name of the .DLL to write (such as
c:\program files\winamp\plugins\vis_myplugin.dll).
This should start with 'vis_' and end in the
'.dll' extension. This DLL will be your plugin.
d. click OK.
6. On the left you should see the workspace view (if not, hit ALT+ZERO)
to bring it up) with 3 tabs at the bottom (ClassView, ResourceView,
FileView). Click 'FileView'. Expand everything in this view so you
can see all the files.
7. Open 'defines.h' by double-clicking it. Now edit this file according
to the comments, to give your plugin a name, a version number, enter
the author's name, copyright string, the name of the .INI file you
want to save the user's settings in, the name of the documentation
file, and so on. (You can always come back and change these values
later, of course).
Now you're ready to build & run the plugin:
8. Press F7 to build the plugin.
a. If you get any of these error messages:
fatal error C1083: Cannot open include file: 'd3d8.h'...
fatal error C1083: Cannot open include file: 'd3dx8.h'...
Then you haven't added the DX8 SDK *include* path to your
build environment. See 'To set up the build environment'
above.
b. If you any linker error messages, such as this one:
LINK : fatal error LNK1104: cannot open file "d3d8.lib"
Then you haven't added the DX8 SDK *library* file path to your
build environment. See 'To set up the build environment'
above.
9. Copy the files 'ex_tex.jpg' and 'vms_desktop.dll' from the MyPlugin
directory to your Winamp PLUGINS folder (usually c:\program files\
winamp\plugins).
10. Run Winamp, press CTRL+P to select your plugin, and make sure that
it appears in the list. Notice that the name matches what you
entered into the 'defines.h' file as APPNAME; if you didn't change
it, it will appear as 'Example Plugin v1.04 / VisMegaSDK' (or
something similar). Next, configure the plugin, hit OK, & run it
by clicking 'Start'.
Writing your own Plugin: A Brief Tour
-------------------------------------
This starts out by pointing you at the important source code,
then by showing you around the resource editor and, finally,
the DirectX 8 and MSDN help libraries.
1. Take a look at each of the 6 files in the 'My Plugin Source Files'
and 'My Plugin Header Files' groups. These will give you an idea
of the code that makes up the example plugin. All of the
behind-the-scenes code is wrapped up in the 'Framework Files'
group, which you shouldn't have to bother with (unless you
want to).
2. Take a close look at plugin.h. This is the C++ class that makes
up your plugin. Note that the class is derived from the
CPluginShell class (which is in pluginshell.h/cpp), so it inherits
all its functions & variables. What you see here (in plugin.h)
are the data members and functions ADDED for this specific
(example) plugin, as well as the 12 pure virtual functions we've
implemented from the base class.
3. Take a close look at plugin.cpp. READ THE BRIEF COMMENTS AT THE
TOP OF THOSE 12 VIRTUAL FUNCTIONS TO GET AN IDEA OF WHEN THEY'RE
CALLED AND WHAT THEY DO.
4. Next we'll go into the Resource Editor.
Click the 'ResourceView' tab at the bottom of the Workspace view.
Then expand 'plugin resources' by double-clicking it, expand
'Dialog' in the same way, and double-click 'IDD_CONFIG' to open
the template for the config panel. You can now double-click
individual controls to edit their properties; move/resize them;
press CTRL+T to test the dialog; press CTRL+D to define the tab
order; and even add new controls (using the floating toolbar)
(note that added controls require a lot of support code in
plugin.cpp; see 'Adding Controls to the Config Panel' below).
Also expand the 'Icon' folder on the left (just after 'Dialog')
and double-click IDI_PLUGIN_ICON. This is the icon used in the
taskbar, window title, and ALT+TAB screen when your plugin is
running. Note that there are 5 different icons within this one,
all at different resolutions and color depths, accessible by
changing the 'device' (just above the enlarged icon in the
resource editor). So, when you go to update the icon, don't forget
to update it for all devices!
5. In Windows, go to Start Menu -> Program Files -> Microsoft
DirectX 8 SDK -> DirectX Documentation (Visual C++). This
is the help library for DirectX 8; you will need to refer to
it religiously in order to get anything done in DirectX 8.
The good news is, it's *extremely* well-written.
6. In Windows, go to Start Menu -> Program Files -> Microsoft
Developer Network -> MSDN Library. This is the help library
for the general Win32 platform, but might not have info on
DirectX 8 (depending on when your version was published).
If you couldn't get the MSDN CD's, you can access the MSDN
library online at:
http://msdn.microsoft.com/library/
You'll have to do this from time to time to write a plugin,
but not nearly as often as you'll be accessing the DirectX 8
help library.
You might also want to take a look at the useful goodies inside
utility.cpp; they could come in handy.
That's it; you've now seen all the 'screens' you'll spend 99% of
your time on, in order to write your own plugin.
Order of Function Calls
-----------------------
The only code that will be called by the plugin framework are the
12 virtual functions in plugin.h. But in what order are they called?
A breakdown follows. A function name in { } means that it is only
called under certain conditions.
Order of function calls...
When the PLUGIN launches
------------------------
INITIALIZATION
OverrideDefaults
MyPreInitialize
MyReadConfig
<< DirectX gets initialized at this point >>
AllocateMyNonDx8Stuff
AllocateMyDX8Stuff
RUNNING
+--> { CleanUpMyDX8Stuff + AllocateMyDX8Stuff } // called together when user resizes window or toggles fullscreen<->windowed.
| MyRenderFn
| MyRenderUI
| { MyWindowProc } // called, between frames, on mouse/keyboard/system events. 100% threadsafe.
+----<< repeat >>
CLEANUP
CleanUpMyDX8Stuff
CleanUpMyNonDx8Stuff
<< DirectX gets uninitialized at this point >>
When the CONFIG PANEL launches
------------------------------
INITIALIZATION
OverrideDefaults
MyPreInitialize
MyReadConfig
<< DirectX gets initialized at this point >>
RUNNING
{ MyConfigTabProc } // called on startup & on keyboard events
CLEANUP
[ MyWriteConfig ] // only called if user clicked 'OK' to exit
<< DirectX gets uninitialized at this point >>
Using Data From the Base Class (CPluginShell)
---------------------------------------------
The base class from which your CPlugin class (in plugin.cpp) is
derived is called CPluginShell and is defined in pluginshell.cpp.
Many of its data members are 'protected', which means that only that
class itself, *plus derived classes*, can access them. ('Public'
members can be accessed by anyone; 'private' are unaccessible even
to derived classes.)
The protected data members and methods (functions) are as follows.
Generally, you should treat the data members as READ-ONLY; the only
exception is in OverrideDefaults(), where you can modify some of
their values to alter the "default defaults". See the comments at
the top of OverrideDefaults() in plugin.cpp for more information.
Here are all of the members & methods maintained by the plugin shell,
and available to CPlugin:
// GET METHODS
// ------------------------------------------------------------
int GetFrame(); // returns current frame # (starts at zero)
float GetTime(); // returns current animation time (in seconds) (starts at zero) (updated once per frame)
float GetFps(); // returns current estimate of framerate (frames per second)
eScrMode GetScreenMode(); // returns WINDOWED, FULLSCREEN, FAKE_FULLSCREEN, DESKTOP, or NOT_YET_KNOWN (if called before or during OverrideDefaults()).
HWND GetWinampWindow(); // returns handle to Winamp main window
HINSTANCE GetInstance(); // returns handle to the plugin DLL module; used for things like loading resources (dialogs, bitmaps, icons...) that are built into the plugin.
char* GetPluginsDirPath(); // usually returns 'c:\\program files\\winamp\\plugins\\'
char* GetConfigIniFile(); // usually returns 'c:\\program files\\winamp\\plugins\\something.ini' - filename is determined from identifiers in 'defines.h'
// GET METHODS THAT ONLY WORK ONCE DIRECTX IS READY
// ------------------------------------------------------------
// The following 'Get' methods are only available after DirectX has been initialized.
// If you call these from OverrideDefaults, MyPreInitialize, or MyReadConfig,
// they will return NULL (zero).
// ------------------------------------------------------------
HWND GetPluginWindow(); // returns handle to the plugin window. NOT persistent; can change!
int GetWidth(); // returns width of plugin window interior, in pixels.
int GetHeight(); // returns height of plugin window interior, in pixels.
int GetBitDepth(); // returns 8, 16, 24 (rare), or 32
LPDIRECT3DDEVICE8 GetDevice(); // returns a pointer to the DirectX 8 Device. NOT persistent; can change!
D3DCAPS8* GetCaps(); // returns a pointer to the D3DCAPS8 structer for the device. NOT persistent; can change.
D3DFORMAT GetBackBufFormat(); // returns the pixelformat of the back buffer (probably D3DFMT_R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5, D3DFMT_A4R4G4B4, D3DFMT_R3G3B2, D3DFMT_A8R3G3B2, D3DFMT_X4R4G4B4, or D3DFMT_UNKNOWN)
D3DFORMAT GetBackBufZFormat(); // returns the pixelformat of the back buffer's Z buffer (probably D3DFMT_D16_LOCKABLE, D3DFMT_D32, D3DFMT_D15S1, D3DFMT_D24S8, D3DFMT_D16, D3DFMT_D24X8, D3DFMT_D24X4S4, or D3DFMT_UNKNOWN)
char* GetDriverFilename(); // returns a text string with the filename of the current display adapter driver, such as "nv4_disp.dll"
char* GetDriverDescription(); // returns a text string describing the current display adapter, such as "NVIDIA GeForce4 Ti 4200"
// FONTS & TEXT
// ------------------------------------------------------------
LPD3DXFONT GetFont(eFontIndex idx); // returns a D3DX font handle for drawing text; see shell_defines.h for the definition of the 'eFontIndex' enum.
int GetFontHeight(eFontIndex idx); // returns the height of the font, in pixels; see shell_defines.h for the definition of the 'eFontIndex' enum.
// MISC
// ------------------------------------------------------------
td_soundinfo m_sound; // a structure always containing the most recent sound analysis information; defined in pluginshell.h.
void SuggestHowToFreeSomeMem(); // gives the user a 'smart' messagebox that suggests how they can free up some video memory.
// CONFIG PANEL SETTINGS
// ------------------------------------------------------------
// *** only read/write these values during CPlugin::OverrideDefaults! ***
int m_start_fullscreen; // 0 or 1
int m_start_desktop; // 0 or 1
int m_fake_fullscreen_mode; // 0 or 1
int m_max_fps_fs; // 1-120, or 0 for 'unlimited'
int m_max_fps_dm; // 1-120, or 0 for 'unlimited'
int m_max_fps_w; // 1-120, or 0 for 'unlimited'
int m_show_press_f1_msg; // 0 or 1
int m_allow_page_tearing_w; // 0 or 1
int m_allow_page_tearing_fs; // 0 or 1
int m_allow_page_tearing_dm; // 0 or 1
int m_minimize_winamp; // 0 or 1
int m_desktop_show_icons; // 0 or 1
int m_desktop_textlabel_boxes; // 0 or 1
int m_desktop_manual_icon_scoot; // 0 or 1
int m_desktop_555_fix; // 0 = 555, 1 = 565, 2 = 888
int m_dualhead_horz; // 0 = both, 1 = left, 2 = right
int m_dualhead_vert; // 0 = both, 1 = top, 2 = bottom
int m_save_cpu; // 0 or 1
int m_skin; // 0 or 1
td_fontinfo m_fontinfo[NUM_BASIC_FONTS + NUM_EXTRA_FONTS];
D3DDISPLAYMODE m_disp_mode_fs; // a D3DDISPLAYMODE struct that specifies the width, height, refresh rate, and color format to use when the plugin goes fullscreen.
Adding Controls to the Config Panel
-----------------------------------
There are four basic aspects of adding a new control to the config panel,
outlined below.
1. Add the control to one of the property pages in the config panel (2..8),
via the Resource Editor. Note that you should not modify the config
panel itself (IDD_CONFIG) or the first property page (IDD_PROPSHEET_1).
Also, do not resize the page dialogs or the config panel; they are designed
to fit on a 640x480 screen, and should not be expanded.
2. Add a variable (data member) to represent the control to your CPlugin class,
in plugin.h.
3. In plugin.cpp:
a. initialize the variable to its default value in MyPreInitialize(),
b. read its value from the INI file in MyReadConfig(), and
c. write its value to the INI file in MyWriteConfig().
4. In plugin.cpp, in the MyConfigTabProc function, **when 'nPage' is
the index (2..8) of the tab on which the control was placed:**
a. add code under WM_INITDIALOG to set the state of the control
(from the variable) when the config panel is started
b. add code under WM_COMMAND, case IDOK, to read the state
of the control and save the result in the variable
c. add a handler for your new control underneath WM_HELP, so that
when the user clicks the '?' in the config panel titlebar,
then clicks on your control, they get a helpful messagebox
explaining what the control does.
Enabling Additional Tabs (pages) on the Config Panel
----------------------------------------------------
By default, only two 'tabs' (pages) are enabled on the config panel.
The first is handled by the framework, and should not be modified;
the second, and any you add, are handled in plugin.cpp, in MyConfigTabProc().
The maximum number of tabs/pages is 8 (unless you want to modify the
framework files).
To add a third page (for example), simply open defines.h, and give a name
to the tab by setting the value of CONFIG_PANEL_BUTTON_3. This is all you
have to do to make the tab appear! To add controls to the new page, see
the above section entitled 'Adding Controls to the Config Panel.'
If you want to extend the framework to add a 9th page (?!), you need to:
1. create a dialog called IDD_PROPPAGE_9 (style=child, border=none, visible, ctrl parent, control).
2. in config.cpp, increment MAX_PROPERTY_PAGES
3. in config.cpp, add IDD_PROPPAGE_9 to g_proppage_id[]
4. in config.cpp, call AddButton for it
Using Visual C++ to Debug your Plugin
-------------------------------------
1. Build the plugin in the 'Debug' configuration
(menu:Build->Configurations, then select 'debug').
2. Go to menu:Project->Settings (ALT+F7) and click the
'Debug' tab. Under 'Executable for debug session',
point it to winamp.exe.
3. Press F5 to start debug session; it will launch winamp.
4. You can now configure your plugin or run it; just set a
breakpoint anywhere in your code (F9) and when the code
gets to that point, it will break, and you can look at
variable values and browse structures (SHIFT+F9), jump
around on the call stack (ALT+7), and so on.
Releasing a Plugin
------------------
1. Build in Release Mode
Once you're done debugging and ready to share your plugin
with others, go to menu:Build->Configurations and select
'plugin - Win32 Release', then go to menu:Build->Clean and
menu:Build->Rebuild All. Building in release mode makes
your code smaller and faster (but doesn't allow debugging).
2. Package it up an a self-installing .EXE
Here you'll want to download the Nullsoft Superpimp Install
System (NSIS) from http://www.nullsoft.com/free/nsis/ to
make your users' lives easier.
Then read the instructions at the top of the install script
file 'installer.nsi' (next to DOCUMENTATION.TXT) and edit the
install script to reflect the name and version of your plugin,
the paths & filenames & destination paths of everything you
want packaged up, and the output installer filename.
After installing NSIS, editing installer.nsi, and doing
a final release build, run a command something like this
from the command prompt (you'll have to adjust the paths):
"c:\program files\Nsis\makensis" C:\MyProjects\MyPlugin\installer.nsi
If all goes well, you'll have a file named something like
'myplugin_100.exe' in your MyPlugin directory. Test it
out on a fresh machine to make sure the install screens
say the right thing and install the right files, and
you're set to go!
3. Checklist: (prior to actually running makensis.exe)
* Did you update the version number and APPNAME in defines.h?
* Did you do a final pass on the tab ordering (CTRL+D from the
Resource Editor) of the config panel?
* Did you add WM_HELP handlers to new controls on the config panel?
* If you added any MessageBox() commands, did you supply the right
HWND parameter? (The messagebox will pop up on the same monitor
that that HWND is on.)
* Did you test your plugin in Desktop Mode, while Winamp is
*paused*, and then try moving icons around, to make sure that
you're properly handling the 'redraw' flag in MyRenderFn()?
* Did you update the version numbers throughout installer.nsi?
* Did you update the help screen text? (see top of plugin.cpp)
* Did you do your final build in Release mode?
* Did you write/update documentation?
Does the config panel link to it work?
* Did you make/update a webpage?
Does the config panel link to it work?
Tips to pass on the the user, in your documentation
---------------------------------------------------
1. In general, it's a very good idea to use only Microsoft-certified
WHQL (Windows Hardware Quality Labs) drivers for your video card.
Often people want to get the newest, fastest beta drivers, but
these drivers are almost ALWAYS riddled with new bugs.
2. If you want Winamp to listen to your sound card's Line-In or Mic-In
(or other audio input channel on your system) for driving the
visuals, just do the following:
1. CONNECT WIRES
Connect your audio source (a stereo, a live feed, whatever) into
the line-in (or microphone) 1/8" jack on your sound card.
2. SELECT SOUND INPUT CHANNEL & ADJUST VOLUME
In Windows, double-click the speaker icon in your systray (where
the clock is). Then, on the menu, go to Options -> Properties
and select the "Recording" option. Then make sure the Line In
(or Microphone) input channel (whichever is appropriate for
your case) is SELECTED (with a check mark) and that the volume
is close to, or at, the maximum. Hit OK.
3. TELL WINAMP TO USE LINE-IN
Open Winamp, and hit CTRL+L (the "Open Location" hotkey). Now
type in "linein://" as the location you want to open. (Leave out
the quotes and make sure you use FORWARD slashes.) Hit PLAY
in Winamp, and the little built-in oscilloscope (or spectrum
analyzer) in Winamp should start showing your signal.
4. RUN YOUR VISUALIZATION PLUGIN OF CHOICE
If the plugin seems to be responding too much or too little,
try adjusting the volume from Windows' Volume Control, or adjust
the sound level at the source.
3. For the best graphics performance, try to close as many other
applications as you can, before running the plugin, especially
those that tend to work in the background, such as anti-virus
or file-swapping software. Also, if you must leave other
applications open, try to minimize them (i.e. shrink the window
down to the taskbar) so that they stay out of the painting loop.
4. LCD screens: Note that most LCD screens (flatpanels) run at 60 Hz only,
meaning that they update the screen 60 times per second. However,
sometimes the video driver reports that it supports other refresh
rates, such as 72, 75, 85, etc. It is strongly recommended that
[for fullscreen mode, and for Windows in general] you choose a
display mode with a 60 Hz refresh rate, for the smoothest possible
animation. For this plugin, you will also want to choose
Maximum Framerates that divide evenly into 60 - such as 60, 30, 20,
15, 12, 10, 6, 5, and so on - so that the # of times the LCD shows
each frame of animation remains constant, resulting in the smoothest
possible animation.
5. Multiple Monitors: It is recommended that whenever you modify your Windows
multimon setup (i.e. turn an adapter on/off, change its color depth, etc.)
that you reboot Windows before running this plugin.
6. Video Capture: If you'd like to save sequences of video from this plugin,
there are several programs out there that will let you do this. Warning:
you will need a ton of free hard drive space, and a fast CPU helps. A
few of these programs are:
"FRAPS" http://www.fraps.com/
"Hypercam" http://www.hyperionics.com
(That's it, for now. PLEASE include the tip about live audio input!)
Performance Tips for DirectX 8
------------------------------
1. Minimize state changes (SetTexture, SetTextureStageState,
and SetRenderState) at all cost; group polygons together
that share the same rendering settings and send them all
together. You will be amazed at the performance gain.
2. Use Vertex Buffers and Index Buffers for all your static
geometry (i.e. vertices/indices that don't change every
frame - like a static model that doesn't change, even
though it might move around, rotate, resize, etc. due
to the world/view/projection matrices). These buffers
will keep the geometry in video memory (if possible) so
that the data doesn't have to cross the bus every frame;
if not, they'll try to at least place the geometry/indices
in AGP memory. If you don't use these driver-managed
buffers (and instead use DrawPrimitiveUP and
DrawIndexedPrimitiveUP), you're keeping all of your data
in non-AGP system memory, and unless the data is very
small, you can expect a major bottleneck. Note that for
dynamically-generated vertex data (i.e. vertices are
generated each frame - like when you draw a waveform),
you don't have a choice.
If you follow these two tips and use common sense (and know
the basic theory behind how 3D accelerators work), you should
be getting 30 fps on a Voodoo 3 (assuming your overdraw is low,
i.e. you don't draw each pixel on the screen more than once or
twice per frame).
For more tips, look in the DX8 SDK Documentation, or look on
the web.
Other Resources
---------------
1. DX8 SDK: The DX8 documentation that came with your DX8 SDK is,
by far, the most critical resource you have. It fully documents
the entire API, and much more. The SDK also comes with tons of
samples and their source code.
2. NSDN: the Nullsoft Developer Network, where the Winamp API
is published: http://www.winamp.com/nsdn/winamp2x/
If you want to do anything in MyWindowProc() that involves
communicating with the Winamp window directly (such as
querying for the song title/time/length, querying the playlist,
adjusting the panning, toggling shuffle, etc.), you'll need
to delve into NSDN. It's all extremely straightforward and
simple. For a few examples of how to talk to the main Winamp
window, check out PluginShellWindowProc() in pluginshell.cpp.
3. Here are links to a few sites with good DirectX tutorials/faqs/code:
The X-Zone: http://www.mvps.org/directx/
Gamedev.net: http://www.gamedev.net/reference/
Known Bugs
----------
1. When running [true] fullscreen in a multimon setup,
sometimes when the user presses ALT-TAB to switch away from the plugin
and to another window, the plugin will minimize. The 'sometimes' is
determined as follows:
-if the user releases TAB before depressing ALT, the window
minimizes (undesired behavior).
-if the user depresses ALT before releasing TAB, the window does
not minimize (desired behavior).
2. Desktop Mode: some features are not implemented yet. They are:
-right-click -> cut/copy/paste/rename
-right-click -> "send to" doesn't work on all machines
-no keyboard commands (delete, enter, arrows, CTRL+X/C/V/Z)
-no drag-and-drop for files
-desktop shortcuts mostly work when you double-click them,
but on some machines bring up an "open/save" dialog
instead of actually launching the file.
That's it for now.
If anyone finds a solution for any of these bugs, please post the solution
in the VMS forum, and it will be included in the next VMS release.
Version History
-----------------------------------------------------------------------
[v1.05 beta 1 - June 26, 2003]
-revamped the way keyboard commands are routed between your plugin
and the plugin shell. Before, the shell captured certain keys
('p' for playlist, 'zxcvb' for playback, 's' for shuffle, 'F1'
for help, ESC to exit, arrows for volume/seeking, etc.)
and the plugin was unable to override these. Now, the shell
will pass the WM_KEYDOWN/WM_CHAR message to the plugin
(MyWindowProc) first, to see if it wants to process it. If the
plugin steals the key, it returns 0, and the shell ignores it.
If the plugin does not process the key, it returns 1, and then
the shell is free to process it.
*** NOTE that if you are upgrading to VMS 1.05, this means you'll have to
*** update the way your WM_CHAR and WM_KEYDOWN handlers work in plugin.cpp!
*** [primarily, you'll have to return 0 when you handle a key, and 1
*** otherwise.]
-added key: 'r' for repeat
-added SKINNING; if you have Winamp 2.90+, you can now check the
'integrate with winamp' checkbox and the plugin [when running in
windowed mode] will be skinned just like Winamp. The integrated
window works just like any other Winamp window; it docks with
other windows, CTRL+TAB cycles between them all, and lots of new
keys work (J, L, CTRL+P, ALT+E, etc.).
-fixed bug (or error in judgment?) where fake fullscreen mode window
would actually run at the *bottom* of the Z order when running
on a multiple monitor setup. The problem was that if you clicked
on any other window, the taskbar would pop up, potentially overtop
of the plugin. Since there's really no way around this, I decided
(before) to just stick the plugin at the bottom of the Z order in
this case. Well, this is now fixed; the plugin tries its best
to stay on top, but watch out - if you try and click on any other
windows, the taskbar WILL pop up. If you want to avoid that,
you'll have to run in true fullscreen mode.
-improved audio and video synchronization
-the current framerate is now used to tell Winamp, each frame,
exactly how far in advance it should give us the audio data.
For example, if we're getting 20 fps, we should get the
audio 50 ms in advance for the proper video frame to appear
when the user will actually hear those audio samples.
-timing: added calls to beginTimePeriod and endTimePeriod, so the assumed
granularity for Sleep() is now 2 ms (down from 10 ms).
This means that CPU usage will dramatically drop, and
fortunately, there should be no effect on framerate accuracy.
-desktop mode: added 'show icons' option to the desktop mode options
dialog, so users can uncheck it (and hide/disable the icons) if they
like.
-user can no longer shrink the window to less than 64x48 in size.
(often the minimum size will be higher than this though; see
WM_GETMINMAXINFO in pluginshell.cpp).
-user can now switch modes (windowed <-> fullscreen <-> desktop mode)
immediately. (before, it was blocked until frame 5.)
-(fixed a small bug in the example plugin, where handler for WM_KEYUP
returned DefWindowProc instead of 1).
-any time the DirectX setup fails when starting up (or switching to)
windowed mode, the window coords are now saved to disk as a 256x256
window placed at (64,64). That way, if the problem was due to running
out of video memory, it will be less likely to recur.
-config panel:
-added two more fonts: one for the playlist, and another for the
help screen.
-it's now easy to add your own fonts to the font dialog in the
config panel; just add the appropriate #defines in the file
defines.h. Then you can access them easily from plugin.cpp by
calling GetFont(EXTRA_1), GetFont(EXTRA_2), and so on, up to
GetFont(EXTRA_5). You can also get their height by calling
GetFontHeight(EXTRA_1) through GetFontHeight(EXTRA_5).
-greatly improved the installer script.
-now selects winamp2 dir by default, if both winamp 2 & 3 are installed.
-fixed a bug where the plugin wasn't being correctly set as the default plugin
in winamp. Also, this is no longer an option - it just automatically does it.
-now, when you go to install to winamp 3, it checks to see if ClassicVis
is installed. If it is, you're set; if not, it prompts you to go download
it. If you choose not to, it alerts you that the installation failed.
-the FFT class (fft.cpp, fft.h) now has 2 extra optional init parameters.
-'bEqualize' is 1 by default; set it to 0 to have a non-equlized FFT;
bass frequencies will be much higher in magnitude than treble frequencies.
-'envelope_power' is 1.0 by default; adjust it to change the characteristics
of the resulting frequency spectrum (see comments in fft.cpp, in
InitEnvelopeTable). Set this to a negative value to not use an envelope.
-the help screen is no longer pre-rendered to a texture; it is now just drawn every
frame that it's needed. (Decided that that precious memory on some 8MB graphics
cards was more important than having a good framerate, on some cards, while viewing
the help screen.)
-added some nice macros to MyRenderUI() in plugin.cpp; makes the code for drawing
text much simpler.
-added 2 functions, GetDriver and GetDesc, which will return text strings with the
name & description of the currently active display adapter. (search these
strings for vendor substrings like "nvidia", using strstr or something similar,
to do vendor-specific bug workarounds. blech.)
-fixed a bug in SSE detection
-added handy memset_MMX() function to utility.cpp (alongside memcpy_MMX)
-fixed tabbing order for controls config panel tab #1 (doh)
-in 'defines.h', you now specify a long name + a short name for your plugin.
The long name is used for the description string in winamp's list of plugins;
the short name is used for the window caption.
-in the example plugin, in plugin.cpp, the F3 key (show song length)
is now a three-state toggle: off, current time, and current time / total
length.
[v1.04 - October 29, 2002]
-DESKTOP MODE: the icing on the cake.
-Allows users to run your plugin as animated wallpaper, with very
little cpu overhead. Uses no overlays or other unusual hardware
features.
-Just make sure you include the file 'vms_desktop.dll' with your
plugin; it is required for Desktop Mode to work properly.
It's small, though - only 48 kb. This file is now included
in the sample install script (installer.nsi).
-You can toggle Desktop Mode on/off at runtime by hitting ALT+D.
And as before, you can toggle Fullscreen via ALT+ENTER.
-Not all features of the desktop are fully implemented, but most
of the most-frequently-used features should be working.
For a list of the features not yet implemented, see the
'Known Bugs' section above.
-CHANGES MADE TO PLUGIN.H,CPP: (isolated for ease-of-merging purposes)
1. added a few config settings; see OverrideDefaults()
in PLUGIN.CPP.
2. added 'redraw' flag to MyRenderFn - see the comments
at the top of MyRenderFn. Make sure you respect this
flag, or else, when the user moves icons around in
Desktop Mode while Winamp is paused, your plugin
will mysteriously start animating.
3. added the 'MyRenderUI' function - please break your
text-rendering code in MyRenderFn off into this function.
4. removed the ClipPlaylist() functions and, instead, provided
pointers to some values as params to MyRenderUI() that tell
you where to place text in each of the corners. As you
draw text, be sure to update these values, so that any
text drawn by the plugin shell (parent class) won't try to
draw text overtop of your text.
-Plugins based on VMS now remember the window position when they last
(successfully) exited windowed mode, and use that as the
default when they re-enter windowed mode (during the same
session or in a later session). If there is an error creating
that window (too big/not enough video memory, off-screen
because display mode resolution decreased, etc.) it will
revert to the default window size & position.
-Config Panel:
-For users with DualHead cards that run two monitors as one
virtual display (e.g. 2048x768 or 1024x1536), you can now
specify which half of the screen you want Fake Fullscreen Mode
and Desktop Mode to occupy, or both. See the 'DualHead'
button on the config panel.
-Added an option to save cpu usage by using a more-tolerant
framerate limitation algorithm - saves 0-20%. Default: ON.
-Fixed appearance of the help screen by adding +0.5-texel offset;
on some cards, help screen text was kind of jaggy and munged.
-Release builds no longer log window messages to the debug
output stream.
-The D3DX font for the help screen text is now created at
initialization time, instead of on demand.
-Framework Files:
-renamed 'fontdialog.cpp' to 'config2.cpp', since it now contains
more than just the font dialog code.
-added 'desktop_mode.cpp' and 'icon_t.h' to support Desktop Mode.
-Changes made to the sample installer script: [installer.nsi]
-added UnInstall options for winamp 2 and 3
-simplified things by using some !define's at the top
-updated it to look for Winamp 3's new executable
name: winamp3.exe (in addition to the old, which was
studio.exe)
-----------------------------------------------------------------------
[v1.03 - August 27, 2002]
[MAJOR CHANGES]
-audio:
-vastly improved frequency analysis by multiplying the waveform by a
bell-shaped envelope before sending it to the FFT, lessening the
frequency response of the old square filter and producing a more
precise frequency analysis. Also improved it by doing a 1024-sample
FFT (instead of a 512). Special thanks goes out to Alan Seefeldt
and Alan Peevers for sharing their extensive knowledge in this area!
-config panel:
-split it into separate property sheets, so that
future updates to VMS (this sdk) will be easier to integrate
with code based on previous versions. Also, this gives developers
a lot more space to add things to the config panel.
-split the settings for 'fake fullscreen' mode and regular
fullscreen mode into two separate sets of controls, instead
of sharing controls; it was too confusing that way.
-added option to minimize winamp when going fullscreen.
Only actually minimizes winampwhen going fullscreen
(or fake fullscreen) AND winamp and the plugin window
are situated on the same monitor.
-added user-configurable fonts to the config panel.
-text:
-added a built-in playlist!
-added some sample code (in plugin.cpp / RenderText()) for showing
the current song title, position, and length.
-timing:
-oops... hi-precision timer was disabled in last version!
-also discovered an even more high-precision timer, which provides
a time sampling precision of from 1 to 5 *MICRO*seconds!
-ditched the 'frame delay' system and replaced it with a 'max fps'
system that should work more intuitively, and be extremely
accurate (thanks to the new timer).
-classes:
-got rid of InitMyGDIStuff() and CleanUpMyGDIStuff() - not really needed
-got rid of MyPreRenderFn() - also not really needed
-in windowed mode, if there is not enough video memory to create
the window at the default size, the window will now try to shrink
further and further, until it is small enough to work.
-fixed problem where the plugin wouldn't show up in the plug-ins list
in Winamp, if the user didn't have DX8 or later installed. Now
it does show up in the list, and if they try to run/configure it
and DX8 is missing, it will indicate this, and even offer to
take them to the MS DirectX website to download it.
-also started calling LoadLibrary("d3d8.dll") before calling
Direct3DCreate8(), so the latter wouldn't crash on systems
without DX8.
-yanked the fractal stuff out of the example plugin; too complicated.
[MINOR CHANGES]
-now more resilient when user turns off some display (in a multimon
setup), then goes to run the plugin on that display (because they
didn't return to the config panel and update the display adapter
selection).
-improved suggested actions for when the plugin fails to start
because there is not enough video memory; suggestions now
include turning off other programs that might be using up
video memory (Windows Media Player, NetMeeting, and so on).
-config panel: disabled caps checking; sometimes requesting
the caps fails when you dynamically enable/disable monitors in
a multimon setup, so adapters that really exist (and are on)
would be missing in the list.
-config panel: added a sample combobox & slider to the 2nd property page,
which now features a checkbox, slider, and combobox, all
as simple examples for the plugin developer to build off of.
-noticed that multipsampling only works with D3DSWAPEFFECT_DISCARD,
so the code is now protected against using D3DSWAPEFFECT_COPY_VSYNC
with multisampling. The config panel has also been updated to
indicate to the user that if page tearing is disallowed,
multisampling will not function. This is a limitation of
the DirectX 8 API.
-added OverrideDefaults() function; see comments in plugin.cpp
-revamped the sample beat detection code
-tightened up the interface to CPluginShell
-made DirectX get initialized earlier (and cleaned up later)
so that GetWidth() and GetHeight() would be valid longer
-moved srand(time(NULL)) up to top of MyPreInitialize, in case
the developer wants to randomly initialize any of their
variables there.
-modified PrepareFor2DDrawing() so that it always makes the range
of X,Y coords -1..1 (before it was -width/2..width/2, and similarly
for height). Also inverted Y, so that y==-1 is actually at the
top of the screen, and Y==1 is at the bottom.
-added PrepareFor3DDrawing()
-improved auto-selection of best-match video mode; now, if it can't
find the exact pixel format that was in the INI file,
if will try other video modes that have the same bit depth,
but a different arrangement of the bits. [This applies to both
the config panel, AND when you go to run the plugin fullscreen.]
-respected key repeat count for playlist navigation (up/down), volume
adjust (up/down), and seeking (left/right).
-fixed a bug where the plugin would close on WM_KEYUP/VK_ESCAPE. Now,
instead, it closes on WM_KEYDOWN/VK_ESCAPE. This was a problem when
you hit ESCAPE to close some other app (on WM_KEYDOWN), then the focus
went to the plugin, and WM_KEYUP/VK_ESCAPE got sent to the plugin.
Not sure why it was even like this in the first place...
-fixed a timing but where, when the frame delay was zero (or fps
was unlimited), and the plugin was using the low-precision timer,
the fps reading would blow up and m_time would stop.
-fixed a bug w/a parameter to CreateFont: max font weight was
900; 'twas calling it with 1000
-fixed bug with context menu cleanup
-fixed a bug where winamp playback nav. keys (zxcvbs) were
handled under WM_KEYDOWN; should have been under WM_CHAR.
-fixed a bug where DXContext was calling DestroyWindow (on the final
exit of the plugin), when in fact, the window had already been
destroyed (by Windows, it seems).
-fixed a bug in config panel, where list of video modes wasn't updating
when you changed the fullscreen adapter.
-fixed a bug where DXContext was remembering the native windows display
mode for the first monitor that the window was created on, only.
This was a problem because if two monitors had different bit depths,
and you ran it and switched to another monitor by toggling fullscreen,
it would try to create a device with a back buffer whose bit depth
was that of the original monitor. To fix this, it now does the
following: the first time it creates a window, before changing the
display mode, it remembers the native display mode for all the
adapters present, then uses the appropriate one whenever it needs
it.
-deleted the 'DX8 Includes' project folder from the workspace;
use 'External Dependencies' folder instead, it automatically
points you to the right directories.
-----------------------------------------------------------------------
[1.02, August 5, 2002]
-Fixed bug where the plugin would minimize if you were running
[true] fullscreen with multiple monitors, and went to click
in another window. Previously the workaround was to use fake
fullscreen mode, but now this is not necessary. Fake fullscreen
mode still remains, though; for the rationale, see the help text
for the 'fake fullscreen mode' checkbox in the config panel.
-Decided that InitMyNonDx8Stuff() should be called first, instead
of last, and that CleanUpMyNonDx8Stuff() should be called last,
not first.
-Might have fixed a bug with high-precision timer.
-Added a custom icon (...which the developer can modify, of course).
-----------------------------------------------------------------------
[1.01, July 19, 2002]
-Initial release
-----------------------------------------------------------------------
License
-------
Copyright (C) 1999-2002 Nullsoft, Inc.
This source code is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this source code or the software it produces.
Permission is granted to anyone to use this source code for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.