<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.winamp.com/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://wiki.winamp.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tarik</id>
		<title>Winamp Developer Wiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.winamp.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tarik"/>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Special:Contributions/Tarik"/>
		<updated>2026-05-03T18:11:04Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.22.3</generator>

	<entry>
		<id>http://wiki.winamp.com/wiki/Winamp_Developer_Network_Wiki_Terms_and_Conditions</id>
		<title>Winamp Developer Network Wiki Terms and Conditions</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Winamp_Developer_Network_Wiki_Terms_and_Conditions"/>
				<updated>2008-10-10T13:50:50Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: /* About These Terms */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Winamp Developer Network Wiki Terms and Conditions==&lt;br /&gt;
&lt;br /&gt;
Welcome!  The following terms govern your access, use and participate in Winamp’s Developer Network Wiki (“Wiki Service”). &lt;br /&gt;
&lt;br /&gt;
BY REGISTERING OR BY USING THE WIKI SERVICE, YOU SIGNIFY ELECTRONICALLY YOUR AGREEMENT TO THE FOLLOWING TERMS. If you do not agree, you may not use the Wiki Service.&lt;br /&gt;
&lt;br /&gt;
==About the Developer Network Wiki==&lt;br /&gt;
&lt;br /&gt;
The Wiki Service is a centralized resource that offers a consolidation of Winamp documentation, code samples, reference materials, and sample articles and gives the development community a place to share information. We offer the Wiki Service to help facilitate the development of Winamp skins, plugins, and visualization presets.  &lt;br /&gt;
&lt;br /&gt;
==About These Terms==&lt;br /&gt;
&lt;br /&gt;
The Wiki Service is provided by Nullsoft, Inc. and its affiliates (collectively, “we” or “us”). In order to use the Wiki Service, you must abide by Nullsoft Terms of Use for Winamp.com (http://www.winamp.com/legal/terms), the supplemental Wiki terms below, the Wiki Policy and Guidelines located at (http://dev.winamp.com/wiki/Policies_%26_Guidelines) and such other policies that we may post from time to time on the Wiki Service. These terms collectively make up your agreement with us regarding your access and use the Wiki Service (the “Terms”). We may change these Terms at any time. Your ongoing use of the Wiki Service after we post or notify you about changes to our terms signifies your agreement electronically to the updated terms.&lt;br /&gt;
&lt;br /&gt;
==Your requirements==&lt;br /&gt;
&lt;br /&gt;
In order to use the Wiki Service, you must register with us and provide complete, accurate and current information about yourself. You must keep this information up to date at all times. You must comply at all times with applicable laws and these Terms.&lt;br /&gt;
&lt;br /&gt;
==Use of Information==&lt;br /&gt;
&lt;br /&gt;
The Winamp Privacy Policy located at http://www.winamp.com/legal/privacy explains the practices that apply to your information when you use the Wiki Service. Your ongoing use of the Wiki Service signifies your consent to the information practices disclosed in our Privacy Policy.&lt;br /&gt;
&lt;br /&gt;
==Use of Wiki Service== &lt;br /&gt;
&lt;br /&gt;
You may not submit or transmit through the Wiki Service any material, or otherwise engage in any conduct that: &lt;br /&gt;
#violates or infringes the rights of others including, without limitation, patent, trademark, trade secret, copyright, publicity or other proprietary rights,&lt;br /&gt;
#is unlawful, threatening, abusive, harassing, defamatory, libelous, deceptive, fraudulent, invasive of another's privacy, tortious, or contains explicit or graphic descriptions, or accounts of, sexual acts,&lt;br /&gt;
#victimizes, harasses, degrades, or intimidates an individual or group of individuals on the basis of religion, gender, sexual orientation, race, ethnicity, age, or disability,&lt;br /&gt;
#impersonates any person, business or entity, &lt;br /&gt;
#contains viruses or any other malicious computer code, &lt;br /&gt;
#encourages conduct that would constitute a criminal offense, or that gives rise to civil liability,&lt;br /&gt;
#transmits, directly or indirectly, any unsolicited bulk communications (including e-mails, “spam” and instant messages),&lt;br /&gt;
#violates these Terms, including without limitation, the Nullsoft Terms of Use for Winamp.com, or&lt;br /&gt;
#interferes with the use of the Wiki Service or any other area on Winamp.com by others.&lt;br /&gt;
&lt;br /&gt;
==Ownership==&lt;br /&gt;
&lt;br /&gt;
The content on Wiki Service including, without limitation, images, graphics, audio, music, videos, texts, software, feedback, data, messages, answers, questions, comments, suggestions, ideas or any other materials (“Content”) are owned or licensed by us and protected under copyright and other intellectual property right laws. All trade names, trademarks and service marks appearing on the Content are protected by Nullsoft, Inc., its parent and affiliates or respective third party owners. Any rights not expressly granted herein are reserved. All Content is for your application development purposes and for your personal use only and may not be modified, reproduced, transmitted, published, exploited, sold, licensed or distributed to any third parties or in combination with any applications if the Content would constitute the primary value of the product being distributed.&lt;br /&gt;
 &lt;br /&gt;
==Submissions== &lt;br /&gt;
&lt;br /&gt;
The Wiki Service allows users to upload, download, edit, host, share and/or publish Content (“User Content”). We may, in our sole discretion, incorporate such User Content into any of our products or services. &lt;br /&gt;
&lt;br /&gt;
You are solely responsible for any submission of User Content. You may only submit User Content that you own or that you have acquired such consents, permissions or licenses needed to submit such Content. If your User Content contains content of a third party or open source material, you shall clearly notify us of such third-party material together with any license terms that deviate from those specified in these Terms, as well as be responsible for acquiring consent for such use the User Content. Any such third party content or open source material shall be subject to your obligation to indemnify us. Upon submission of any User Content to the Wiki Service, you will grant us and our parent a worldwide, perpetual, irrevocable, royalty-free, non-exclusive, assignable and sublicensable license to use, reproduce, modify, create derivative works, publicly perform and display such User Content in connection with any of our products or services, entirely without obligation, compensation or restriction of any kind. &lt;br /&gt;
 &lt;br /&gt;
==No Duty to Monitor==&lt;br /&gt;
&lt;br /&gt;
You agree that we are not liable for Content (including User Content) that is provided by others. We have no duty to pre-screen Content, but we have the right to refuse to post or to edit submitted Content. We reserve the right to remove Content for any reason, but we are not responsible for any failure or delay in removing such material. &lt;br /&gt;
&lt;br /&gt;
==Procedure for Making Claims of Copyright Infringement.== &lt;br /&gt;
&lt;br /&gt;
We respect the intellectual property of others. If you believe that your work has been copied and is accessible on the Wiki Service in a way that constitutes copyright infringement, please click here &amp;lt;http://about.aol.com/aolnetwork/copyright_infringement&amp;gt; for instructions on how to contact us to report possible copyright infringement.&lt;br /&gt;
&lt;br /&gt;
==No Warranties==&lt;br /&gt;
&lt;br /&gt;
We provide the Wiki Service &amp;quot;as is&amp;quot;, &amp;quot;with all faults&amp;quot; and &amp;quot;as available.&amp;quot; You use the Content and Wiki Service at your own risk. We and our suppliers and distributors make no express warranties or guarantees about the Wiki Service. TO THE EXTENT PERMITTED BY LAW, WE AND OUR SUPPLIERS DISCLAIM IMPLIED WARRANTIES THAT THE WIKI SERVICE ARE MERCHANTABLE, OF SATISFACTORY QUALITY, ACCURATE, TIMELY, FIT FOR A PARTICULAR PURPOSE OR NEED, OR NON-INFRINGING. WE DO NOT GUARANTEE THAT THE WIKI SERVICE WILL MEET YOUR REQUIREMENTS, IS ERROR-FREE, RELIABLE, WITHOUT INTERRUPTION OR AVAILABLE AT ALL TIMES. WE DO NOT GUARANTEE THAT THE RESULTS THAT MAY BE OBTAINED FROM THE WIKI SERVICE OR THAT YOU WILL BE ABLE TO ACCESS THE WIKI SERVICE AT ALL TIMES. You may have additional consumer rights under your local laws that this contract cannot change. &lt;br /&gt;
&lt;br /&gt;
==Limitation of Liability==&lt;br /&gt;
&lt;br /&gt;
YOUR SOLE AND EXCLUSIVE REMEDY FOR ANY DISPUTE WITH US IS TO DISCONTINUE YOUR USE OF THE WIKI SERVICE. WE, OUR PARENT, AND OUR SUPPLIERS SHALL NOT BE LIABLE FOR ANY INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES ARISING FROM YOUR USE OF, INABILITY TO USE, OR RELIANCE UPON AOL.COM. THESE EXCLUSIONS APPLY TO ANY CLAIMS FOR LOST PROFITS, LOST DATA, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF WE KNEW OR SHOULD HAVE KNOWN OF THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME STATES OR JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR THE LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, IN SUCH STATES OR JURISDICTIONS, OUR LIABILITY, AND THE LIABILITY OF OUR PARENT AND SUPPLIERS, SHALL BE LIMITED TO THE EXTENT PERMITTED BY LAW. &lt;br /&gt;
&lt;br /&gt;
==Indemnification==&lt;br /&gt;
&lt;br /&gt;
Upon a request by us, you agree to defend, indemnify, and hold harmless us and our parent and other affiliated companies, and our respective employees, contractors, officers, directors, and agents from all liabilities, claims, and expenses, including attorney's fees that arise from your use or misuse of the Wiki Service. We reserve the right, at our own expense, to assume the exclusive defense and control of any matter otherwise subject to indemnification by you, in which event you will cooperate with us in asserting any available defenses. &lt;br /&gt;
&lt;br /&gt;
==International Use==&lt;br /&gt;
&lt;br /&gt;
We make no representation that Content on the Wiki Service is appropriate or available for use in locations outside the United States, and accessing it from territories where the Content is illegal is prohibited. If you choose to access the Wiki Service from a location outside the U.S., you do so on your own initiative and you are responsible for compliance with local laws. &lt;br /&gt;
&lt;br /&gt;
==Software Restrictions==&lt;br /&gt;
&lt;br /&gt;
Any software offered through the Wiki Service is a &amp;quot;commercial item,&amp;quot; as that term is defined in 48 C.F.R. 2.101, consisting of &amp;quot;commercial computer software&amp;quot; and &amp;quot;commercial computer software documentation,&amp;quot; as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 27.405(b)(2) (June 1998) and 48 C.F.R. 227.7202, all U.S. Government end users acquire the software with only those rights as set forth herein. You agree to fully comply with all import and export laws, regulations, rules and orders of the United States, or any foreign government agency or authority, and that you will not directly or indirectly export, re-export, transfer and/or release the software, related technology, or any product thereof, for any proscribed end-use, or to any proscribed country, entity or person (wherever located), without proper authorization from the U.S. and/or foreign government. &lt;br /&gt;
&lt;br /&gt;
==Choice of Law==&lt;br /&gt;
&lt;br /&gt;
You agree that the laws of the Commonwealth of Virginia govern this contract and any claim or dispute that you may have against us, without regard to Virginia’s conflict of laws rules, and that the United Nations Convention on Contracts for the International Sale of Goods shall have no applicability. You further agree that any disputes or claims that you may have against us will be resolved by a court located in the Commonwealth of Virginia and you agree and submit to the exercise of personal jurisdiction of such courts for the purpose of litigating any such claim or action. PLEASE NOTE THAT BY AGREEING TO THESE TERMS OF USE, YOU ARE: (1) WAIVING CLAIMS THAT YOU MIGHT OTHERWISE HAVE AGAINST US BASED ON THE LAWS OF OTHER JURISDICTIONS, INCLUDING YOUR OWN; (2) IRREVOCABLY CONSENTING TO THE EXCLUSIVE JURISDICTION OF, AND VENUE IN, STATE OR FEDERAL COURTS IN THE COMMONWEALTH OF VIRGINIA OVER ANY DISPUTES OR CLAIMS YOU HAVE WITH US; AND (3) SUBMITTING YOURSELF TO THE PERSONAL JURISDICTION OF COURTS LOCATED IN THE COMMONWEALTH OF VIRGINIA FOR THE PURPOSE OF RESOLVING ANY SUCH DISPUTES OR CLAIMS.&lt;br /&gt;
&lt;br /&gt;
==Termination==&lt;br /&gt;
&lt;br /&gt;
Your right to use the Wiki Service automatically terminates if you violate these Terms or any rules or guidelines posted in connection with AOL.COM. We also reserve the right, in our sole discretion, to terminate your access to all or part of the Wiki Service, for any reason, with or without notice.&lt;br /&gt;
&lt;br /&gt;
==Electronic Notices==&lt;br /&gt;
&lt;br /&gt;
YOU AGREE TO TRANSACT WITH US ELECTRONICALLY. WE MAY PROVIDE NOTICES TO YOU ELECTRONICALLY (1) VIA E-MAIL IF YOU HAVE PROVIDED US WITH A VALID EMAIL ADDRESS OR (2) BY POSTING THE NOTICE ON A WEBSITE DESIGNATED BY US FOR THIS PURPOSE. The delivery of any Notice is effective when sent or posted by us, regardless of whether you read the Notice or actually receive delivery. You can withdraw your consent to receive Notices electronically by discontinuing your use of the Wiki Service. &lt;br /&gt;
&lt;br /&gt;
==General Terms==&lt;br /&gt;
&lt;br /&gt;
(a) This agreement constitutes the entire agreement between you and us concerning the subject matter of these Terms, which may only be modified by us. (b) This Agreement shall not be governed by the United Nations Convention on Contracts for the International Sale of Goods. (c) If any part of these Terms is held invalid or unenforceable, that part shall be construed to reflect the parties' original intent as nearly as practicable, and the remaining portions remain in full force and effect, or we may at its option instead terminate this Agreement. (d) English is the controlling language of these Terms. If you have received a translation into another language, it has been provided for your convenience only. (e) A waiver by either party of any term or condition of this Agreement or any breach thereof, in any one instance, shall not waive such term or condition or any subsequent breach thereof. (f) You may not assign or otherwise transfer by operation of law or otherwise this Agreement or any rights or obligations herein. We may assign these Terms to any entity, including to any of our affiliates or parent at our sole discretion. (g) These Terms shall be binding upon and shall inure to the benefit of the parties, their successors and permitted assigns.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Articles</id>
		<title>Articles</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Articles"/>
				<updated>2008-09-26T14:44:25Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: /* Modern Skins */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Skin Articles==&lt;br /&gt;
&lt;br /&gt;
===Classic Skins===&lt;br /&gt;
*Link to Classic Skin Article 1&lt;br /&gt;
&lt;br /&gt;
===Modern Skins===&lt;br /&gt;
*[http://dev.aol.com/article/2007/winamp_skins Winamp Skins Development Tutorial]&lt;br /&gt;
*Link to Modern Skin Article 2&lt;br /&gt;
*[[Creating a ClassicPro Skin]]&lt;br /&gt;
&lt;br /&gt;
===ClassicPro Skins===&lt;br /&gt;
* [[Creating a ClassicPro Skin]]&lt;br /&gt;
&lt;br /&gt;
==Visualization Articles==&lt;br /&gt;
*[[MilkDrop_Preset_Authoring|MilkDrop Preset Authoring]]&lt;br /&gt;
*Link to vis Article 2&lt;br /&gt;
&lt;br /&gt;
==Plug-in Articles==&lt;br /&gt;
&lt;br /&gt;
*[[Wasabi|Overview of the Wasabi API]]&lt;br /&gt;
*[[Decode File API]]&lt;br /&gt;
*[[Media Library Plugin|How to create a Media Library plugin]]&lt;br /&gt;
*[[Input Plugin|How to create an Input plugin]]&lt;br /&gt;
*[[General Purpose Plugin|General Purpose plugins]]&lt;br /&gt;
*[[Output Plugin|How to create an Output plugin]]&lt;br /&gt;
*[[DSP Plugin|Audio Effects (DSP) plugins]]&lt;br /&gt;
*[[Random API]]&lt;br /&gt;
*[[Language API]]&lt;br /&gt;
*[[Agave Config API]]&lt;br /&gt;
*[[Album Art API]]&lt;br /&gt;
*[[Tagz API]]&lt;br /&gt;
*[[XML Parser Object]]&lt;br /&gt;
*[[System Callbacks API]]&lt;br /&gt;
*[[Skin API]]&lt;br /&gt;
*[[Service Manager API]]&lt;br /&gt;
*[[Memory Manager API]]&lt;br /&gt;
*[[Image Writer Service]]&lt;br /&gt;
*[[Image Loader Service]]&lt;br /&gt;
*[[Text Feed Service]]&lt;br /&gt;
*[[File Reader Service]]&lt;br /&gt;
*[[Application API]]&lt;br /&gt;
*[[Replay Gain API]]&lt;br /&gt;
*[[Podcasts API]]&lt;br /&gt;
*[[Agave Metadata API]]&lt;br /&gt;
*[[System Component Interface]]&lt;br /&gt;
*[[Burner API]]&lt;br /&gt;
*[[Audio Encoder Plugin|Audio encoders (transcoding, CD ripper)]]&lt;br /&gt;
*[[Skinning Plugins|WAC Skinning plugins]]&lt;br /&gt;
*[[Nullsoft Database Engine|Nullsoft Database Engine (NDE)]]&lt;br /&gt;
*[[JNetLib|JNetLib networking library]]&lt;br /&gt;
*[[APE Plugins|AVS Plugins]]&lt;br /&gt;
*[[NSV Plugins|NSV Audio and Video decoders]]&lt;br /&gt;
*[[Playlist API]]&lt;br /&gt;
*[[Media Core API|Media Core API (Freeform skins only!)]]&lt;br /&gt;
*[[SendMessage API|Winamp 2 API]]&lt;br /&gt;
*[[Media Library API|Media Library SendMessage API]]&lt;br /&gt;
*[[Plugin Terminology]]&lt;br /&gt;
&lt;br /&gt;
==Web Development Articles==&lt;br /&gt;
* [[HTTP Example Plugin]]&lt;br /&gt;
* [[Javascript External Interface]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Articles</id>
		<title>Articles</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Articles"/>
				<updated>2008-09-26T14:44:07Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: /* Modern Skins */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Skin Articles==&lt;br /&gt;
&lt;br /&gt;
===Classic Skins===&lt;br /&gt;
*Link to Classic Skin Article 1&lt;br /&gt;
&lt;br /&gt;
===Modern Skins===&lt;br /&gt;
*[http://dev.aol.com/article/2007/winamp_skins Winamp Skins Development Tutorial]&lt;br /&gt;
*Link to Modern Skin Article 2&lt;br /&gt;
*[[Creating a ClassicPro Skin]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===ClassicPro Skins===&lt;br /&gt;
* [[Creating a ClassicPro Skin]]&lt;br /&gt;
&lt;br /&gt;
==Visualization Articles==&lt;br /&gt;
*[[MilkDrop_Preset_Authoring|MilkDrop Preset Authoring]]&lt;br /&gt;
*Link to vis Article 2&lt;br /&gt;
&lt;br /&gt;
==Plug-in Articles==&lt;br /&gt;
&lt;br /&gt;
*[[Wasabi|Overview of the Wasabi API]]&lt;br /&gt;
*[[Decode File API]]&lt;br /&gt;
*[[Media Library Plugin|How to create a Media Library plugin]]&lt;br /&gt;
*[[Input Plugin|How to create an Input plugin]]&lt;br /&gt;
*[[General Purpose Plugin|General Purpose plugins]]&lt;br /&gt;
*[[Output Plugin|How to create an Output plugin]]&lt;br /&gt;
*[[DSP Plugin|Audio Effects (DSP) plugins]]&lt;br /&gt;
*[[Random API]]&lt;br /&gt;
*[[Language API]]&lt;br /&gt;
*[[Agave Config API]]&lt;br /&gt;
*[[Album Art API]]&lt;br /&gt;
*[[Tagz API]]&lt;br /&gt;
*[[XML Parser Object]]&lt;br /&gt;
*[[System Callbacks API]]&lt;br /&gt;
*[[Skin API]]&lt;br /&gt;
*[[Service Manager API]]&lt;br /&gt;
*[[Memory Manager API]]&lt;br /&gt;
*[[Image Writer Service]]&lt;br /&gt;
*[[Image Loader Service]]&lt;br /&gt;
*[[Text Feed Service]]&lt;br /&gt;
*[[File Reader Service]]&lt;br /&gt;
*[[Application API]]&lt;br /&gt;
*[[Replay Gain API]]&lt;br /&gt;
*[[Podcasts API]]&lt;br /&gt;
*[[Agave Metadata API]]&lt;br /&gt;
*[[System Component Interface]]&lt;br /&gt;
*[[Burner API]]&lt;br /&gt;
*[[Audio Encoder Plugin|Audio encoders (transcoding, CD ripper)]]&lt;br /&gt;
*[[Skinning Plugins|WAC Skinning plugins]]&lt;br /&gt;
*[[Nullsoft Database Engine|Nullsoft Database Engine (NDE)]]&lt;br /&gt;
*[[JNetLib|JNetLib networking library]]&lt;br /&gt;
*[[APE Plugins|AVS Plugins]]&lt;br /&gt;
*[[NSV Plugins|NSV Audio and Video decoders]]&lt;br /&gt;
*[[Playlist API]]&lt;br /&gt;
*[[Media Core API|Media Core API (Freeform skins only!)]]&lt;br /&gt;
*[[SendMessage API|Winamp 2 API]]&lt;br /&gt;
*[[Media Library API|Media Library SendMessage API]]&lt;br /&gt;
*[[Plugin Terminology]]&lt;br /&gt;
&lt;br /&gt;
==Web Development Articles==&lt;br /&gt;
* [[HTTP Example Plugin]]&lt;br /&gt;
* [[Javascript External Interface]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Articles</id>
		<title>Articles</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Articles"/>
				<updated>2008-09-26T14:41:33Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: /* Classic Skins */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Skin Articles==&lt;br /&gt;
&lt;br /&gt;
===Classic Skins===&lt;br /&gt;
*Link to Classic Skin Article 1&lt;br /&gt;
&lt;br /&gt;
===Modern Skins===&lt;br /&gt;
*[http://dev.aol.com/article/2007/winamp_skins Winamp Skins Development Tutorial]&lt;br /&gt;
*Link to Modern Skin Article 2&lt;br /&gt;
*[[Creating a ClassicPro Skin]]&lt;br /&gt;
&lt;br /&gt;
==Visualization Articles==&lt;br /&gt;
*[[MilkDrop_Preset_Authoring|MilkDrop Preset Authoring]]&lt;br /&gt;
*Link to vis Article 2&lt;br /&gt;
&lt;br /&gt;
==Plug-in Articles==&lt;br /&gt;
&lt;br /&gt;
*[[Wasabi|Overview of the Wasabi API]]&lt;br /&gt;
*[[Decode File API]]&lt;br /&gt;
*[[Media Library Plugin|How to create a Media Library plugin]]&lt;br /&gt;
*[[Input Plugin|How to create an Input plugin]]&lt;br /&gt;
*[[General Purpose Plugin|General Purpose plugins]]&lt;br /&gt;
*[[Output Plugin|How to create an Output plugin]]&lt;br /&gt;
*[[DSP Plugin|Audio Effects (DSP) plugins]]&lt;br /&gt;
*[[Random API]]&lt;br /&gt;
*[[Language API]]&lt;br /&gt;
*[[Agave Config API]]&lt;br /&gt;
*[[Album Art API]]&lt;br /&gt;
*[[Tagz API]]&lt;br /&gt;
*[[XML Parser Object]]&lt;br /&gt;
*[[System Callbacks API]]&lt;br /&gt;
*[[Skin API]]&lt;br /&gt;
*[[Service Manager API]]&lt;br /&gt;
*[[Memory Manager API]]&lt;br /&gt;
*[[Image Writer Service]]&lt;br /&gt;
*[[Image Loader Service]]&lt;br /&gt;
*[[Text Feed Service]]&lt;br /&gt;
*[[File Reader Service]]&lt;br /&gt;
*[[Application API]]&lt;br /&gt;
*[[Replay Gain API]]&lt;br /&gt;
*[[Podcasts API]]&lt;br /&gt;
*[[Agave Metadata API]]&lt;br /&gt;
*[[System Component Interface]]&lt;br /&gt;
*[[Burner API]]&lt;br /&gt;
*[[Audio Encoder Plugin|Audio encoders (transcoding, CD ripper)]]&lt;br /&gt;
*[[Skinning Plugins|WAC Skinning plugins]]&lt;br /&gt;
*[[Nullsoft Database Engine|Nullsoft Database Engine (NDE)]]&lt;br /&gt;
*[[JNetLib|JNetLib networking library]]&lt;br /&gt;
*[[APE Plugins|AVS Plugins]]&lt;br /&gt;
*[[NSV Plugins|NSV Audio and Video decoders]]&lt;br /&gt;
*[[Playlist API]]&lt;br /&gt;
*[[Media Core API|Media Core API (Freeform skins only!)]]&lt;br /&gt;
*[[SendMessage API|Winamp 2 API]]&lt;br /&gt;
*[[Media Library API|Media Library SendMessage API]]&lt;br /&gt;
*[[Plugin Terminology]]&lt;br /&gt;
&lt;br /&gt;
==Web Development Articles==&lt;br /&gt;
* [[HTTP Example Plugin]]&lt;br /&gt;
* [[Javascript External Interface]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Tagz_API</id>
		<title>Tagz API</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Tagz_API"/>
				<updated>2008-09-25T13:13:33Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Tagz API&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Tagz is the title formatting engine that powers the playlist titles.  (See Winamp preferences-&amp;gt;Titles-&amp;gt;Advanced Title Formatting for more information).  You can use this title formatting engine for your plugin's needs, optionally providing your own metadata for %artist%, etc.  &lt;br /&gt;
&lt;br /&gt;
Note that although Winamp's Tagz engine and the Tagz engine in Foobar2000 both come from a common source, they have diverged significantly and are not compatible for anything but the simplest of formats.&lt;br /&gt;
&lt;br /&gt;
Interface: api_tagz&lt;br /&gt;
&lt;br /&gt;
Include file: tagz/api_tagz.h&lt;br /&gt;
&lt;br /&gt;
You can also use Tagz via [[SendMessage API|WM_WA_IPC]]:&lt;br /&gt;
&lt;br /&gt;
 #define IPC_FORMAT_TITLE 297&lt;br /&gt;
 #define IPC_FORMAT_TITLE_EXTENDED 298&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Subclassing</id>
		<title>Subclassing</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Subclassing"/>
				<updated>2008-09-25T13:13:28Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Subclassing&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Subclassing ==&lt;br /&gt;
&lt;br /&gt;
Subclassing is a technique common to Windows development.  It involves supplying your own window function for someone's window, and changing behavior by supplying your own logic for processing certain messages.&lt;br /&gt;
&lt;br /&gt;
Because your plugin is given Winamp's HWND during initialization, it is possible for your plugin to subclass Winamp's main window.  Since the [[SendMessageAPI|Send Message API]] is built by sending messages to the Winamp window, your plugin can do a great deal without even effecting the UI.  From simple notifications (e.g. Winamp sends msg=WM_WA_IPC, wParam=IPC_CB_MISC_TITLE, lParam=IPC_CB_MISC on song change) to radically altering behavior (e.g. Winamp checks the return value of msg=WM_WA_IPC, lParam=IPC_GET_NEXT_PLITEM to allow plugin's to override playlist playback order).&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Service_Manager_API</id>
		<title>Service Manager API</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Service_Manager_API"/>
				<updated>2008-09-25T13:13:23Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Service Manager API&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;api/service/api_service.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Random_API</id>
		<title>Random API</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Random_API"/>
				<updated>2008-09-25T13:13:12Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Random API&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Agave/Random/api_random.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Nullsoft_Database_Engine</id>
		<title>Nullsoft Database Engine</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Nullsoft_Database_Engine"/>
				<updated>2008-09-25T13:12:04Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Nullsoft Database Engine&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Nullsoft Database Engine powers the local media library, history, and the CD metadata database.  It is relative simple and has a small query language.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Snap_Points</id>
		<title>Modern Skin: Snap Points</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Snap_Points"/>
				<updated>2008-09-25T13:11:55Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Snap Points&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A snap point is a point that windows will snap on to. When you move that window close in proximity to that point, the window will &amp;quot;latch&amp;quot; on to that point. You can drag it out of that point later. Take a look at these two examples.&lt;br /&gt;
&lt;br /&gt;
==Boxor Example==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Snap point is a useful tool that adds more functionalities to your skin. Take a look at the Boxor example. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Snappoint boxor.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Default Player Example==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Snappoint default.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; Snap points defined along the Main Window&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Winamp3 mainpl.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; The Playlist Editor snaps to the Main Window when you move it close in proximity of the Main Window &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==XML Example==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lets take a look at the XML code to define a snappoint. To get two components to snap together when they're close, you need to define snappoints in their XML. The XML itself is simple. The important part is the id: components with the same snappoint id will snap together whereas components with different ids will not.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Snappoint xml1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Snappoint xml2.png]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Simple_Skin_Tutorial</id>
		<title>Modern Skin: Simple Skin Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Simple_Skin_Tutorial"/>
				<updated>2008-09-25T13:11:49Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Simple Skin Tutorial&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In the next section, we will show how to make a simple skin and teach you the basic modern skinning terminologies.&lt;br /&gt;
&lt;br /&gt;
Before you start, you will need these items.&lt;br /&gt;
&lt;br /&gt;
==Simple Tutorial Skin File==&lt;br /&gt;
&lt;br /&gt;
We're going to show you how to make a simaple skin like the one shown below.  Download the [http://media.winamp.com/5541/main/downloads/development/skinsmodern/SimpleTutorial.wal &amp;quot;Simple Tutorial Skin&amp;quot; example].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Simpleskin_blue.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you save the file, make sure that the type of the file is selected to &amp;quot;All Type&amp;quot; and NOT &amp;quot;Winzip&amp;quot; filetype. You should save the file into your skin subdirectory in your Winamp 5 directory. for most people, that path is &amp;quot;C:\Program Files\Winamp\Skins&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Simpletutsave.png]]&lt;br /&gt;
&lt;br /&gt;
==Text Editing Programs==&lt;br /&gt;
You can use any text editing program to write XML and MAKI script files.&lt;br /&gt;
&lt;br /&gt;
1) The plain Windows Notepad will do. It is under &amp;quot;Start Menu&amp;quot; =&amp;gt; &amp;quot;Programs =&amp;gt; &amp;quot;Accessories =&amp;gt; &amp;quot;Notepad&amp;quot;. Here's what it looks like.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Notepad.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) However, if you intend to do alot of coding rather a quick editing, we recommed you to use something like [http://www.editplus.com/ EditPlus]. EditPlus will automatically color your HTML and XML code. The coloring makes it easier for you to see your code and find missing closing tags. Here's what it looks like.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Editplus.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can select the type of coloring by going to &amp;quot;Document&amp;quot; menu =&amp;gt; &amp;quot;Change File Type...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Editplus_changetype.png]]&lt;br /&gt;
&lt;br /&gt;
==A Graphics program==&lt;br /&gt;
We recommend [http://www.adobe.com/ Adobe Photoshop] or [http://www.corel.com/servlet/Satellite/us/en/Product/1184951547051#tabview=tab0 Paintshop Pro]. Here're some [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=93803 graphic design tutorials] if you're new to graphics.&lt;br /&gt;
&lt;br /&gt;
[[Image:Adobe.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Psp.png]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Maki_Overview</id>
		<title>Modern Skin: Maki Overview</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Maki_Overview"/>
				<updated>2008-09-25T13:11:33Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Maki Overview&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What is Maki==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Maki is a user interface and event management scripting system and more. The primary purpose of Maki is to handle all of the user interface behavior. Maki is used to insert functionality in Winamp3. The inserted functionality can range from a new user interface behavior to an alarm clock to a seperate EQ control system. You must not forget that Maki is part of Wasabi, which is used to build Winamp3. It's therefor safe to assume that Wasabi based applications (other than Winamp3) support Maki also. Well, when there are others that is.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What does Maki mean?==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''M'''ake '''A''' '''K'''iller '''I'''nterface&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What can Maki do?==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Maki as a language can do pretty much everything most scripting languages do. It supports user functions, user classes. It also has a full fledged pre-processor that allows you to include other Maki source files. Maki scripts are actually compiled using the Maki Compiler (MC.EXE, look for it in your Winamp3 directory. Don't worry about the compiler, we'll explain how it works later on).&lt;br /&gt;
&lt;br /&gt;
So here's a list of what Maki can do, just remember, it might change, but always in a good way, at least, we hope so.&lt;br /&gt;
&lt;br /&gt;
*Trap and hook events (onClick() do something...)&lt;br /&gt;
*Move user interface elements (take button A and move it to position x,y)&lt;br /&gt;
*Move and change images (button A has image A, set button A's image to image B)&lt;br /&gt;
*Show and Hide Windows.&lt;br /&gt;
*Control Winamp3 playback (play, stop, next, etc.)&lt;br /&gt;
*Control Winamp3 volume (set the volume to 100%)&lt;br /&gt;
*Control Winamp3 equalizer levels (set 60hz to +20db, for you bass addicts.)&lt;br /&gt;
*Make an Alarm&lt;br /&gt;
*Make a Clock&lt;br /&gt;
*etc.&lt;br /&gt;
&lt;br /&gt;
Now, you might not realise it, but the fact it can trap events and hook events and create new GUI objects on the fly means it can pretty much do anything. Something very important to remember is that some GUI objects need to be &amp;quot;binded&amp;quot; before being able to be used to trap events. The best way to go about this is to remember that objects need to be binded before being used. Here's a short example: &lt;br /&gt;
&lt;br /&gt;
 Global Timer myTimer;&lt;br /&gt;
 System.onScriptLoaded() {&lt;br /&gt;
 myTimer = new Timer;&lt;br /&gt;
 }&lt;br /&gt;
 myTimer.onTimer() {&lt;br /&gt;
 //Do cool stuff here.&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==When should I use Maki?==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 It's always hard to decide if you want to implement something via scripting or component. Always remember that many things can be done with Maki and that implementing something via scripting is also much faster than using a component. This is super true when it comes to user interface behavior in skins. Literaly ANYTHING that has to do with how the user interface (skin) behaves and changes because of user input is pretty darn quick to write in scripting, but you can still do it in a component if you wish.&lt;br /&gt;
&lt;br /&gt;
Mainly, you have to look at the potential level of complexity of what you're trying to do. You don't want to implement something very complex in script because it will definitely be slower than straight C++ code. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Maki Syntax==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Here's where the fun ends for me and I have to start being all serious and actually explain important stuff. Ugh. So, first I'm going to explain general syntax, like what constitutes an instruction, how you terminate lines, etc. Then we'll jump into variables, functions, classes and class members. Here we gooooooooo!&lt;br /&gt;
&lt;br /&gt;
First off, Maki is NOT case sensitive, so a function named llama can also be called by using Llama. I'd also like to point out the difference between pre-processor statements and actual code statement. Pre-processor statements are read and processed FIRST, before even ONE shred of code is actually compiled. They start with # and end with a carriage return. Actual code starts pretty much with anything but # and ends with a ;. This excludes flow control statements (like if(..) {... ). Now I know it's a bit odd to just read things and not see it, so, how about a little example? *nod*&lt;br /&gt;
&lt;br /&gt;
First, pre-processor statements:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;../../lib/std.mi&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #define ACTIVEALPHA   (230)&lt;br /&gt;
 #define INACTIVEALPHA (150)&lt;br /&gt;
&lt;br /&gt;
The pre-processor statements are pretty self explainatory. I'll explain what they actually mean really soon, just observe the syntax for now.&lt;br /&gt;
&lt;br /&gt;
Now, a code snippet:&lt;br /&gt;
&lt;br /&gt;
 if (isactive != prev_active) {&lt;br /&gt;
 prev_active = isactive;&lt;br /&gt;
 fader.start();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Since if is a control statement and marks the beginning of a code block ( a code block is something in between { .. } ), it doesn't require a ;, the line below it however, isn't a control statement and requires the line to end with a ;. Again, I will explain what everything means later, for now, just observe the syntax.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Maki Datatypes==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 In this section, we'll go thru all the different datatypes available in Maki and how to use them (And also, a quick overview of what exactly is a variable in Maki). Currently in Maki there are 6 basic types you can use:&lt;br /&gt;
&lt;br /&gt;
*Boolean&lt;br /&gt;
*Int&lt;br /&gt;
*Float&lt;br /&gt;
*Double&lt;br /&gt;
*String&lt;br /&gt;
*Object&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; Object is a compound type, we'll see what it means later.&lt;br /&gt;
&lt;br /&gt;
Now for a description of each of the types. Please note that the variable types aren't case sensitive.&lt;br /&gt;
&lt;br /&gt;
===Boolean===&lt;br /&gt;
&lt;br /&gt;
Boolean is a boolean value that can have two states. For us, these states are true (1) and false (0). Here's how you create a Boolean variable and assign a value to it:&lt;br /&gt;
&lt;br /&gt;
 //Create a bool type variable and assign 0 (false) to it.&lt;br /&gt;
 Boolean state = 0;&lt;br /&gt;
&lt;br /&gt;
 //Assign 1 (true) to our bool variable named state.&lt;br /&gt;
 state = 1;&lt;br /&gt;
&lt;br /&gt;
 //Assign false (0) to our bool variable named state.&lt;br /&gt;
 state = false;&lt;br /&gt;
&lt;br /&gt;
 //Assign true (1) to our bool variable named state.&lt;br /&gt;
 state = true;&lt;br /&gt;
&lt;br /&gt;
===Int===&lt;br /&gt;
&lt;br /&gt;
Int is a signed* round integer value from -2 147 483 647 to +2 147 483 648 (this means no decimal values, ever). Here's how you create an Int variable and assign a value to it:&lt;br /&gt;
&lt;br /&gt;
 //Create an int type variable and assign 255 to it.&lt;br /&gt;
 Int alpha = 255;&lt;br /&gt;
&lt;br /&gt;
 //Assign the value 1000 to our int variable named alpha.&lt;br /&gt;
 alpha = 1000;&lt;br /&gt;
&lt;br /&gt;
 //Assign the value -1000 to our int variable named alpha.&lt;br /&gt;
 alpha = -1000;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Float===&lt;br /&gt;
&lt;br /&gt;
Float is a signed floating point number. Here's how you create a Float variable and assign a value to it:&lt;br /&gt;
&lt;br /&gt;
 //Create a float type variable and assign 0.25 to it.&lt;br /&gt;
 Float fraction = 0.25;&lt;br /&gt;
&lt;br /&gt;
 //Assign the value 0.5 to our float variable named fraction.&lt;br /&gt;
 fraction = 0.5;&lt;br /&gt;
&lt;br /&gt;
 //Assign the value -3.5566 to our float variable named fraction.&lt;br /&gt;
 fraction = -3.5566;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Double===&lt;br /&gt;
&lt;br /&gt;
Double is a signed floating point number with double precision.&lt;br /&gt;
&lt;br /&gt;
 //Create a float type variable and assign 0.000000125 to it.&lt;br /&gt;
 Double fraction = 0.000000125;&lt;br /&gt;
&lt;br /&gt;
 //Assign the value 0.5 to our double variable named fraction.&lt;br /&gt;
 fraction = 0.5;&lt;br /&gt;
&lt;br /&gt;
 //Assign the value -3.5566 to our double variable named fraction.&lt;br /&gt;
 fraction = -3.5566;&lt;br /&gt;
&lt;br /&gt;
===String===&lt;br /&gt;
&lt;br /&gt;
String is a string, it can be of any length. Here's how you create a String variable and assign a value to it:&lt;br /&gt;
&lt;br /&gt;
 //Create a string type variable and assign a sentence to it.&lt;br /&gt;
 String name = &amp;quot;My real name is not Aus.&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
 //Assign the value &amp;quot;Guru&amp;quot; to our string variable named name.&lt;br /&gt;
 name = &amp;quot;Guru&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
 //Assign the value &amp;quot;Francis&amp;quot; to our string variable named name.&lt;br /&gt;
 name = &amp;quot;Francis&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
===Object===&lt;br /&gt;
&lt;br /&gt;
Object is a compound type. This means it can have more than just one value associated with it. Infact, you can even attach values to it, and even other objects.&lt;br /&gt;
&lt;br /&gt;
===Null===&lt;br /&gt;
&lt;br /&gt;
Null is a special case. You can't create a variable of this type, it is ONLY used in comparaisons and can compare to any type variable and object. You can use it to see if a variable contains something or exists.&lt;br /&gt;
&lt;br /&gt;
==Maki Operators==&lt;br /&gt;
&lt;br /&gt;
===Mathematical===&lt;br /&gt;
&lt;br /&gt;
All basic math operators are available, here's a list of them and what they do.&lt;br /&gt;
&lt;br /&gt;
[[Image:Table1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Logical===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Table2.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Bit===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Table1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Assignment===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Table1.png]]&lt;br /&gt;
&lt;br /&gt;
==Maki Control Structures==&lt;br /&gt;
&lt;br /&gt;
Control structures are what influence the flow of the code, certain parts are executed only in certain cases, some a fixed amount of times, some a variable amount of times, etc. Most of the basic control structures found in modern languages are available in Maki. Here's a list of them:&lt;br /&gt;
&lt;br /&gt;
===if===&lt;br /&gt;
&lt;br /&gt;
 if(state == true) {&lt;br /&gt;
 	state = false;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===if else===&lt;br /&gt;
&lt;br /&gt;
 if(state == true) {&lt;br /&gt;
 	state = false;&lt;br /&gt;
 } else {&lt;br /&gt;
 state = true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===while loop===&lt;br /&gt;
&lt;br /&gt;
 while(state == true) {&lt;br /&gt;
 ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===do while loop===&lt;br /&gt;
&lt;br /&gt;
 do {&lt;br /&gt;
 	...&lt;br /&gt;
 } while(state == true);&lt;br /&gt;
&lt;br /&gt;
===for loop===&lt;br /&gt;
&lt;br /&gt;
 for(int i = 0; i &amp;lt; 10; i++) {&lt;br /&gt;
 	...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Maki Functions==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===How do I create my own Maki functions===&lt;br /&gt;
&lt;br /&gt;
Functions in Maki need to be declared before they can be used (you can declare and define it if you want also). When declaring a function you need to use the proper prototype line for the function you wish to create. This includes the return value type and the parameters it takes.&lt;br /&gt;
&lt;br /&gt;
There are two ways you can go about creating functions.&lt;br /&gt;
&lt;br /&gt;
1) You can group all your function declarations (called prototypes) at the top of your script and then define (write the actual code associated with the functions) them anywhere in the file. Like so:&lt;br /&gt;
&lt;br /&gt;
 #include &lt;br /&gt;
 &lt;br /&gt;
 Function Boolean CheckLevel(int Threshold);&lt;br /&gt;
 Function Int CheckPlaystring(String _Playstring);&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 Boolean CheckLevel(int Threshold) {&lt;br /&gt;
 ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Int CheckPlaystring(String _Playstring) {&lt;br /&gt;
 ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
2) You can declare the function just before defining it. Like so:&lt;br /&gt;
&lt;br /&gt;
 #include &lt;br /&gt;
 ...&lt;br /&gt;
 Function Boolean CheckLevel(int Threshold);&lt;br /&gt;
 Boolean CheckLevel(int Threshold) {&lt;br /&gt;
 ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The preferred method is the first because it's just much easier to organize things, but, you can do it the other way if you want to.&lt;br /&gt;
&lt;br /&gt;
===How to read function prototypes===&lt;br /&gt;
&lt;br /&gt;
Function RETURN_VALUE_TYPE FUNCTION_NAME(PARAM_TYPE PARAM_NAME, ...);&lt;br /&gt;
&lt;br /&gt;
*RETURN_VALUE_TYPE is the type of the return value, it can be any type supported by Maki, including user classes.&lt;br /&gt;
*FUNCTION_NAME is the name of the function you are declaring. It can be any combination of letters and numbers but it MUST start with a letter.&lt;br /&gt;
*PARAM_TYPE is the type of the parameter you will be passing to the function, it can be any type supported by Maki, including user classes.&lt;br /&gt;
*PARAM_NAME is the name the parameter will have inside the function, it can be any combination of letters and numbers but it MUST start with a letter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The function's name and parameter names CAN NOT use any of the existing Maki keywords.&lt;br /&gt;
&lt;br /&gt;
==Maki Classes==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The already existing Maki classes usually consist of two things: member data and methods. It's very important to remember that user classes do not support methods yet. (needs improvement)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Maki User Classes==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(needs improvement)&lt;br /&gt;
&lt;br /&gt;
==Gerneral Scripting Rules==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These are just general things you want to keep in mind when writing Maki scripts and when writing code in general too! :)&lt;br /&gt;
&lt;br /&gt;
*As a rule of thumb, all uppercase is reserved for constants. So please avoid naming anything that's not a constant all in uppercase.&lt;br /&gt;
&lt;br /&gt;
==STD.MI Reference==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you'd like to know more about STD.MI simply open it in your favorite text editor and check out the spiffy comments. If you need more help, [http://forums.winamp.com/ check out the forums!]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Group</id>
		<title>Modern Skin: Group</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Group"/>
				<updated>2008-09-25T13:11:25Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Group&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What is a Group?==&lt;br /&gt;
&lt;br /&gt;
A group is a set of objects that can be referred to and manipulated as a whole. First must defined by a &amp;lt;groupdef&amp;gt; tag, then located with a &amp;lt;group&amp;gt; tag. Group is an important concept to understand because a group is such a versatile object.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Simple Tutorial: Using groups==&lt;br /&gt;
&lt;br /&gt;
Let's go back to our &amp;quot;Simple Tutorial&amp;quot; example. As you recall, we have two groups defined: &amp;quot;player.normal.playbuttons&amp;quot; and &amp;quot;play.normal&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Simpleskin_diag.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Let's take a look at the code: (player.xml)&lt;br /&gt;
&lt;br /&gt;
[[Image:Playerxmlcode6.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we change line 113 and 114: change the x and y coordinates of the group objects, their positions are reversed. This is a simple change and much more convinient than changing the position of each element independently.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Simpleskin_reversedxml.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Simpleskin_reversed.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Simple Tutorial: Playback Buttons Group Definition==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:playerxmlcode4.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:playbackgroup.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On lines 19-64 you'll see our group definition of the playback buttons. This section contains only the definition of the group or, in another words, it defines which objects are in the group. Once the group is defined, you can use it later as we will see later. Let's go over the elements inside the group.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:playbackexpl.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Simple Tutorial: Song File Info &amp;amp; Visualization Group Definition==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:playerxmlcode5.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SongInfo group is another group definition just like the Playback Buttons group. As you can see that the elements defined inside this group is different from the previous one. In this example, we're using elements other than buttons. We're using the layer to set the background color of two areas. A layer is basically an image. Layers can overlay on top of each other. It is similar to a layer in Adobe Photoshop. &amp;quot;Songinfo&amp;quot; and &amp;quot;infoline&amp;quot; are text objects displaying information stored within Winamp3 runtime variables.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:songinfogroup.png]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Container</id>
		<title>Modern Skin: Container</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Container"/>
				<updated>2008-09-25T13:11:19Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Container&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What's a Container?==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A container is a top level object and it basically represents a window. Nothing holds a container. It is an object that holds multiple related layouts. Each layout represents an appearance for that window. You can design different layouts for each window but only one can be visible at a time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Container_xml.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What's a Layout?==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A layout is a special kind of group, which shown inside a container. Each layout represents an appearance for that window. Layouts give you the ability to design differnt looks for the same container (or window). However, only one layout can be visible at a time. You must toggle among layouts you defined. An example is the normal mode and windowshade mode in the Default skin.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Winamp_normal.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; ''The top image is using normal layout and the bottom is using the windowshade layout.''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lets look at the Simple Tutorial xml code for layout:&lt;br /&gt;
&lt;br /&gt;
[[Image:Layout_xml.png]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Animatedlayer</id>
		<title>Modern Skin: Animatedlayer</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Animatedlayer"/>
				<updated>2008-09-25T13:11:13Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Animatedlayer&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
An animated layer is a layer that displays a series of graphics by cycling through parts of a graphics file. A simple example is the rotating arrow that you see below.&lt;br /&gt;
&lt;br /&gt;
An animated layer does not move. However, an animating skin does move. To move a graphical element in animating layer, you must write a MAKI script. Scripting is covered in the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Flash2.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Complex Tutorial Modern Skin'''&lt;br /&gt;
&lt;br /&gt;
In Complex Tutorial, Group #4 shows a spinning arrow inside a yellow circle. This is done through Animated Layer. Here's the process.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lets go through in detail how do to each step:&lt;br /&gt;
*Make the graphics: rotating arrow&lt;br /&gt;
*Define the elements in the XML code.&lt;br /&gt;
*Define layers using those elements.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Make the Graphics: Rotating Arrow==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you make the graphics for this layer, make the graphics for each frame separately. Then put the frames together vertically in a single file as shown below. This example has a short animation. If you plan to show more complicated animation, make more frames.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Animlayer graphics.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; yellowcircle-arrow.png&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Define the Elements in the XML Code==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The definition for the element is the same as any bitmap definition. The thing that is different is the next step.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Animlayer xml1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Define Layers Using those Elements==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Take a look at line 70. The width and height tells Winamp3 how big each frame is. It will cycle through each frame automatically.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Animlayer xml2.png]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/MilkDrop_Unleashed_Guide</id>
		<title>MilkDrop Unleashed Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/MilkDrop_Unleashed_Guide"/>
				<updated>2008-09-25T13:11:08Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;MilkDrop Unleashed Guide&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
===Installation===&lt;br /&gt;
MilkDrop 2 comes with Winamp.  To install it, just download and install the latest version of Winamp.  During the installation, make sure the &amp;quot;MilkDrop&amp;quot; visualizer option is checked, so that it gets installed, too.  &lt;br /&gt;
&lt;br /&gt;
Once Winamp is installed, launch it.  Load some music files into your playlist and start playing some music.  (Be sure to play some music before trying to launch the visualizer - otherwise you'll just see a black screen.)&lt;br /&gt;
&lt;br /&gt;
Once music is playing, hit CTRL+K and a list of visualization plug-ins will appear.  Select &amp;quot;MilkDrop 2&amp;quot; from the list.  Then click the &amp;quot;Start&amp;quot; button, and it will launch the visualizer.  &lt;br /&gt;
&lt;br /&gt;
    Quick Tips:    &lt;br /&gt;
      * If you want to go full-screen, double-click on the visualizer itself.&lt;br /&gt;
      * CTRL+SHIFT+K starts or stops the visualizer.&lt;br /&gt;
      * To configure MilkDrop's options, exit the visualizer and hit ALT+K.&lt;br /&gt;
    &lt;br /&gt;
    If you have trouble getting MilkDrop to run properly after installation, &lt;br /&gt;
    try installing various recent WHQL drivers for your video card, or installing &lt;br /&gt;
    DirectX; doing these two things (especially the first) will fix 99% of&lt;br /&gt;
    problems. See the Troubleshooting section of the documentation for more&lt;br /&gt;
    information.&lt;br /&gt;
&lt;br /&gt;
===Tweaking to achieve best image quality===&lt;br /&gt;
&lt;br /&gt;
a) Fullscreen Display Mode   [first tab of config screen]&lt;br /&gt;
&lt;br /&gt;
When you run MilkDrop fullscreen, it changes the display mode to whatever you select here.  Generally speaking, the speed (framerate) and smoothness of MilkDrop will drop as the resolution (number of pixels on the screen)increases.  So, if it's running to slow in fullscreen mode, try selecting a smaller fullscreen display mode. &lt;br /&gt;
        &lt;br /&gt;
b) Canvas Stretch  [second tab]&lt;br /&gt;
&lt;br /&gt;
This option lets you trade resolution [crispness] for speed.  If MilkDrop runs too slow, in any mode (windowed/fullscreen/desktop), try cranking up the canvas stretch to, say, 1.5X or 2X.  The image will not look as crisp, but MilkDrop will probably run much faster.  (Assuming that your graphics chip was the bottleneck.)&lt;br /&gt;
&lt;br /&gt;
c) Mesh Size  [second tab]&lt;br /&gt;
&lt;br /&gt;
This is the main option that affects how much processor (CPU) MilkDrop uses.  If you crank it up far beyond the default, expect to be CPU-bound (where your framerate drops because the CPU is the bottleneck).  To get MilkDrop to speed up, drop the Mesh Size back down.  The Mesh Size decides how many points on the screen the per-vertex equations will be executed for; the higher the mesh size, the more fidelity you will see in the motion.  &lt;br /&gt;
        &lt;br /&gt;
d) Tips for LCD and laptop users&lt;br /&gt;
&lt;br /&gt;
LCD screens: Note that most LCD screens (flatpanels) usually run at a fixed frequency only - usually 60 Hz - 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.&lt;br /&gt;
&lt;br /&gt;
e) color (bit) depth: 16 or 32?&lt;br /&gt;
&lt;br /&gt;
The answer, nowadays, is a resounding &amp;quot;32&amp;quot;.  Video memory is plentiful these days; use 32 bit color, for both your windows desktop (...so that MilkDrop's windowed mode can run at 32 bits) and for MilkDrop's Fullscreen Display Mode setting (where &amp;quot;8888&amp;quot; denotes 32 bits). Some ancient video cards don't have enough memory to run MilkDrop properly (or smoothly) in 32 bits, though; you might want to try 16-bit color if your card has less than 32 MB of video memory, if you are using a laptop, or if your video card is significantly old.  In the MilkDrop config panel, 16-bit modes show up as &amp;quot;555&amp;quot; or &amp;quot;565&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you find that your card runs best in 32-bit color, you should have no problems with brightness levels while running MilkDrop. However, if your card runs best in 16-bit color, you should then adjust the Brightness slider on the second tab of the config panel (which only affects 16-bit color video modes!).  The goal is to make the image as bright as possible, without oversaturating it (washing it out, often to bright pink or white).  This setting also varies for different cards, depending on how the card rounds color values, so we recommend seeing how bright you can set the slider closer to '0') without oversaturating the image.  Usually,a setting of '0' or '2' works the best.&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
'''4.a. Keyboard Commands'''&lt;br /&gt;
    &lt;br /&gt;
The following keys can be used to control MilkDrop while it is running.&lt;br /&gt;
(Note: pressing F1 while MilkDrop is running will show you this list)&lt;br /&gt;
          &lt;br /&gt;
GENERAL&lt;br /&gt;
escape: exit to winamp&lt;br /&gt;
PRESET LOADING&lt;br /&gt;
BACKSPACE: return to previous preset&lt;br /&gt;
SPACE: transition to next preset&lt;br /&gt;
H: instant Hard cut (to next preset)&lt;br /&gt;
R: toggle random (vs. sequential) preset traversal&lt;br /&gt;
L: load a specific preset (invokes the 'Load' menu)&lt;br /&gt;
+/-: rate current preset (better/worse)&lt;br /&gt;
scroll lock: lock/unlock current preset &lt;br /&gt;
(keyboard light on means preset is locked)&lt;br /&gt;
(prevents random switch to new preset)&lt;br /&gt;
A: aggregate preset - loads a random preset,&lt;br /&gt;
steals the warp shader from a different random preset,&lt;br /&gt;
and steals the composite shader from a third random preset.&lt;br /&gt;
D: cycle between various lock-states for the warp and&lt;br /&gt;
composite shaders.  When one of these shaders is locked,&lt;br /&gt;
loading a new preset will load everything *except* the&lt;br /&gt;
locked shaders, creating a mix between the two presets.&lt;br /&gt;
&lt;br /&gt;
PRESET EDITING AND SAVING&lt;br /&gt;
M: show/hide the preset-editing menu&lt;br /&gt;
S: save new preset (asks you for the new filename)&lt;br /&gt;
N: show per-frame variable moNitor&lt;br /&gt;
(see [[MilkDrop Preset Authoring]])&lt;br /&gt;
&lt;br /&gt;
MUSIC PLAYBACK&lt;br /&gt;
z/x/c/v/b: navigate playlist (prev/play/pause/stop/next)&lt;br /&gt;
U: toggle shuffle&lt;br /&gt;
P: show playlist&lt;br /&gt;
up/down arrows: volume up/down&lt;br /&gt;
left/right arrows: rewind/ffwd 5 seconds&lt;br /&gt;
SHIFT + left/right arrows: rewind/ffwd 30 seconds&lt;br /&gt;
&lt;br /&gt;
FUNCTION KEYS                                &lt;br /&gt;
F1: show help screen&lt;br /&gt;
F2: show song title&lt;br /&gt;
F3: show song length&lt;br /&gt;
F4: show preset name&lt;br /&gt;
F5: show fps (frames per second)&lt;br /&gt;
F6: show rating of current preset&lt;br /&gt;
F7: re-read custom message file (milk_msg.ini) from disk&lt;br /&gt;
F8: jump to new directory (for presets)&lt;br /&gt;
F9: toggle stereo 3D on/off&lt;br /&gt;
&lt;br /&gt;
SPRITES AND CUSTOM MESSAGES (FOR VJ's)&lt;br /&gt;
T: launch song title animation&lt;br /&gt;
 Y: enter custom message mode&lt;br /&gt;
 ##: load message ## (where ## is a 2-digit numeric code (00-99) &lt;br /&gt;
 of a message defined in milk_msg.ini)&lt;br /&gt;
 *: clear any digits entered.&lt;br /&gt;
DELETE: clear message (if visible)&lt;br /&gt;
F7: re-read milk_msg.ini from disk&lt;br /&gt;
 K: enter sprite mode&lt;br /&gt;
 ##: load sprite ## (where ## is a 2-digit numeric code (00-99) &lt;br /&gt;
 of a sprite defined in milk_img.ini)&lt;br /&gt;
 *: clear any digits entered.&lt;br /&gt;
DELETE: clear newest sprite &lt;br /&gt;
SHIFT + DELETE: clear oldest sprite&lt;br /&gt;
CTRL+SHIFT+DELETE: clear all sprites&lt;br /&gt;
F7: no effect (milk_img.ini is never cached)&lt;br /&gt;
 SHIFT + K: enter sprite kill mode&lt;br /&gt;
 ##: clear all sprites with code ##&lt;br /&gt;
 *: clear any digits entered.&lt;br /&gt;
CTRL + T/Y: kill song title and/or any custom messages&lt;br /&gt;
CTRL + K: kill all sprites&lt;br /&gt;
            &lt;br /&gt;
Note that there are more keys available, but because many&lt;br /&gt;
are only relevant to people designing their own presets, &lt;br /&gt;
they are listed in the preset authoring guide instead.&lt;br /&gt;
    &lt;br /&gt;
'''4.b. config panel'''&lt;br /&gt;
 &lt;br /&gt;
The configuration panel lets you customize the way MilkDrop runs.&lt;br /&gt;
To learn how to get to the configuration panel, see the &amp;quot;Installation&amp;quot;&lt;br /&gt;
section above.&lt;br /&gt;
        &lt;br /&gt;
Once you're in the config panel, you'll see a number of tabs&lt;br /&gt;
at the top, some dropdown boxes, and some checkboxes.  Each&lt;br /&gt;
of the tabs at the top brings you to a different page of &lt;br /&gt;
configuration options.  To get help on a setting, simply click&lt;br /&gt;
on the '?' in the upper-right corner of the config panel, &lt;br /&gt;
and then click on the setting you want help with.&lt;br /&gt;
&lt;br /&gt;
'''4.c. preset authoring'''&lt;br /&gt;
    &lt;br /&gt;
Please check the [[MilkDrop Preset Authoring]] guide for instructions on how to create and save your own presets.&lt;br /&gt;
&lt;br /&gt;
'''4.d. rating system'''&lt;br /&gt;
&lt;br /&gt;
The built-in rating system allows you to rate each preset on a scale &lt;br /&gt;
from 0 to 5.  A rating of 5 is very good, while a rating of 0 is&lt;br /&gt;
the worst.  The ratings decide how often the presets will be randomly&lt;br /&gt;
loaded.  If a preset has a rating of 0, it will never be randomly&lt;br /&gt;
loaded (unless they're all zero; then they all have an equal chance).&lt;br /&gt;
        &lt;br /&gt;
To show the rating for a preset, press F6.  You can adjust the &lt;br /&gt;
rating for a preset with the +/- keys.  When you make adjustments,&lt;br /&gt;
they save automatically; there's no need to save the preset to make&lt;br /&gt;
the rating change permanent.&lt;br /&gt;
        &lt;br /&gt;
Here's a recommended interpretation of the numeric values:&lt;br /&gt;
            0 = I never want to see this preset again&lt;br /&gt;
            1 = very ugly&lt;br /&gt;
            2 = mediocre&lt;br /&gt;
            3 = fair&lt;br /&gt;
            4 = good&lt;br /&gt;
            5 = downright stimulating&lt;br /&gt;
            &lt;br /&gt;
If a preset seems &amp;quot;lost&amp;quot; because you set its rating to 0 and it&lt;br /&gt;
won't ever come back, you can always load it up by hitting 'L'&lt;br /&gt;
to conjure the 'Load Preset' menu, finding the preset you want,&lt;br /&gt;
loading it, then hitting +.&lt;br /&gt;
&lt;br /&gt;
'''4.e. custom messages'''&lt;br /&gt;
&lt;br /&gt;
ABOUT CUSTOM MESSAGES:&lt;br /&gt;
The &amp;quot;Custom Message&amp;quot; feature of MilkDrop allows you to display&lt;br /&gt;
short text messages on the screen while MilkDrop is running.&lt;br /&gt;
They are highly configurable; you can set all of the following&lt;br /&gt;
parameters: the font, the size, the positioning, color, bold &lt;br /&gt;
state, italic state, and so on; and you can even have it &lt;br /&gt;
randomize some of these properties.&lt;br /&gt;
&lt;br /&gt;
CREATING THE MESSAGES:&lt;br /&gt;
You can save up to 100 messages in the file MILK_MSG.INI in&lt;br /&gt;
your Winamp\Plugins\ folder.  To open this file, go to the &lt;br /&gt;
MilkDrop configuration screen (ALT+K from Winamp) and click the&lt;br /&gt;
&amp;quot;Edit Custom Messages&amp;quot; button.  Or, you can just edit it &lt;br /&gt;
manually if you know how; it's plain-text.&lt;br /&gt;
            &lt;br /&gt;
The first thing you see when you open the file is a bunch of&lt;br /&gt;
lines that start with two forward slashes (//).  These are&lt;br /&gt;
comment lines, and they explain the syntax for adding a font&lt;br /&gt;
or a message to the file.  This is your main reference for&lt;br /&gt;
finding out what all the parameters do for the fonts &amp;amp; messages;&lt;br /&gt;
it is recommended that you leave this information in the file,&lt;br /&gt;
although it can be removed or (modified) and the messages will&lt;br /&gt;
still work.&lt;br /&gt;
&lt;br /&gt;
After the comments come first the fonts, then the messages.&lt;br /&gt;
The fonts are simply a way to specify a typeface, bold state,&lt;br /&gt;
italics state, and red/green/blue color for the font.  You can &lt;br /&gt;
configure up to 16 fonts like this (numbered 00-15). These fonts&lt;br /&gt;
will serve as template fonts for the custom messages.&lt;br /&gt;
&lt;br /&gt;
The next section is the actual messages.  Each one has a&lt;br /&gt;
text message (the 'text' parameter) that will be shown to the&lt;br /&gt;
user, and each one references one of the 16 fonts that were&lt;br /&gt;
defined in the previous section.  You can also specify the&lt;br /&gt;
size (size), position (x,y), a growth factor (growth) that&lt;br /&gt;
will grow/shrink the message over its lifetime, the number&lt;br /&gt;
of seconds to show the message (time), and the fraction of that&lt;br /&gt;
time that is spent fading in (fade).  &lt;br /&gt;
&lt;br /&gt;
You can also randomize some of these values: 'randx' and 'randy'&lt;br /&gt;
will randomly perturb the (x,y) coordinates every time the message&lt;br /&gt;
is shown to the user, and 'randr'/'randg'/'randb' will randomly&lt;br /&gt;
perturb the (r,g,b) color in the same way.&lt;br /&gt;
&lt;br /&gt;
Finally, you can override any of the default properties for the&lt;br /&gt;
font that this message uses: (face, bold, ital, r, g, b).&lt;br /&gt;
&lt;br /&gt;
INVOCATION AND USAGE:&lt;br /&gt;
There are two ways to invoke custom messages: one automatic,&lt;br /&gt;
the other manual.  &lt;br /&gt;
&lt;br /&gt;
The automatic way is to go to the MilkDrop config panel (ALT+K),&lt;br /&gt;
click the 'More Options' button, and set the value in the&lt;br /&gt;
'Time between RANDOM custom messages' box to something greater&lt;br /&gt;
than zero.  This will cause MilkDrop to randomly display custom &lt;br /&gt;
messages while it is running, and the average time (in seconds) &lt;br /&gt;
between messages will be the value you entered here.  If you &lt;br /&gt;
wish to disable random custom messages, set this value to -1&lt;br /&gt;
(or any negative number).  Note that all messages in the file&lt;br /&gt;
have an equal change of being picked.&lt;br /&gt;
&lt;br /&gt;
The manual way is to type in the two-digit code (00-99) of the &lt;br /&gt;
message while MilkDrop is running.  However, you can't use the &lt;br /&gt;
numeric keypad for this - you have to use the numbers at the &lt;br /&gt;
TOP of your keyboard to do it.  If you mess up while entering&lt;br /&gt;
the first digit, just press the '*' key to start over.&lt;br /&gt;
            &lt;br /&gt;
Note that if you change the MILK_MSG.INI file while MilkDrop&lt;br /&gt;
is running, you will not be able to see the changes until&lt;br /&gt;
you hit F7, which tells MilkDrop to re-read the MILK_MSG.INI &lt;br /&gt;
file from disk.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.f. sprites'''&lt;br /&gt;
&lt;br /&gt;
ABOUT SPRITES:&lt;br /&gt;
The &amp;quot;Sprite&amp;quot; feature of MilkDrop allows you to display any image of your choice in the foreground (on top of MilkDrop) while it runs.  The sprites can fade in and out, move around, respond to the music, and so on.  You define them in a file - milk_img.ini in your winamp\plugins directory - much like you define custom messages, each having an identifying code number from 00 through 99 (used to invoke them).  However, the way the individual sprites are defined is different; you write code for them, instead of just setting parameter values.  This is a little bit tougher to do (it's very much like preset authoring), but adds a great deal of flexibility to what you can do with the sprites.&lt;br /&gt;
&lt;br /&gt;
CREATING THE SPRITES:&lt;br /&gt;
            &lt;br /&gt;
You can define up to 100 sprites in the file MILK_IMG.INI in your Winamp\Plugins\ folder.  To open this file, go to the MilkDrop configuration screen (ALT+K from Winamp) and click the &amp;quot;Edit Sprites&amp;quot; button.  Or, you can just edit it manually if you know how; it's plain-text.&lt;br /&gt;
            &lt;br /&gt;
The first thing you see when you open the file is a bunch of lines that start with two forward slashes (//).  These are comment lines, and they explain the syntax for creating a sprite. This is your main reference for finding out what all the parameters do for the fonts &amp;amp; messages; it is recommended that you leave this information in the file, although it can be removed (or modified) and the sprites will still work.&lt;br /&gt;
&lt;br /&gt;
After the comments come the sprite definitions.  Each sprite is made up of one parameter that indicates the image file to use (this is the 'img=...' line), and two types of code: initialization code, and regular code.  &lt;br /&gt;
            &lt;br /&gt;
The first - initialization code - is executed only once, when you launch the sprite.  Use it to do one-time initialization of variables (such as the opacity (a), rotation angle (rot), position (x,y), and so on) or to invent new variables that you will access later. This code is marked by the 'init_1=...', 'init_2=...', etc. lines. The second type of code - marked by 'code_1=...', 'code_2=...', etc. is executed every frame, just prior to plastering the sprite on             the screen.  Use it to animate the sprite, moving it around (changing x,y), scaling it up and down (sx,sy), fading it in and out (a), changing its color, and so on.&lt;br /&gt;
            &lt;br /&gt;
            Please see the comments included in the sample milk_img.ini file&lt;br /&gt;
            for full details and examples on how to author sprites.&lt;br /&gt;
&lt;br /&gt;
INVOCATION AND USAGE:&lt;br /&gt;
There is currently only one way to invoke sprites: manually. To do this, first press 'K' to enter 'sprite mode' (while running MilkDrop).  Now, whenever you type in a two-digit             code (00-99), MilkDrop will try to find &amp;amp; launch the sprite you've requested, from the milk_img.ini file.  If there is an error, it will display an error message in the upper-right corner.  Note that to enter the two-digit code, you can't use the numeric keypad; you have to use the numbers at the TOP of  your keyboard.  &lt;br /&gt;
&lt;br /&gt;
If you make an error entering the first digit of the code, just press '*' to start over.  If you want to clear the most recently-invoked sprite, press DELETE.  If you want to clear the oldest sprite, press SHIFT + DELETE.  If you want to clear all sprites, press SHIFT + CTRL + DELETE.&lt;br /&gt;
&lt;br /&gt;
If you want to clear sprites by their 2-digit code, press SHIFT + K (instead of just 'K') to enter 'sprite kill mode.' Now, when you enter a two-digit code, instead of invoking the sprite, MilkDrop clears all running sprites with that two-digit code.&lt;br /&gt;
&lt;br /&gt;
===Trouble Shooting===&lt;br /&gt;
&lt;br /&gt;
If MilkDrop has a critical problem (e.g. fails to load, freezes, etc.)or if the image is distorted, torn, corrupted, or all one solid color, try the following two suggestions to resolve the problem.  In 90% of these cases it can be fixed.  If you have a different problem, scroll down past this part and try to find the appropriate symptom and its solution.&lt;br /&gt;
&lt;br /&gt;
====1. UPDATE YOUR VIDEO DRIVER, OR TRY OTHER DRIVERS====&lt;br /&gt;
    &lt;br /&gt;
Almost all display problems are caused by buggy video drivers! A &amp;quot;driver&amp;quot; is a piece of software that translates graphics-related commands from programs, like MilkDrop, into the native language of your specific graphics hardware.&lt;br /&gt;
&lt;br /&gt;
For desktop machines, there are typically three sources for video drivers: &lt;br /&gt;
# those from the *chip* manufacturer's website (usually nvidia.com or ati.com) (best source) &lt;br /&gt;
# those from the card manufacturer's website (LeadTEK, PNY, etc.)&lt;br /&gt;
# those that shipped with Windows (yuck)&lt;br /&gt;
        &lt;br /&gt;
For laptops:&lt;br /&gt;
# the driver from the *laptop* manufacturer&lt;br /&gt;
# (maybe) the driver from the graphics chip manufacturer (ATI, Nvidia, etc) - however, it's fairly common to find that the laptop requires a custom driver written by the laptop manufacturer.&lt;br /&gt;
# the driver that shipped with Windows (yuck)&lt;br /&gt;
&lt;br /&gt;
Give them all a shot.  Track down every driver you can find for your card, and try it.  Try the WHQL ones first - these versions of the drivers have passed &amp;quot;Windows Hardware Quality Labs&amp;quot; certification and are usually the more stable and reliable ones. In general, it's a very good idea to use only Microsoft-certified WHQL 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.  You can also watch the version number of the drivers a company releases - if the version number just jumped to a new series such as from the 70's to the 80's), watch out, it probably has a lot of bugs that need worked out - give it 3-4 months before expecting the new driver series to work well.  With video drivers, the newest isn't always the best!&lt;br /&gt;
&lt;br /&gt;
Here is a list of some common card/chip manufacturers and where to get their drivers.  Don't forget to choose the WHQL driver!&lt;br /&gt;
&lt;br /&gt;
            [http://www.nvidia.com/page/drivers.html NVIDIA driver]&lt;br /&gt;
                Card manufacturers using NVIDIA (GeForce) graphics chips:&lt;br /&gt;
                (note - most of these just link you to the nvidia driver above)&lt;br /&gt;
                [http://www.xfxforce.com/web/support/showSearchDriversProductCode.jspa XFX]&lt;br /&gt;
                [http://www.evga.com/support/drivers EVGA]&lt;br /&gt;
                [http://www.bfgtech.com/driverdownload.aspx BFG]&lt;br /&gt;
                [http://www2.pny.com/support/support.aspx PNY]  &lt;br /&gt;
            [http://ati.amd.com/support/driver.html ATI driver] &lt;br /&gt;
                Card manufacturers using ATI (Radeon) graphics chips:&lt;br /&gt;
                [http://www.visiontek.com/teksupport/drivers/drivers.html VisionTek]              &lt;br /&gt;
                [http://www.dmmdownload.com/current.php Diamond]                &lt;br /&gt;
            [http://downloadcenter.intel.com Intel] - then click 'graphics' on the left&lt;br /&gt;
            [http://www.sis.com/download SiS] - agree, then select 'graphics drivers'&lt;br /&gt;
            [http://www.s3graphics.com S3] - then click 'drivers'&lt;br /&gt;
            [http://www.via.com.tw/en/products/graphics VIA]    &lt;br /&gt;
            [http://www.matrox.com/graphics/en/corpo/support/drivers/home.php Matrox]&lt;br /&gt;
            [http://www.creative.com/language.asp?sDestUrl=/support/downloads Creative Labs]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For others - or in general - if your graphics chip is made by Trident, for example, then try a [http://www.google.com/ google] search for:&lt;br /&gt;
        &lt;br /&gt;
                Trident graphics driver&lt;br /&gt;
                        &lt;br /&gt;
Then click on &amp;quot;support&amp;quot;, then &amp;quot;drivers&amp;quot; (or &amp;quot;downloads&amp;quot;), then &amp;quot;graphics driver&amp;quot;, and so on.&lt;br /&gt;
&lt;br /&gt;
====2. [RE]INSTALL DIRECTX====&lt;br /&gt;
    &lt;br /&gt;
Make sure you have a quasi-recent version of Microsoft DirectX installed.  In reality, though, almost every PC in the world has DirectX 9 on it at this point, so this shouldn't be a problem. If you go to download it, you'll only be able to find DirectX 10 - this is fine to install, though, as it includes DirectX 9 inside it.  As a last resort, though, if you are having problems, you could try re-installing DirectX to see if it helps.&lt;br /&gt;
&lt;br /&gt;
If you're having a non-critical problem, browse the following list of common problems and their causes and solutions.  Note that for each symptom- cause-solution block, there can be multiple symptoms with the same cause and solution, and the same symptom might be listed in multiple blocks.&lt;br /&gt;
&lt;br /&gt;
If the solutions below don't work for you, please visit the forums at http://forums.winamp.com/forumdisplay.php?forumid=84, where you can read the most recent troubleshooting issues and solutions.&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
    ENTRY 1&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        -any error message saying &amp;quot;Failed to create ...&amp;quot; &lt;br /&gt;
            or &amp;quot;not enough memory...&amp;quot;, or&lt;br /&gt;
        -only a portion of the screen displays correctly; the rest is &lt;br /&gt;
            either filled with garbage or badly flickering&lt;br /&gt;
    CAUSE:&lt;br /&gt;
        1) Your video card might not have enough memory to run MilkDrop at &lt;br /&gt;
        the resolution (screen width and height) you've picked, &lt;br /&gt;
        2) your drivers might be out of date, &lt;br /&gt;
        3) you might need to reinstall DirectX (very very rare), or&lt;br /&gt;
        4) your graphics card might be to crappy to *actually* run&lt;br /&gt;
             pixel shaders well.&lt;br /&gt;
    SOLUTION:    &lt;br /&gt;
        1) To battle video memory problems:&lt;br /&gt;
            &lt;br /&gt;
            Go to the config panel and try smaller video modes (e.g.,&lt;br /&gt;
            320x240 is smaller than 640x480).  Even better is to try&lt;br /&gt;
            a lower color bit depth; if you'd selected a 32-bit (&amp;quot;8888&amp;quot;) &lt;br /&gt;
            video mode before, try a 16- (&amp;quot;565&amp;quot; or &amp;quot;555&amp;quot;) or 24-bit (&amp;quot;888&amp;quot;) &lt;br /&gt;
            one, for example.  Note that it might only work in one of them; &lt;br /&gt;
            so make sure you try them all.  Trying these things is especially &lt;br /&gt;
            important on laptops with limited video memory, or older video &lt;br /&gt;
            cards with a small amount of video memory.&lt;br /&gt;
        &lt;br /&gt;
            Finally, you can try locking the texture size (or &amp;quot;canvas size&amp;quot;) &lt;br /&gt;
            to 256x256 pixels, just to see if that fixes the problem.  &lt;br /&gt;
            If it does, try using a smaller fullscreen video mode to&lt;br /&gt;
            free up some memory, or if running windowed, close other&lt;br /&gt;
            graphics-hungry applications.&lt;br /&gt;
        &lt;br /&gt;
        2,3) for instructions on how to reinstall DirectX or update &lt;br /&gt;
            drivers, go here.&lt;br /&gt;
            &lt;br /&gt;
        4) Go to the MilkDrop config panel (hit ALT+K) and on the second tab, &lt;br /&gt;
            in the &amp;quot;Pixel Shaders&amp;quot; box, select &amp;quot;None.&amp;quot;  Now does MilkDrop run &lt;br /&gt;
            ok?  If so, your video card probably just can't reliably run&lt;br /&gt;
            pixel shaders, due to either inferior hardware, or it could&lt;br /&gt;
            be the driver.  You can always try setting &amp;quot;Pixel Shaders&amp;quot; &lt;br /&gt;
            back to &amp;quot;Auto&amp;quot; and then installing a newer (preferably WHQL) &lt;br /&gt;
            video driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    ENTRY 2&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        -When I go to the Load Preset menu ('L') in MilkDrop, some of the&lt;br /&gt;
            presets on disk are missing.&lt;br /&gt;
        -I downloaded some new presets and put them in my Plugins\MilkDrop2\Presets&lt;br /&gt;
            directory, but I can't access them from within MilkDrop.&lt;br /&gt;
    CAUSE:&lt;br /&gt;
        You probably have an older video card that can't handle the pixel&lt;br /&gt;
        shaders needed to run some of the presets.  MilkDrop automatically&lt;br /&gt;
        hides any presets from you that you can't run.&lt;br /&gt;
    SOLUTION:&lt;br /&gt;
        * You could buy a new graphics card - one that meets the minimum&lt;br /&gt;
        recommendation for MilkDrop 2.  These cost less than $40.&lt;br /&gt;
        * You could try forcing MilkDrop to try to run these presets.&lt;br /&gt;
        Sometimes MilkDrop just hides them from you because it predicts&lt;br /&gt;
        they will run horribly slow on your graphics card; in case it&lt;br /&gt;
        is wrong about that, try this.  Go into the MilkDrop config&lt;br /&gt;
        panel (ALT+K) and go to the More Settings tab.  Under the &lt;br /&gt;
        &amp;quot;Pixel Shaders&amp;quot; option, change it from &amp;quot;Auto&amp;quot; to &amp;quot;Shader Model 2&amp;quot;&lt;br /&gt;
        or &amp;quot;Shader Model 3&amp;quot;.  Then try to run MilkDrop and see if the&lt;br /&gt;
        presets appear.  If they do, you're in luck; if they don't, your&lt;br /&gt;
        GPU really doesn't support those shader models.&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    ENTRY 3&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        MilkDrop always looks the same - it's always showing the same&lt;br /&gt;
        preset, and it never changes to a new preset unless I tell it to.&lt;br /&gt;
    CAUSE:&lt;br /&gt;
        Scroll Lock is on.&lt;br /&gt;
    SOLUTION:&lt;br /&gt;
        The Scroll Lock key is how you tell MilkDrop to lock the current&lt;br /&gt;
        preset - i.e. don't randomly transition to a new preset unless you &lt;br /&gt;
        do it.  The state of the Scroll Lock key is remembered when you&lt;br /&gt;
        start or stop MilkDrop, too, so be careful of that.  If you are&lt;br /&gt;
        experiencing this problem, you can fix it in any of the following&lt;br /&gt;
        three ways:&lt;br /&gt;
          1. hit Scroll Lock while MilkDrop is running (and the viz window is active);&lt;br /&gt;
          2. load up the MilkDrop config panel (ALT+K), go to the More Settings&lt;br /&gt;
              tab, and uncheck the &amp;quot;Start milkdrop with preset lock (scroll lock) &lt;br /&gt;
              key ON&amp;quot; box;&lt;br /&gt;
          3. if you're using a modern skin, there is a &amp;quot;random&amp;quot; button on&lt;br /&gt;
              the frame of the window, which is the inverse of the Scroll Lock&lt;br /&gt;
              state - i.e. you probably have Scroll Lock on and &amp;quot;random&amp;quot; off.&lt;br /&gt;
              Click the &amp;quot;Random&amp;quot; button to turn random transitions back on&lt;br /&gt;
              (and notice that scroll lock gets turned off as a result).&lt;br /&gt;
&lt;br /&gt;
    ENTRY 4&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        I was browsing for presets from within MilkDrop ('L') key and &lt;br /&gt;
        got lost.  How do I get back to my presets?&lt;br /&gt;
    SOLUTION:   &lt;br /&gt;
        Two ways to fix this.  The easiest is to just reset MilkDrop&lt;br /&gt;
        to its defaults - hit ALT+K to load the MilkDrop config panel,&lt;br /&gt;
        then click the 'Defaults' button.  The next time you launch&lt;br /&gt;
        MilkDrop, it will start you in the default preset directory.&lt;br /&gt;
        &lt;br /&gt;
        To fix it manually (and preserve all your settings), run&lt;br /&gt;
        MilkDrop, hit F8, and paste in this path:&lt;br /&gt;
          C:\Program Files\Winamp\Plugins\Milkdrop2\presets&lt;br /&gt;
        [or equivalent].&lt;br /&gt;
        &lt;br /&gt;
        Another way to fix it is to hit 'L', and browse all the way &lt;br /&gt;
        down to the root folder (repeatedly select &amp;quot;..&amp;quot;), then&lt;br /&gt;
        go into Program Files, Winamp, Plugins, MilkDrop2, and finally,&lt;br /&gt;
        presets.&lt;br /&gt;
&lt;br /&gt;
    ENTRY 5&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        -things flicker through (such as my AIM window ticker, taskbar&lt;br /&gt;
        clock, web page animations, etc.) when I'm running MilkDrop&lt;br /&gt;
        in fullscreen mode.&lt;br /&gt;
    CAUSE:&lt;br /&gt;
        You're probably running MilkDrop fullscreen at the same&lt;br /&gt;
        resolution &amp;amp; color depth as your desktop, and Windows isn't &lt;br /&gt;
        properly handling MilkDrop's request for exclusive access to the&lt;br /&gt;
        screen, and is still letting other applications paint (draw)&lt;br /&gt;
        themselves.&lt;br /&gt;
    SOLUTION:&lt;br /&gt;
        Change either your Windows desktop resolution or color depth, or &lt;br /&gt;
        MilkDrop's fullscreen resolution or color depth, so that there&lt;br /&gt;
        is some difference between the two.   (To change your Windows &lt;br /&gt;
        display settings, go to the Start Menu -&amp;gt; Settings -&amp;gt; Control &lt;br /&gt;
        Panel -&amp;gt; Display -&amp;gt; Settings tab, and then change the &amp;quot;colors&amp;quot; &lt;br /&gt;
        or &amp;quot;screen area&amp;quot; settings from there.)  Also make sure you're&lt;br /&gt;
        not using &amp;quot;fake&amp;quot; fullscreen mode (...uncheck this box on the&lt;br /&gt;
        main screen of the config panel).&lt;br /&gt;
&lt;br /&gt;
===Known Issues / Misc. / Tips:===&lt;br /&gt;
&lt;br /&gt;
    a. Tip for video capture: if you'd like to save sequences of video &lt;br /&gt;
        from this plugin, there are several programs out there that will &lt;br /&gt;
        let you do this.  Warning: you will need a ton of free hard drive &lt;br /&gt;
        space, and a fast CPU helps.  A few of these programs are:&lt;br /&gt;
            &amp;quot;FRAPS&amp;quot;               http://www.fraps.com/&lt;br /&gt;
            &amp;quot;Hypercam&amp;quot;            http://www.hyperionics.com&lt;br /&gt;
    &lt;br /&gt;
    b. Close other apps:&lt;br /&gt;
        For the best graphics performance, try to close as many other &lt;br /&gt;
        applications as you can, before running the plugin, especially &lt;br /&gt;
        those that tend to work in the background, such as anti-virus &lt;br /&gt;
        or file-swapping software.  Also, if you must leave other &lt;br /&gt;
        applications open, try to minimize them (i.e. shrink the window &lt;br /&gt;
        down to the taskbar) so that they stay out of the painting loop.&lt;br /&gt;
    &lt;br /&gt;
    c. Windows Vista / Winamp with per-user settings&lt;br /&gt;
        Be aware that if you're running Vista as a non-admin user,&lt;br /&gt;
        you can't write to (or delete from) files in the Program Files&lt;br /&gt;
        directory, which is were MilkDrop 2 is installed.  So, anything&lt;br /&gt;
        you try to write or save (like milkdrop's settings file, milk2.ini; &lt;br /&gt;
        or presets) will probably end up deep in some user-specific, &lt;br /&gt;
        virtualized &amp;quot;Program Files&amp;quot; directory somewhere on your hard &lt;br /&gt;
        drive.  Yell at Microsoft for this one!&lt;br /&gt;
        &lt;br /&gt;
        Also, if you installed Winamp with per-user settings (instead of &lt;br /&gt;
        shared settings) - on any OS, not just Vista - be aware that your&lt;br /&gt;
        .INI files (milk2.ini, milk2_img.ini, milk2_cfg.ini) are all&lt;br /&gt;
        stored in a folder like this:&lt;br /&gt;
            &lt;br /&gt;
            C:\Documents and Settings\\Application Data\Winamp\Plugins         &lt;br /&gt;
            &lt;br /&gt;
        (Note that 'Application Data' is a hidden folder.)  However,&lt;br /&gt;
        presets, textures, and things like that are all shared between&lt;br /&gt;
        users, in the real [c:\Program Files]\winamp\plugins\milkdrop2 folder. &lt;br /&gt;
        If you want to keep your presets separate, you can still do that, &lt;br /&gt;
        though - just put them in a personal folder, and then seek to it&lt;br /&gt;
        from within MilkDrop.  If you're using per-user settings in Winamp,&lt;br /&gt;
        it will remember which folder you last used.&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using Line-In===&lt;br /&gt;
-----------------------&lt;br /&gt;
    If you want to use your sound card's Line-In or CD Audio inputs for&lt;br /&gt;
    sound data (instead of mp3 files), you can do this.  Do the following:&lt;br /&gt;
        1. CONNECT WIRES&lt;br /&gt;
            Connect your audio source (a stereo, a live feed, whatever) into&lt;br /&gt;
            the line-in (or microphone) 1/8&amp;quot; jack on your sound card.  You&lt;br /&gt;
            might want to test &amp;amp; verify that your cable is good before doing &lt;br /&gt;
            this.&lt;br /&gt;
        2. SELECT SOUND INPUT CHANNEL &amp;amp; ADJUST VOLUME&lt;br /&gt;
            In Windows, double-click the speaker icon in your systray (where&lt;br /&gt;
            the clock is).  Then, on the menu, go to Options -&amp;gt; Properties&lt;br /&gt;
            and select the &amp;quot;Recording&amp;quot; option.  Then make sure the Line In&lt;br /&gt;
            (or Microphone) input channel (whichever is appropriate for&lt;br /&gt;
            your case) is SELECTED (with a check mark) and that the volume &lt;br /&gt;
            is close to, or at, the maximum.  Hit OK.           &lt;br /&gt;
        3. TELL WINAMP TO USE LINE-IN&lt;br /&gt;
            Open Winamp, and hit CTRL+L (the &amp;quot;Open Location&amp;quot; hotkey).  Now&lt;br /&gt;
            type in &amp;quot;linein://&amp;quot; as the location you want to open.  (Leave out&lt;br /&gt;
            the quotes and make sure you use FORWARD slashes.)  Hit PLAY&lt;br /&gt;
            ('x' key for the lazy), and the little built-in oscilloscope (or &lt;br /&gt;
            spectrum analyzer) in Winamp should start showing your signal.&lt;br /&gt;
        4. RUN MILKDROP&lt;br /&gt;
            Run MilkDrop as usual.  If the waves are too small or large, &lt;br /&gt;
            either adjust the volume from Windows' Volume Control, or adjust&lt;br /&gt;
            the sound level at the source.       &lt;br /&gt;
   &lt;br /&gt;
    If you are doing shows using live audio, and if you have a multiple monitor&lt;br /&gt;
    setup, you might also want to use the &amp;quot;VJ mode&amp;quot; feature, which lets you &lt;br /&gt;
    control MilkDrop (even editing shaders on the fly, etc.) via a separate monitor.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Media_Library_Plugin</id>
		<title>Media Library Plugin</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Media_Library_Plugin"/>
				<updated>2008-09-25T13:10:56Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Media Library Plugin&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Plugin struct definition&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;&lt;br /&gt;
  char *description;&lt;br /&gt;
  int (*init)(); // return 0 on success, non-zero for failure (quit WON'T be called) &lt;br /&gt;
  void (*quit)();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  // return NONZERO if you accept this message as yours, otherwise 0 to pass it &lt;br /&gt;
  // to other plugins&lt;br /&gt;
  INT_PTR (*MessageProc)(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3); &lt;br /&gt;
  //note: INT_PTR becomes 64bit on 64bit compiles...  if you don't like windows types or caps, you can #include &amp;lt;stddef.h&amp;gt; and use intptr_t&lt;br /&gt;
&lt;br /&gt;
  //all the following data is filled in by the library&lt;br /&gt;
  HWND hwndWinampParent;&lt;br /&gt;
  HWND hwndLibraryParent; // send this any of the WM_ML_IPC messages&lt;br /&gt;
  HINSTANCE hDllInstance;&lt;br /&gt;
} winampMediaLibraryPlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Plugins work by defining a struct full of functions for Winamp to call.  For Media Library plugins, there are three functions.&lt;br /&gt;
# Init - called after your plugin is loaded.  We need an Init() function (rather than having the plugin doing init is the winampGetMediaLibraryPlugin function) because Winamp needs to give YOU data before you can really do your initialization stuff&lt;br /&gt;
# Quit - duh&lt;br /&gt;
# MessageProc.  This is a function that the Winamp calls when certain events happen, such as someone activating your treeview node in the media library, or someone invoking the send-to menu&lt;br /&gt;
* You communicate with Winamp one of two basic ones&lt;br /&gt;
# By using SendMessage and sending Winamp or the Media Library window custom messages which are defined in Winamp/wa_ipc.h (for Winamp HWND) and gen_ml/ml.h (for Media Libary HWND).  This is the &amp;quot;old&amp;quot; way of doing things but even some newer APIs are still built on this mechanism.&lt;br /&gt;
# By retrieving pointers to objects from the Wasabi Service Manager.  Winamp has a bunch of APIs that you can grab, and plugins can add additional features that you might want to use.  Examples of useful Wasabi objects are the [[Media Library Database API|Local Media API]] (which lets you query against the media library), the [[Application API]] (let's you get version #, build #, path to winamp settings folder, etc), and the [[Playlist Manager API]] (lets you parse playlists, among other things)&lt;br /&gt;
&lt;br /&gt;
ml_xmlex is probably the most useful example of the bunch.  ml_ stands for media library plugin.  __declspec(dllexport) is a magic keyword for Visual C++ that means that the DLL &amp;quot;exports&amp;quot; this function, meaning that a program that loads the DLL can locate and call this function.  Winamp goes through and loads ml_*.dll plugins, looks for &amp;quot;winampGetMediaLibraryPlugin&amp;quot; and if it it exists it calls it.  From that function you are supposed to return a struct that defines your plugin.  It has the plugin name, some function pointers and some data that winamp will populate with information that'll be helpful to you, like winamp's HWND (window handle).  &lt;br /&gt;
&lt;br /&gt;
winampMediaLibraryPlugin is defined in gen_ml/ml.h which is one ugly beast of a file&lt;br /&gt;
benski&amp;gt; reupload to [[Image:winampMediaLibraryPlugin.png]]&lt;br /&gt;
http://shup.com/Shup/57721/10872016431-ml_xmlex-Microsoft-Visual-C__-%5Bdesign%5D-ml.h.png&lt;br /&gt;
&lt;br /&gt;
So you supply &amp;quot;init&amp;quot;, &amp;quot;quit&amp;quot; and &amp;quot;MessageProc&amp;quot; functions as well as a description.  Winamp calls Init(), at which point ml_xmlex does two things&lt;br /&gt;
# Gets the all-important Wasabi Service Manager object&lt;br /&gt;
# tells the media library to add a node to the treeview for itself [[Image:ml_xmlex_in_ml.png]] http://shup.com/Shup/57726/10872016155-Main-Window.png&lt;br /&gt;
&lt;br /&gt;
Plugins can manifest themselves in many ways (or be completely invisible!), just this media library plugin is a good starting point because you don't have to write too much busy-work GUI code.&lt;br /&gt;
&lt;br /&gt;
For Media Library plugins, when the media library needs your plugin (e.g. when the user clicked on you in the media library) it calls your message procedure.  xmlview.cpp line 147 is the message procedure.  this plugin is only handling one message which is to create a view.  there are other messages like &amp;quot;do you want to be on the send-to menu&amp;quot; but this example is keeping it simple.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Main</id>
		<title>Main</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Main"/>
				<updated>2008-09-25T13:09:58Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Main&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Classic Skin:  [[The Base Skin]] --&amp;gt; [[Main|Paint the Main Window]] --&amp;gt; [[Equalizer|Paint the Equalizer Window]] --&amp;gt; [[Playlist|Paint the Playlist Window]] --&amp;gt; [[Mini-browser|Paint the Minibrowser Window]] --&amp;gt; [[AVS|Paint the AVS Window]] --&amp;gt; [[For_Winamp_2.9/5.x|Paint the Winamp 2.9/5.x Windows]] --&amp;gt; [[Creating Custom Cursors|Create Custom Cursors]] --&amp;gt; [[Editing the Configuration Files|Edit the Configuration Files]] --&amp;gt; [[WSZ Files|Compress to .WSZ format]] --&amp;gt; [[Submitting Your Skin to Winamp.com|Submit to Winamp.com]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Skinning The Main Window==&lt;br /&gt;
The Winamp main window is probably the most complex window, graphics wise, of all its windows. There are many things going on in that one window at all times. Each part of the main window is divided up into various bitmap images. Here is a list of the images below that actually create the main window. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Winamp.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Main.bmp&lt;br /&gt;
*Titlebar.bmp&lt;br /&gt;
*CButtons.bmp&lt;br /&gt;
*ShufRep.bmp&lt;br /&gt;
*Volume.bmp&lt;br /&gt;
*Balance.bmp&lt;br /&gt;
*MonoSter.bmp&lt;br /&gt;
*Posbar.bmp&lt;br /&gt;
*Playpaus.bmp&lt;br /&gt;
*Numbers.bmp&lt;br /&gt;
*Text.bmp&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | Main.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:main.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This file provides the background image for Winamp, sections of the other bitmaps are cropped and layered over this background image to create the various states of &amp;quot;on&amp;quot; and &amp;quot;off&amp;quot;, buttons, sliders, etc. Many skin artists (skinners) create their own main.bmp image as well as the other components to make their skin as unique as possible. Although the regions in which the buttons can actually be clicked, the artists have a certain amount of pixels to play with for each element. This will enable the skinner to give the illusion of making smaller more precise controls, transparent controls, or even just big silly dumb ones if they wish. The possibilities are simply endless. The skin components are all bitmaps and therefore *cannot support animation or transparencies* The only way to achieve transparency is to use the overlapping area of main.bmp as the background in the various components.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | Titlebar.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:titlebar.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Titlebar.bmp provides the title bars for the all the various skinned windows of Winamp. The first of the bars are the graphics for Winamp's main window when that window has focus (the current window on your desktop is said to have the 'focus', and on that window the currently selected control also has the 'focus'). The second bar is the main window's title bar when it does not have the focus. The third and fourth bars provide the graphics for Winamp running in Window Shade mode. The fifth and sixth bars are special. They provide the graphics for the title bar when the Winamp Easter Egg is active. (Easter Eggs are usually useless aspects of a piece of software that the software developers include as a joke or to give credit to something. It's just the programmers trying to have a little fun. do not worry about these last two bars for now.)&lt;br /&gt;
&lt;br /&gt;
To the left of the title bars are a selection of graphics for the windows buttons in their various states.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:winbut.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The top row consists of the images for system menu (a.k.a. Winamp's Main Menu), the minimize button, as well as the close button in it's normal state (the way the buttons would look if they weren't clicked). The second row consists of the same set of buttons, however in the pressed state (the way the buttons would look if they were clicked). The third row is the graphics for the WindowShade button where the left image is the image of the button not pressed, and the left is the image of the button pressed. The fourth row contains the images for the button that restores Winamp or its various windows from WindowShade mode to its expanded form, the images being in the same order, the left being not pressed, and the right being the pressed state.&lt;br /&gt;
&lt;br /&gt;
The fifth and final row consists of the images that create the progress bar for Winamp when Winamp is in WindowShade mode. The first part of the row consists of the image for which the seek bar rests in, followed by the slider in various states.&lt;br /&gt;
&lt;br /&gt;
To the right of the title bars are the graphics for the CuttleBar, which is a little strip of buttons to the left of the visualization area of the Winamp main window. At the top the strip is shown in it's un-pressed state. To the right of the first strip is a version of the strip with all the labels removed, this is for the people who turn off the CuttleBar in Winamp's Preferences window. The next row of strips are simply the different states of the CuttleBar with copy of the strip in each of it's five states, one state for each button being pressed.&lt;br /&gt;
&lt;br /&gt;
When modifying the title bar it's important to remember that if you change the appearance of your buttons in the main title bar images, you should also change all the graphics that are relevant to the title bar to match so that they don't look out of place when you press them and remove the focus from the button you had just pressed. Also note that you can not add graphics for components that do not exist, for example adding a spot in WindowShade mode for track title scrolling would not make sense, due to the fact that Winamp wasn't coded with that in mind, leaving that spot you created blank.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | ShufRep.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Cbuttons.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The cbuttons.bmp image provides the images for Winamp's playback control buttons. The top row displays the buttons un-pressed or in their normal state, the second row of graphics are the same buttons except in the pressed state. Remember when skinning this set of components that transparency does not exist, if the button is incorporated into the background, you will have to place the background into the cbuttons.bmp.&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | ShufRep.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Shufrep.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Shufrep.bmp provides the graphics for both states of the Shuffle-Play button, Play/Loop button (Repeat), Equalizer button as well as the Playlist button. The top row is the (repeat) loop and shuffle in the off state, the second row, are the loop and shuffle button in the off, clicked state(the button being pressed while the shuffle/loop buttons were in the off state). The third row is loop and shuffle button in the on state, and the fourth row are the buttons being clicked in the on state.&lt;br /&gt;
&lt;br /&gt;
The bottom four images make up the graphics for the Equalizer and Playlist editor buttons in both two states. The first is the Equalizer button in the off state. The second button is the Playlist button in the off state. The third is the Equalizer off state and pressed at the same time. The fourth being the Playlist button in the same state. The next row is the exact same thing, however, instead of the buttons being in the off state, they are on.&lt;br /&gt;
&lt;br /&gt;
The same conditions in regards to transparency that apply for the Cbuttons.bmp image apply for this image as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | Volume.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Volume.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The volume.bmp file (partial shown here enlarged at the left) contains a set of of bars and two slider graphics. Depending on how high or low the level of the volume is, Winamp selects one of the bars to demonstrate the level at which the volume is currently at. If the volume is all the way down, it displays the more green bars, if all the way up, it displays the more yellow bars. The first bar is the volume at its lowest level, the last bar is the volume at its maximum level. Fiddle with these graphics yourselves to find out which bar is which level. The bottom contains the sliders control images. The first image being the slider, which is in the clicked, the second being in the un-clicked state.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | Balance.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Bal.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Balance.bmp works virtually identitical to volume.bmp, however, the images in balance need to illustrate the volume coming from either the left, right, or both speakers. This is done by swaying from green to red when moving the slider from one of the sides towards center. Simply color all the bars the way you would do for the volume.bmp and the outcome should be the same.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | MonoSter.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Monoster.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Monoster.bmp provides the indication that the audio source is running in Stereo or Mono mode. The top row shows the &amp;quot;in stereo&amp;quot; indicator as well as the &amp;quot;in mono&amp;quot;, indicator. The second row shows the &amp;quot;stereo off&amp;quot; and &amp;quot;mono off&amp;quot; indicators. When Winamp is playing in stereo sound, the &amp;quot;stereo on&amp;quot; with the &amp;quot;mono off&amp;quot; indicators are displayed. When the audio is in mono, the opposite is displayed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | Posbar.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Posbar.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The posbar.bmp, shown here enlarged, provides the track for the song position slider. At the right side of the image, the song seek slider is shown in both states, pressed and not pressed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | Playpaus.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:playpaus.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The playpaus.bmp file provides indicators that the file being played is playing, paused or stopped. The final item shows whether the file is synchronized or buffered or a break in transmission has been found.&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | Numbers.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Numbers.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The numbers.bmp file provides the images for displaying the numbers used in the time display, located directly above the visualizations area.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Winamp Skins | Text.bmp===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Text.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Text.bmp is performs the same job that numbers.bmp, however, this image isn't as limited in use as numbers.bmp. Text.bmp provides all the text that is used for the track area, Playlist editor, and anywhere else that Winamp uses text within the skinned interface.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Input_Plugin</id>
		<title>Input Plugin</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Input_Plugin"/>
				<updated>2008-09-25T13:09:48Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Input Plugin&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Include files:&lt;br /&gt;
:Winamp/in2.h&lt;br /&gt;
:Winamp/out.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Image_Writer_Service</id>
		<title>Image Writer Service</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Image_Writer_Service"/>
				<updated>2008-09-25T13:09:38Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Image Writer Service&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;api/service/svcs/svc_imgwrite.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/For_Winamp_2.9/5.x</id>
		<title>For Winamp 2.9/5.x</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/For_Winamp_2.9/5.x"/>
				<updated>2008-09-25T13:09:25Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;For Winamp 2.9/5.x&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Classic Skin:  [[The Base Skin]] --&amp;gt; [[Main|Paint the Main Window]] --&amp;gt; [[Equalizer|Paint the Equalizer Window]] --&amp;gt; [[Playlist|Paint the Playlist Window]] --&amp;gt; [[Mini-browser|Paint the Minibrowser Window]] --&amp;gt; [[AVS|Paint the AVS Window]] --&amp;gt; [[For_Winamp_2.9/5.x|Paint the Winamp 2.9/5.x Windows]] --&amp;gt; [[Creating Custom Cursors|Create Custom Cursors]] --&amp;gt; [[Editing the Configuration Files|Edit the Configuration Files]] --&amp;gt; [[WSZ Files|Compress to .WSZ format]] --&amp;gt; [[Submitting Your Skin to Winamp.com|Submit to Winamp.com]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Skinning Additional Winamp 2.9/5.x Windows==&lt;br /&gt;
&lt;br /&gt;
===The Video Window===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Video_window.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This file is for the Video window. It is resizeable and tiled, just like the playlist window. The titlebar occupies the two top rows. It's just like the playlist titlebar without the winshade mode and missing the winshade button. The close button is in the default state, beside the little graphic that is tiled across everytime the window is scaled horizontally. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Video.gif]]&lt;br /&gt;
&lt;br /&gt;
'''video.bmp'''&lt;br /&gt;
&lt;br /&gt;
The next row of graphics contains what would appear on the bottom left corner of the window which has all the video window buttons in their unpressed states. It also contains (from left to right) the left and right borders of the window for vertical scaling, the pressed close button and all the other buttons in their pressed state. The video buttons are (from left to right) full screen, regular size, double size, TV browser and load file. The next row of graphics has the right corner of the window and the bottom tile. The right corner has the resize button. The bottom tile will be used for horizontal scaling. Along this bottom tile, there will be a box to contain the current playing filename.&lt;br /&gt;
&lt;br /&gt;
===&amp;quot;Gen&amp;quot; Windows===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Gen.gif]]&lt;br /&gt;
&lt;br /&gt;
'''gen.bmp'''&lt;br /&gt;
&lt;br /&gt;
Gen.bmp is used for general purpose windows such as the media library and the AVS window in Winamp versions greater than 2.9. General purpose windows are resizeable and tiled. The first row is th active title bar and the second row is the inactive one. The title bar is divided into six parts. The first part is the top left corner of the window. The second is a fixed bitmap graphic which does not repeat in the title bar. The third section is the main title container. The fourth is another non repeating part of the title bar. The fifth section is used when the window is horizontally scaled. The last piece is the top right corner of the window and it contains the close window button. Below the title bars are the left bottom corner and the right bottom corner. The left one is placed above the right one. The right bottom corner has a resize button. To the right of these bottom corners are the sidewalls of the window. The left sidewall comes first then the right one. These sections are used during resizing. next to these is the close window button. next to this close button are the bottom corner sidewalls. These sections are used to join the sidewalls to the left and right bottom corners of the window. The left corner sidewall comes before the right one. The right one contains part of the resizer button from the bottom right corner of the window. Immediately below these corner sidewalls is a graphic for the bottom of the window. This graphic is tiled when the window is resized. Below this are the font of the titlebar. The highlighted one lies above the non highlighted font. The fonts are of variable width but not height. Both the highlighted and non highlighted fonts must be of the same width. The letters are ordered in the standard English alphabet order. There are no foreign characters. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Genex.gif]]&lt;br /&gt;
&lt;br /&gt;
'''genex.bmp'''&lt;br /&gt;
&lt;br /&gt;
Genex.bmp is used for the buttons and sliders used in the general purpose windows. It also contains the colour controls for this window. The top button is the active state button. The one right below it is the inactive or pressed state button. These buttons have a four pixel wide border around it. The borders stay 4 pixels thick, no matter the size of the buttons or window. Beside these buttons is a row of pixels used to control the various colors and background of the gen window. The coordinates of the pixels are for as follows (y=0):&lt;br /&gt;
&lt;br /&gt;
# x=48: item background (background to edits, listviews, etc.)&lt;br /&gt;
# x=50: item foreground (text colour of edits, listviews, etc.)&lt;br /&gt;
# x=52: window background (used to set the bg color for the dialog)&lt;br /&gt;
# x=54: button text colour&lt;br /&gt;
# x=56: window text colour&lt;br /&gt;
# x=58: colour of dividers and sunken borders&lt;br /&gt;
# x=60: selection colour for entries inside playlists (nothing else yet)&lt;br /&gt;
# x=62: listview header background colour&lt;br /&gt;
# x=64: listview header text colour&lt;br /&gt;
# x=66: listview header frame top and left colour&lt;br /&gt;
# x=68: listview header frame bottom and right colour&lt;br /&gt;
# x=70: listview header frame colour, when pressed&lt;br /&gt;
# x=72: listview header dead area colour&lt;br /&gt;
# x=74: scrollbar colour #1&lt;br /&gt;
# x=76: scrollbar colour #2&lt;br /&gt;
# x=78: pressed scrollbar colour #1&lt;br /&gt;
# x=80: pressed scrollbar colour #2&lt;br /&gt;
# x=82: scrollbar dead area colour &lt;br /&gt;
&lt;br /&gt;
Below these are the scroll buttons. The first four buttons are these buttons: (from left to right) the scroll up unpressed, scroll down unpressed, scroll up pressed, scroll down pressed. Immediately below these are (from left to right) the scroll left unpressed, scroll right unpressed, scroll left pressed, scroll right pressed. Beside these two rows of scroll buttons are the sliders. The first one from the left is the vertical slider unpressed, the second one is the vertical slider pressed. Beside it, on the top is the horizontal slider unpressed. Below this is the horizontal slider pressed.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Editing_the_Configuration_Files</id>
		<title>Editing the Configuration Files</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Editing_the_Configuration_Files"/>
				<updated>2008-09-25T13:09:20Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Editing the Configuration Files&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Classic Skin:  [[The Base Skin]] --&amp;gt; [[Main|Paint the Main Window]] --&amp;gt; [[Equalizer|Paint the Equalizer Window]] --&amp;gt; [[Playlist|Paint the Playlist Window]] --&amp;gt; [[Mini-browser|Paint the Minibrowser Window]] --&amp;gt; [[AVS|Paint the AVS Window]] --&amp;gt; [[For_Winamp_2.9/5.x|Paint the Winamp 2.9/5.x Windows]] --&amp;gt; [[Creating Custom Cursors|Create Custom Cursors]] --&amp;gt; [[Editing the Configuration Files|Edit the Configuration Files]] --&amp;gt; [[WSZ Files|Compress to .WSZ format]] --&amp;gt; [[Submitting Your Skin to Winamp.com|Submit to Winamp.com]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Any skin file is not complete without first finishing up the configuration files. These configuration files control such things as the background and foreground colors of the Winamp visualizations, or areas that are designated areas to be displayed to the end user. There are three text files that allow you to change these various aspects of Winamp. The first of the three that we will cover is called VisColor.txt.&lt;br /&gt;
&lt;br /&gt;
==Configuration File | VisColor.txt==&lt;br /&gt;
&lt;br /&gt;
VisColor.txt is the file that sets the colors for the Visualization panel. It contains 24 lines. Each line is an RGB value followed by a comment. (See RGB for more Info). Here is a brief explanation of the lines:&lt;br /&gt;
&lt;br /&gt;
* Row 0 is the background color of the visualization area.&lt;br /&gt;
* Row 1 is the color of the dots that appear in the visualization area&lt;br /&gt;
* Rows 2 through 17 affect the colors of the Spectrum Analyzer. Row 2 is the peak value, the highest part of the graphical bar that is visible. This means that when you hit a high frequency, the top of the bar becomes the color specified. As you move from row to row, you can color each level of the frequency spectrum a different color to signify the peak levels of the frequencies in the file you are playing at that moment.&lt;br /&gt;
* Rows 18 to 22 pertain to the oscilloscope colors. They function in the same fashion as the Spectrum Analyzer. Row 18 controls the colors that is displayed at the troughs and the row 22 is the color that is displayed at the crest. Each row between 18 and 22 sets a different level of the whole wave.&lt;br /&gt;
* Row 23 gives the color used to mark the last peak value. Let's take a look at what this all means, here are some screenshots with example images to help you get a clearer perspective.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Vis.gif]]&lt;br /&gt;
&lt;br /&gt;
The result with row 0 set to 0,0,0 and row 1 set to 255,255,255&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Configuration File | Pledit.txt==&lt;br /&gt;
&lt;br /&gt;
Pledit.txt gives the font colors and font face for the Playlist Editor track listing as well as the MiniBrowser URL display, located at the bottom of the MiniBrowser.&lt;br /&gt;
&lt;br /&gt;
Here are some sample settings for pledit.txt is:&lt;br /&gt;
&lt;br /&gt;
'''[Text]'''&lt;br /&gt;
&lt;br /&gt;
Normal=#FF8924&lt;br /&gt;
&lt;br /&gt;
Current=#FFFF00&lt;br /&gt;
&lt;br /&gt;
NormalBG=#1A120A&lt;br /&gt;
&lt;br /&gt;
SelectedBG=#944E11&lt;br /&gt;
&lt;br /&gt;
MbFG=#FF8924&lt;br /&gt;
&lt;br /&gt;
MbBG=#1A120A&lt;br /&gt;
&lt;br /&gt;
Font=Comic Sans MS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The funny values are Hexadecimal RBG values (see Hex RGB). Each row has a different setting:&lt;br /&gt;
&lt;br /&gt;
* Normal - Color of the regular text (Playlist).&lt;br /&gt;
* Current - Color of the current track text (Playlist).&lt;br /&gt;
* NormalBG - Background for normal text (Playlist).&lt;br /&gt;
* SelectedBG - Background for the selected text (Playlist)&lt;br /&gt;
* MbFG - Text color in the MiniBrowser status bar. (MiniBrowser)&lt;br /&gt;
* MbBG - Text background in the MiniBrowser status bar. (MiniBrowser)&lt;br /&gt;
* Font - Font face that's used in both windows&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Configuration File | Region.txt==&lt;br /&gt;
&lt;br /&gt;
So you want a skin with areas that are simply put, transparent? Well, this is a highly tricky task. The file you need is called region.txt and the way to do it is a lot like playing connect-the-dots.&lt;br /&gt;
&lt;br /&gt;
Region.txt provides a set of names such as Normal, WindowShade and so fourth. These set points define how many points make up each window. Another set defines how to draw the picture over Winamp.&lt;br /&gt;
&lt;br /&gt;
Region.txt has 4 regions (the sets). They are delimited with the following tags:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[Normal]&lt;br /&gt;
&lt;br /&gt;
[WindowShade]&lt;br /&gt;
&lt;br /&gt;
[Equalizer]&lt;br /&gt;
&lt;br /&gt;
[EqualizerWS]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each of these provides a list that constist of two parts. The first gives the number of points that make up a region. The second is a list of the points used to make those regions.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The lines are:&lt;br /&gt;
&lt;br /&gt;
NumPoints=&lt;br /&gt;
&lt;br /&gt;
PointList=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The NumPoints list must be on a single line with comma separated numbers.&lt;br /&gt;
&lt;br /&gt;
Example: NumPoints = 4, 4&lt;br /&gt;
&lt;br /&gt;
Each number, x, says to read the next x points of the list and plot the region they define. The points list is comma seperated pairs of x,y co-ordinates. For example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[Normal]&lt;br /&gt;
&lt;br /&gt;
NumPoints = 4, 4&lt;br /&gt;
&lt;br /&gt;
PointList = 0,1, 275,1, 275,14, 0,14,    3,15,&lt;br /&gt;
&lt;br /&gt;
272,15, 272,113, 3,113&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Defines two rectangular regions to be drawn. For more information read the comments in the region.txt file in the base skin. You will find a little more explanation in this file. The only item missing is the EqualizerWS group which is new and will be defined at a later time. &amp;quot;Normal&amp;quot; defines the regions drawn for the main window, WindowShade is the regions drawn in the windowshade mode. Equalizer and EqualizerWS are the same as above. Use the examples above to work out the other points. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Configuration File | RGB==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RGB stands for &amp;quot;Red, Green, Blue&amp;quot;. A certain combination of each of these colors at various percentages can make millions of different colors. For example, combining 100% Blue and 100% Green will make the brightest achievable Yellow. Using this model, RGB has become a method of defining color.&lt;br /&gt;
&lt;br /&gt;
Since a computer displays light using pixels which are really three lights one Red one Green and one Blue (well close enough description for our purposes), we can define a color as the amount of red, green and blue. The ranges we use to help put into perceptive for each of the colors on a computer, we use 0 all the way to 255. Basically, that means, there are 256 different shades of each of those primary three colors, and any combination of those three shades will result in a color. For example, 128, 128, and 128 would make a gray in about the middle of the spectrum. Here are the different values of each of those colors.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Skins-classic-config.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Configuration File | Hexadecimal==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hexadecimal RGB numbers are exactly the same as RGB, except the value is represented in Hexadecimal notation. Digit position has less meaning (no hundreds tens and units). And each digit can be 0-9 then A-F. To convert from Hex to Decimal use Windows Calculator in Scientific mode.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Creating_a_ClassicPro_Skin</id>
		<title>Creating a ClassicPro Skin</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Creating_a_ClassicPro_Skin"/>
				<updated>2008-09-25T13:09:08Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Creating a ClassicPro Skin&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==What is ClassicPro?==&lt;br /&gt;
ClassicPro is a plugin for Winamp that will allow you to use a new type of skin in Winamp Media Player. What makes this type of skin different from normal modern skins is that all the coding stuff is already done in one central place so you don't need to be a programmer to create a great Winamp skin anymore! &lt;br /&gt;
The advantages are not just for the skinners though, artistic people can now create great skins easily, and this means we'll see more beautiful skins by great artists!&lt;br /&gt;
&lt;br /&gt;
ClassicPro skins use an advanced single-user-interface which is really easy to use. The great thing is cPro appeals both to the advanced Winamp user and the minimalistic user who would for example just want to use the playlist. This means ClassicPro will probably fit you like a glove no matter who you are!&lt;br /&gt;
If you are used to a Classic Winamp skin and didn't want to switch to the modern skins of the past then we urge you to give this a test drive since this skin type was designed especially for the old school user who might need a minimalistic approach to their favourite media player.&lt;br /&gt;
&lt;br /&gt;
The 2 main key focus points in the development was as follows:&lt;br /&gt;
* Performance - Winamp must load quick and use as little resources running as possible&lt;br /&gt;
* Easy Interface - The interface must be easy to understand and give enough play for the experienced users too&lt;br /&gt;
&lt;br /&gt;
[http://cpro.skinconsortium.com/ Download ClassicPro plugin]&lt;br /&gt;
&lt;br /&gt;
==Introduction to ClassicPro skins==&lt;br /&gt;
[[Image:http://cpro.skinconsortium.com/images/cpro-promo1_04.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ClassicPro skins are basically pre-coded Winamp Modern Skins. The advantage of this is that the skinner dont have to spend months coding the skin anymore and can just edit a few picture files and have a fully working skin. All the coding of the skin is installed in one central place by the cPro plugin and then this plugin is maintained by the developer. So when the plugin installs new features or fixes your skin will automatically have them too.&lt;br /&gt;
&lt;br /&gt;
For more information make a post at their forums:&lt;br /&gt;
[http://forums.skinconsortium.com SkinConsortium Forums]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Tools needed to create a skin==&lt;br /&gt;
* Graphics Editor&lt;br /&gt;
** Paint, Corel PSP, Adobe PS, GIMP, Paint.NET&lt;br /&gt;
* Text Editor&lt;br /&gt;
** Notepad, Notepad2, Notepad++&lt;br /&gt;
* Archiver&lt;br /&gt;
** 7zip, WinZip, WinRar&lt;br /&gt;
* ClassicPro plug-in&lt;br /&gt;
** [http://cpro.skinconsortium.com/ Download ClassicPro plugin]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Tutorials==&lt;br /&gt;
* [http://cpro.skinconsortium.com/index.php?content=manual Skinners Guide to ClassicPro] by pjn123&lt;br /&gt;
** This is the manual released by the developers&lt;br /&gt;
* [http://wilian.deviantart.com/art/ClassicPro-Template-pack-95549517 ClassicPro Template pack and Manual] by Wilian &amp;amp; Veroka&lt;br /&gt;
** This is a more in depth look at creating cPro skins. Really great for beginners.&lt;br /&gt;
** Comes with great base skin for you to start off with&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Box_source_code_here</id>
		<title>Box source code here</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Box_source_code_here"/>
				<updated>2008-09-25T13:09:02Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Box source code here&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;&lt;br /&gt;
 #include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
 #include &amp;quot;resource.h&amp;quot;&lt;br /&gt;
 #include &amp;quot;avs_ape.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// this will be the directory and APE name displayed in&lt;br /&gt;
// the AVS Editor&lt;br /&gt;
 #define MOD_NAME &amp;quot;Tutorials / BOX v1.0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// this is how WVS will recognize this APE internally&lt;br /&gt;
  #define UNIQUEIDSTRING &amp;quot;Nullsoft Tut0: BOX&amp;quot;&lt;br /&gt;
  class C_THISCLASS : public C_RBASE&lt;br /&gt;
  {protected:&lt;br /&gt;
  public:&lt;br /&gt;
  C_THISCLASS();&lt;br /&gt;
  virtual ~C_THISCLASS();&lt;br /&gt;
  virtual int render(char visdata[2][2][576], int isBeat,&lt;br /&gt;
   int *framebuffer, int *fbout, int w, int h);&lt;br /&gt;
  virtual HWND conf(HINSTANCE hInstance, HWND hwndParent);&lt;br /&gt;
  virtual char *get_desc();&lt;br /&gt;
  virtual void load_config(unsigned char *data, int len);&lt;br /&gt;
  virtual int  save_config(unsigned char *data);&lt;br /&gt;
  int enabled;  // toggles plug-in on and off&lt;br /&gt;
                // (a good idea for any APE)&lt;br /&gt;
  int color;		// color of rectangle};&lt;br /&gt;
&lt;br /&gt;
// global configuration dialog pointer&lt;br /&gt;
static C_THISCLASS *g_ConfigThis;&lt;br /&gt;
// global DLL instance pointer (not needed in this&lt;br /&gt;
// example, but is useful)static HINSTANCE g_hDllInstance;&lt;br /&gt;
// this is where we deal with the configuration screen&lt;br /&gt;
static BOOL CALLBACK g_DlgProc(HWND hwndDlg, UINT uMsg,&lt;br /&gt;
WPARAM wParam,LPARAM lParam)&lt;br /&gt;
{&lt;br /&gt;
 switch (uMsg)&lt;br /&gt;
 {&lt;br /&gt;
  case WM_INITDIALOG:&lt;br /&gt;
  if (g_ConfigThis-&amp;gt;enabled)&lt;br /&gt;
  {&lt;br /&gt;
   CheckDlgButton(hwndDlg,IDC_CHECK1,BST_CHECKED);&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
  case WM_DRAWITEM:&lt;br /&gt;
  DRAWITEMSTRUCT *di;&lt;br /&gt;
  di=(DRAWITEMSTRUCT *)lParam;&lt;br /&gt;
  if (di-&amp;gt;CtlID == IDC_DEFCOL)&lt;br /&gt;
  {&lt;br /&gt;
   int w;&lt;br /&gt;
   int color;&lt;br /&gt;
   w=di-&amp;gt;rcItem.right-di-&amp;gt;rcItem.left;&lt;br /&gt;
   color=g_ConfigThis-&amp;gt;color;&lt;br /&gt;
   color = ( (color&amp;gt;&amp;gt;16)&amp;amp;0xff) |&lt;br /&gt;
   (color&amp;amp;0xff00) |&lt;br /&gt;
   ((color&amp;lt;&amp;lt;16)&amp;amp;0xff0000);&lt;br /&gt;
&lt;br /&gt;
   // paint nifty color button&lt;br /&gt;
   HBRUSH hBrush,hOldBrush;&lt;br /&gt;
   LOGBRUSH lb={BS_SOLID,color,0};&lt;br /&gt;
   hBrush = CreateBrushIndirect(&amp;amp;lb);&lt;br /&gt;
   hOldBrush=(HBRUSH)SelectObject(di-&amp;gt;hDC,hBrush);&lt;br /&gt;
   Rectangle(di-&amp;gt;hDC,di-&amp;gt;rcItem.left,di-&amp;gt;rcItem.top,&lt;br /&gt;
   di-&amp;gt;rcItem.right,di-&amp;gt;rcItem.bottom);&lt;br /&gt;
   SelectObject(di-&amp;gt;hDC,hOldBrush);&lt;br /&gt;
   DeleteObject(hBrush);&lt;br /&gt;
   }&lt;br /&gt;
  return 0;&lt;br /&gt;
  case WM_COMMAND:&lt;br /&gt;
&lt;br /&gt;
  // see if enable checkbox is checked&lt;br /&gt;
  if (LOWORD(wParam) == IDC_CHECK1)&lt;br /&gt;
   {&lt;br /&gt;
    g_ConfigThis-&amp;gt;enabled=&lt;br /&gt;
    (IsDlgButtonChecked(hwndDlg,IDC_CHECK1)?1:0);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   // is colorbox is selected?&lt;br /&gt;
  if (LOWORD(wParam) == IDC_DEFCOL)&lt;br /&gt;
   {&lt;br /&gt;
    static COLORREF custcolors[16];&lt;br /&gt;
    int *a;&lt;br /&gt;
    CHOOSECOLOR cs;&lt;br /&gt;
    a=&amp;amp;g_ConfigThis-&amp;gt;color;&lt;br /&gt;
    cs.lStructSize = sizeof(cs);&lt;br /&gt;
    cs.hwndOwner = hwndDlg;&lt;br /&gt;
    cs.hInstance = 0;&lt;br /&gt;
    cs.rgbResult = ((*a&amp;gt;&amp;gt;16)&amp;amp;0xff)|&lt;br /&gt;
     (*a&amp;amp;0xff00)|&lt;br /&gt;
     ((*a&amp;lt;&amp;lt;16)&amp;amp;0xff0000);&lt;br /&gt;
    cs.lpCustColors = custcolors;&lt;br /&gt;
    cs.Flags = CC_RGBINIT|CC_FULLOPEN;&lt;br /&gt;
&lt;br /&gt;
   // go to windows color selection screen&lt;br /&gt;
   if (ChooseColor(&amp;amp;cs))&lt;br /&gt;
   {&lt;br /&gt;
    *a = ((cs.rgbResult&amp;gt;&amp;gt;16)&amp;amp;0xff)|&lt;br /&gt;
    (cs.rgbResult&amp;amp;0xff00)|&lt;br /&gt;
    ((cs.rgbResult&amp;lt;&amp;lt;16)&amp;amp;0xff0000);&lt;br /&gt;
   }&lt;br /&gt;
   InvalidateRect(GetDlgItem(hwndDlg,IDC_DEFCOL),&lt;br /&gt;
    NULL,TRUE);&lt;br /&gt;
   }&lt;br /&gt;
   return 0;&lt;br /&gt;
   }&lt;br /&gt;
   return 0;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
// set up default configuration&lt;br /&gt;
C_THISCLASS::C_THISCLASS()&lt;br /&gt;
{&lt;br /&gt;
 //set initial color&lt;br /&gt;
 color=RGB(255,0,0);&lt;br /&gt;
 enabled=1;}&lt;br /&gt;
&lt;br /&gt;
// virtual destructor&lt;br /&gt;
C_THISCLASS::~C_THISCLASS()&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* RENDER FUNCTION:&lt;br /&gt;
render should return 0 if it only used framebuffer,&lt;br /&gt;
or 1 if the new output data  is in fbout.&lt;br /&gt;
this is used when you want to do something that you'd otherwise&lt;br /&gt;
need to make a copy of the framebuffer.&lt;br /&gt;
w and h are the width and height of the screen, in pixels.&lt;br /&gt;
isBeat is 1 if a beat has been detected.&lt;br /&gt;
visdata is in the format of [spectrum:0,wave:1][channel][band].&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
int C_THISCLASS::render(char visdata[2][2][576], int isBeat,&lt;br /&gt;
		int *framebuffer, int *fbout, int w, int h)&lt;br /&gt;
{&lt;br /&gt;
 int halfw;&lt;br /&gt;
 int halfh;&lt;br /&gt;
&lt;br /&gt;
 // is this effect on?&lt;br /&gt;
 if (!enabled)&lt;br /&gt;
 {&lt;br /&gt;
  return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 // did we just hit a beat?&lt;br /&gt;
 if(isBeat)&lt;br /&gt;
 {&lt;br /&gt;
  // draw our magic box&lt;br /&gt;
  halfw=w/2;&lt;br /&gt;
  halfh=h/2;&lt;br /&gt;
  framebuffer+=(((halfh/2)*w)+ (halfw/2));&lt;br /&gt;
  for(int j=0;j&amp;lt;halfh;j++)&lt;br /&gt;
   {&lt;br /&gt;
    for(int i=0;i&amp;lt;halfw;i++)&lt;br /&gt;
    {&lt;br /&gt;
     framebuffer[i]=color;&lt;br /&gt;
    }&lt;br /&gt;
    framebuffer+=w;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
HWND C_THISCLASS::conf(HINSTANCE hInstance, HWND hwndParent)&lt;br /&gt;
// return NULL if no config dialog possible&lt;br /&gt;
{&lt;br /&gt;
 g_ConfigThis = this;&lt;br /&gt;
 return CreateDialog(hInstance,MAKEINTRESOURCE(IDD_CONFIG),&lt;br /&gt;
  hwndParent,g_DlgProc);&lt;br /&gt;
}&lt;br /&gt;
char *C_THISCLASS::get_desc(void)&lt;br /&gt;
{&lt;br /&gt;
 return MOD_NAME;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// load_/save_config are called when saving and loading&lt;br /&gt;
// presets (.avs files)&lt;br /&gt;
&lt;br /&gt;
#define GET_INT() (data[pos]|(data[pos+1]&amp;lt;&amp;lt;8)|\&lt;br /&gt;
  (data[pos+2]&amp;lt;&amp;lt;16)|(data[pos+3]&amp;lt;&amp;lt;24))&lt;br /&gt;
// read configuration of max length &amp;quot;len&amp;quot; from data.&lt;br /&gt;
&lt;br /&gt;
void C_THISCLASS::load_config(unsigned char *data, int len)&lt;br /&gt;
{&lt;br /&gt;
 int pos=0;&lt;br /&gt;
 // always ensure there is data to be loaded&lt;br /&gt;
 if (len-pos &amp;gt;= 4)&lt;br /&gt;
  {&lt;br /&gt;
   // load activation toggle&lt;br /&gt;
   enabled=GET_INT();&lt;br /&gt;
   pos+=4;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
 if (len-pos &amp;gt;= 4)&lt;br /&gt;
  {&lt;br /&gt;
   // load the box color&lt;br /&gt;
   color=GET_INT();&lt;br /&gt;
   pos+=4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// write configuration to data, return length.&lt;br /&gt;
// config data should not exceed 64k.&lt;br /&gt;
#define PUT_INT(y) data[pos]=(y)&amp;amp;255; data[pos+1]=(y&amp;gt;&amp;gt;8)&amp;amp;255;\&lt;br /&gt;
data[pos+2]=(y&amp;gt;&amp;gt;16)&amp;amp;255; data[pos+3]=(y&amp;gt;&amp;gt;24)&amp;amp;255&lt;br /&gt;
&lt;br /&gt;
int  C_THISCLASS::save_config(unsigned char *data)&lt;br /&gt;
{&lt;br /&gt;
 int pos=0;&lt;br /&gt;
&lt;br /&gt;
 PUT_INT(enabled);&lt;br /&gt;
 pos+=4;&lt;br /&gt;
&lt;br /&gt;
 PUT_INT(color);&lt;br /&gt;
 pos+=4;&lt;br /&gt;
&lt;br /&gt;
 return pos;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
export stuff&lt;br /&gt;
creates a new effect object if desc is NULL, otherwise&lt;br /&gt;
fills in desc with description&lt;br /&gt;
*/&lt;br /&gt;
C_RBASE *R_RetrFunc(char *desc)&lt;br /&gt;
{&lt;br /&gt;
 if (desc)&lt;br /&gt;
 {&lt;br /&gt;
  strcpy(desc,MOD_NAME);&lt;br /&gt;
  return NULL;&lt;br /&gt;
 }&lt;br /&gt;
 return (C_RBASE *) new C_THISCLASS();&lt;br /&gt;
}&lt;br /&gt;
 // allows AVS to retrieve this APE module&lt;br /&gt;
extern &amp;quot;C&amp;quot;&lt;br /&gt;
{&lt;br /&gt;
 __declspec (dllexport) int _AVS_APE_RetrFunc(HINSTANCE\&lt;br /&gt;
  hDllInstance, char **info, int *create)&lt;br /&gt;
  // return 0 on failure&lt;br /&gt;
 {&lt;br /&gt;
  g_hDllInstance=hDllInstance;&lt;br /&gt;
  *info=UNIQUEIDSTRING;&lt;br /&gt;
  *create=(int)(void*)R_RetrFunc;&lt;br /&gt;
  return 1;&lt;br /&gt;
 }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Album_Art_API</id>
		<title>Album Art API</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Album_Art_API"/>
				<updated>2008-09-25T13:08:56Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Album Art API&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Agave/AlbumArt/api_albumart.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Wasabi</id>
		<title>Wasabi</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Wasabi"/>
				<updated>2008-09-25T13:08:50Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Wasabi&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''W'''inamp '''S'''ervice '''A'''rchitecture '''B'''inary '''I'''nterface&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The plugin struct definition API is effective, but it would be cumbersome to create a new plugin type for every possible scenario.  As a result, a new generic plugin system was created named Wasabi (Winamp Service Architecture Binary Interface).  Instead of hard-coded lists of function pointers to be defined, plugins create C++ objects implementing known interfaces identified with some unique ID (GUID).  Rather than a specific filename having one specific plugin type (in_*.dll for Input plugins), Wasabi components 'register' the services they provide.  This allows one plugin to load provide multiple services, allows for new plugin types to be created without new code, and allows for &amp;quot;specialized&amp;quot; plugin types.  For example, playlist.w5s loads the [[Playlist API|Playlist Manager API]] for loading and analyzing playlist files, as well as individual playlist loading objects for each type (M3U, PLS, B4S), and various helper services involving playlists.&lt;br /&gt;
&lt;br /&gt;
Plugins can communicate with each other by requesting each other's services via the Service Manager.  They can also query for API's that Winamp itself registers such as the [[System Callbacks API]] (generic notification system) and the [[Application API]] (allows plugins to query for version number, settings path, etc)&lt;br /&gt;
&lt;br /&gt;
Wasabi relies on a common base class called &amp;quot;Dispatchable&amp;quot;.  Dispatchable implements a single virtual method which consists of a &amp;quot;function ID&amp;quot; integer value, an array of parameters and a parameter count.  Child class implementations override this function with logic which &amp;quot;dispatches&amp;quot; each ID to the appropriate function.  In some regards, it is similar to the old [[SendMessage API]].  However, a set of inline helper methods defined inside each interface removes the complexity of using Wasabi interfaces, and most of the complexity from implementing Wasabi interfaces.  They can be treated like any other C++ object.&lt;br /&gt;
&lt;br /&gt;
== Components of Wasabi ==&lt;br /&gt;
 &lt;br /&gt;
* api definitions - formalizes the interfaces for various objects, APIs, interfaces and services&lt;br /&gt;
* wasabi helper classes - accesses the service manager to find services to perform required tasks. e.g. FileReaderApi enumerates the available file reader services to find an appropriate one and read from it. Used to hide complexity from the programmer. Some of these exist as shared services, to cut down on duplicate code across plugins.&lt;br /&gt;
* general purposes helper classes / functions - called BFC (brennan foundation class) currently.&lt;br /&gt;
&lt;br /&gt;
What is Wasabi intended to solve?&lt;br /&gt;
&lt;br /&gt;
# C++ does not define a binary interface to share objects between modules&lt;br /&gt;
# The existing [[SendMessage API|winamp 2]] plugin architecture only defines a limited set of interfaces&lt;br /&gt;
# Existing winamp 2 plugins have limited interaction with Winamp.&lt;br /&gt;
&lt;br /&gt;
== Dispatchable ==&lt;br /&gt;
&lt;br /&gt;
The Dispatchable class is the base class for many of the classes within Wasabi. It contains a single virtual method, _dispatch(), which is passed a dispatch ID msg, a pointer to store a return value retval, a pointer to an array of parameters params, and the parameter count nparam.&lt;br /&gt;
&lt;br /&gt;
The class is defined as:&lt;br /&gt;
&lt;br /&gt;
 '''class''' Dispatchable&lt;br /&gt;
 {&lt;br /&gt;
 '''public''':&lt;br /&gt;
  // this is virtual so it is visible across modules&lt;br /&gt;
  '''virtual''' '''int''' _dispatch('''int''' msg, '''void''' *retval, '''void''' **params = NULL, '''int''' nparam = 0)=0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In many ways, it is similiar to the Invoke() portion of COM's IDispatch class. It is also conceptually similiar to a Win32 Window Procedure.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When classes are used by different plugins, the Dispatchable base class is used instead of abstract classes with pure virtual functions. Why? Because it makes it easier to add additional methods, without requiring &amp;quot;version 2&amp;quot; classes such as those that COM uses. (See for example http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmform95/htm/readerobject.asp). And since the handling of an unknown &amp;quot;msg&amp;quot; is uniform, it allows a limited form of forwards compatability as well.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
Interfaces that are intended to be shared amongst plugins are defined specially in Wasabi. An interface is derived from Dispatchable and defines a set of dispatch messages which make up the particular interface.  Depending on its use, an interface's classname will be given one of the following prefixes&lt;br /&gt;
&lt;br /&gt;
* api - For singleton APIs.  Examples of APIs are the Service Manager and the System Callbacks API.&lt;br /&gt;
* ifc - For interfaces.  These are given to Dispatchable classes which are not involved with the service manager.  These are typically used for passing objects to other objects or for accepting objects as return values.&lt;br /&gt;
* svc - For collective services.  These are services which are one of many classes which implement an interface.  Examples include image loading services and playlist loading services.&lt;br /&gt;
* obj - For objects.  These are classes which are created by the service factory on getInterface() and destroyed on releaseInterface().  Examples of objects are instances of the XML Parser and the JNetLib http retriever.&lt;br /&gt;
&lt;br /&gt;
=== Example === &lt;br /&gt;
The interface for a &amp;quot;Region&amp;quot; (a shape that defines a portion of a window, usually used for painting)&lt;br /&gt;
&lt;br /&gt;
 class ifc_region : public Dispatchable&lt;br /&gt;
 {&lt;br /&gt;
 public:&lt;br /&gt;
  int _dispatch(int msg, void *retval, void **params=NULL, int nparam=0);&lt;br /&gt;
 &lt;br /&gt;
  enum&lt;br /&gt;
  {&lt;br /&gt;
  REGION_GETOSHANDLE =50,&lt;br /&gt;
  REGION_CLONE =100,&lt;br /&gt;
  REGION_DISPOSECLONE =110,&lt;br /&gt;
  REGION_PTINREGION =120,&lt;br /&gt;
  REGION_OFFSET =130,&lt;br /&gt;
  REGION_GETBOX =140,&lt;br /&gt;
  REGION_SUBTRACTRGN =150,&lt;br /&gt;
  REGION_SUBTRACTRECT =160,&lt;br /&gt;
  REGION_ADDRECT =170,&lt;br /&gt;
  REGION_ADD =180,&lt;br /&gt;
  REGION_AND =190,&lt;br /&gt;
  REGION_SETRECT =200,&lt;br /&gt;
  REGION_EMPTY =210,&lt;br /&gt;
  REGION_ISEMPTY =220,&lt;br /&gt;
  REGION_EQUALS =230,&lt;br /&gt;
  REGION_ENCLOSED =240,&lt;br /&gt;
  REGION_INTERSECTRGN =250,&lt;br /&gt;
  REGION_DOESINTERSECTRGN =251,&lt;br /&gt;
  REGION_INTERSECTRECT =260,&lt;br /&gt;
  REGION_ISRECT =270,&lt;br /&gt;
  REGION_SCALE =280,&lt;br /&gt;
  REGION_DEBUG =290,&lt;br /&gt;
  REGION_MAKEWNDREGION =300,&lt;br /&gt;
  REGION_GETNUMRECTS =310,&lt;br /&gt;
  REGION_ENUMRECT =320,&lt;br /&gt;
  };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Typically, the Dispatchable classes define non-virtual methods corresponding to each dispatch message. The implementation of these methods are to simply pack the parameters into an array and call _dispatch.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 inline void Region::offset(int x,int y)&lt;br /&gt;
 {&lt;br /&gt;
  void *params[2] = {&amp;amp;x, &amp;amp;y};&lt;br /&gt;
  _dispatch(REGION_OFFSET, NULL, params,2);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The purpose of these methods are to allow the interface to be used without having to think about the Dispatchable interface. Once the interface is defined and the helper methods are written you can totally forget about Dispatchable.&lt;br /&gt;
&lt;br /&gt;
Interfaces allow for an object to be shared amongst Winamp and plugins. For example, since api_region is defined, you may call the function api_region *GetUpdateRegion(); and use the returned object safely.&lt;br /&gt;
Services&lt;br /&gt;
&lt;br /&gt;
== Services ==&lt;br /&gt;
&lt;br /&gt;
In Wasabi, a service is an object that implements functionality that Winamp or other plugins may require. For example, the image loader service loaded decompresses an image. The memory manager service acts as a common malloc/free, so that memory allocated in one plugin can be freed safely in another.&lt;br /&gt;
&lt;br /&gt;
Services use Interfaces. The GetUpdateRegion example in the Interfaces section described using interfaces to define an object returned from a function. But how does a plugin call a function in Winamp in the first place? That's where services come in.&lt;br /&gt;
&lt;br /&gt;
Services are retrieved through api_service, an interface which is passed to each plugin as it is loaded. api_service acts as a &amp;quot;global store&amp;quot; of services. Plugins can retrieve other services and register their own services.&lt;br /&gt;
&lt;br /&gt;
There are two basic kinds of services, '''''unique''''' services and '''''collective''''' services.&lt;br /&gt;
&lt;br /&gt;
A collective service is an interface which implements a particular service type. Typically, this is a service that has to be implemented differently depending on use. For example, a PNG loading service would be part of the WaSvc::IMAGELOADER service type, and would be a different object from other WaSvc::IMAGELOADER services (such as a JPG loader). File readers are another example: direct file access could be implemented separately from HTTP access, ZIP file access, etc. Clients (Winamp or plugins) can enumerate through all the services of a particular type, to find one that fits its needs.&lt;br /&gt;
&lt;br /&gt;
Unique services are one-off interfaces. They have a service type of WaSvc::UNIQUE. Rather than checking for a particular service type, a client asks for a particular service by GUID. A memory manager service would be a unique service. Typically, unique services are used to provide some sort of system access, or to perform some sort of very specific task.&lt;br /&gt;
&lt;br /&gt;
== Service Factories ==&lt;br /&gt;
&lt;br /&gt;
Services are retrieved via Service Factories. api_service operates with service factories, and plugins must provide service factories for the services they implement. Service Factories create objects of your service whenever requested by a client.&lt;br /&gt;
&lt;br /&gt;
Although the factory is annoying to deal with (just another layer to get to what you want), it allows for the developer to control object creation. Most unique services (and some collective services) are singletons. That is, there only needs to be one of them in existance at any point in time. The same object pointer may be returned every time from the factory.&lt;br /&gt;
&lt;br /&gt;
Other services might be need to be uniquely created for each client. Each file reader, for example, will need a separate object, since state is stored in the file reader object.&lt;br /&gt;
&lt;br /&gt;
Services are released through the factory that created them, allowing the factory to control destruction as well as construction.&lt;br /&gt;
&lt;br /&gt;
== System Callbacks ==&lt;br /&gt;
Not technically part of the the api/interface/services infrastructure within Wasabi. System Callbacks (api_syscb), is a service which broadcasts messages to any callback receiver (a class dervied from SysCallback) that has registered itself with the System Callbacks service.&lt;br /&gt;
&lt;br /&gt;
Service registration and deregistration messages are broadcasted by api_service, so api_syscb is guaranteed to be an available service (because it must be created for api_service to operate).&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/The_Base_Skin</id>
		<title>The Base Skin</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/The_Base_Skin"/>
				<updated>2008-09-25T13:08:46Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;The Base Skin&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Classic Skin:  [[The Base Skin]] --&amp;gt; [[Main|Paint the Main Window]] --&amp;gt; [[Equalizer|Paint the Equalizer Window]] --&amp;gt; [[Playlist|Paint the Playlist Window]] --&amp;gt; [[Mini-browser|Paint the Minibrowser Window]] --&amp;gt; [[AVS|Paint the AVS Window]] --&amp;gt; [[For_Winamp_2.9/5.x|Paint the Winamp 2.9/5.x Windows]] --&amp;gt; [[Creating Custom Cursors|Create Custom Cursors]] --&amp;gt; [[Editing the Configuration Files|Edit the Configuration Files]] --&amp;gt; [[WSZ Files|Compress to .WSZ format]] --&amp;gt; [[Submitting Your Skin to Winamp.com|Submit to Winamp.com]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=The Winamp Base Skin=&lt;br /&gt;
The Base Skin is a copy of the default skin built into Winamp. All you have to do to skin Winamp is paint over or replace a skin component with your own design and voila, your own personalized version of Winamp. You can replace any or all of the components in a skin. Anything you don't replace will use its Base Skin counterpart. Naturally the Base Skin components will look out of place, so we suggest changing every file.&lt;br /&gt;
&lt;br /&gt;
=The Base Skin Breakdown=&lt;br /&gt;
&lt;br /&gt;
The Base Skin can be split into 6 logical segments which consist of the following files:&lt;br /&gt;
&lt;br /&gt;
1) [[Main]]:&lt;br /&gt;
      Main.bmp: Main Frame&lt;br /&gt;
      Titlebar.bmp: Titlebar&lt;br /&gt;
      Cbuttons.bmp: Control Buttons&lt;br /&gt;
      Shufrep.bmp: Shuffle and Repeat Buttons&lt;br /&gt;
      Volume.bmp: Volume Bar&lt;br /&gt;
      Balance.bmp: Balance Bar&lt;br /&gt;
      Monoster.bmp: Mono/ Stereo Indicators&lt;br /&gt;
      Posbar.bmp: Position Bar&lt;br /&gt;
      Playpaus.bmp: Play/Paused Indicators&lt;br /&gt;
      Numbers.bmp: Digit Reference&lt;br /&gt;
      Text.bmp: Text Reference&lt;br /&gt;
2) [[Equalizer]]:&lt;br /&gt;
      Eqmain.bmp: Equalizer Main Frame&lt;br /&gt;
      Eq_ex.bmp: Equalizer Window Shade Bar&lt;br /&gt;
3) [[Playlist]]:&lt;br /&gt;
      Pledit.bmp: Playlist Editor Frame/Buttons&lt;br /&gt;
4) [[Mini-browser]]:&lt;br /&gt;
      Mb.bmp: Mini-browser Frame&lt;br /&gt;
5) [[AVS]]:&lt;br /&gt;
      Avs.bmp: AVS Frame&lt;br /&gt;
6) [[For Winamp 2.9/5.x]]: (Thanks to Jellby)&lt;br /&gt;
      Video.bmp: Video Window&lt;br /&gt;
      Gen.bmp: General Purpose Window&lt;br /&gt;
      Genex.bmp: General Purpose Buttons and Sliders&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/System_Callbacks_API</id>
		<title>System Callbacks API</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/System_Callbacks_API"/>
				<updated>2008-09-25T13:08:38Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;System Callbacks API&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;api/syscb/api_syscb.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/SendMessage_API</id>
		<title>SendMessage API</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/SendMessage_API"/>
				<updated>2008-09-25T13:08:20Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;SendMessage API&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Include files: &lt;br /&gt;
:Winamp/wa_ipc.h&lt;br /&gt;
:Winamp/ipc_pe.h&lt;br /&gt;
&lt;br /&gt;
Although Winamp provides input plugins with a number of function pointers to make calls into Winamp, there are simply too many functions in the Winamp SDK to reasonably provide that for every available function.  The API was expanded by means of special window messages that could be sent to the main winamp window.  Although the API was built this was largely as an historical accident, but this part of API continues to gain new features as it has a number of advantages despite its quirks.&lt;br /&gt;
A plugin can call a &amp;quot;function&amp;quot; in Winamp by passing a message with msg id == WM_WA_IPC (defined in Winamp/wa_ipc.h).  The lParam value determines what function to call and the wParam contains a parameter relevant to the function (often a pointer to a struct in case multiple parameters are needed).  These function calls are referred to as IPC's (inter-plugin communication) Despite the quirkiness and the odd reminiscence to DOS interrupt function calls, it does offer two major advantages:&lt;br /&gt;
&lt;br /&gt;
# Windows automatically runs the SendMessage response on the &amp;quot;main&amp;quot; application thread, allowing plugins to make SendMessage calls on other threads safely.&lt;br /&gt;
# *this is important, this is how a lot of stuff gets done by plugins* - By subclassing the main Winamp window, a plugin can alter Winamp's handling of various API calls.  This has become such a popular method used by plugin developers that Winamp often sends messages to itself as a way to notify plugins about various events.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Playlist</id>
		<title>Playlist</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Playlist"/>
				<updated>2008-09-25T13:06:50Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Playlist&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Classic Skin:  [[The Base Skin]] --&amp;gt; [[Main|Paint the Main Window]] --&amp;gt; [[Equalizer|Paint the Equalizer Window]] --&amp;gt; [[Playlist|Paint the Playlist Window]] --&amp;gt; [[Mini-browser|Paint the Minibrowser Window]] --&amp;gt; [[AVS|Paint the AVS Window]] --&amp;gt; [[For_Winamp_2.9/5.x|Paint the Winamp 2.9/5.x Windows]] --&amp;gt; [[Creating Custom Cursors|Create Custom Cursors]] --&amp;gt; [[Editing the Configuration Files|Edit the Configuration Files]] --&amp;gt; [[WSZ Files|Compress to .WSZ format]] --&amp;gt; [[Submitting Your Skin to Winamp.com|Submit to Winamp.com]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Skinning the Playlist Window==&lt;br /&gt;
&lt;br /&gt;
Check it out, it's the playlist window:&lt;br /&gt;
&lt;br /&gt;
[[Image:Pl.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Despite being made from only one image file, the Playlist skin is actually fairly complex due to the fact that it is a fully resizable window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Pledit.gif]]&lt;br /&gt;
&lt;br /&gt;
'''pledit.bmp'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The explanation for this window is fairly complicated due to the randomness of the various components layed out through out the image, so please bear with me.&lt;br /&gt;
&lt;br /&gt;
The top section is fairly straightforward. The upper left image is the top left corner of the Playlist window. This is then followed by the graphic that creates the title for the Playlist window, please remember that this title is always centered within the Playlist Editor window. To it's right is a little part of the titlebar which is tiled all across for every time the window is stretched more and more horizontally. Next would be the default state for the WindowShade mode and close buttons, which is then followed by a graphic which spans two rows, this is a graphic for the bottom edge of the Playlist window which is also tiled as the window is stretched horizontally. Finally to the right of that is a fairly large graphic which once again spans two rows. This graphic is the background for the secondary Visualization area. This area only comes to life when the Winamp Main Window has been disabled.&lt;br /&gt;
&lt;br /&gt;
The next row contains the same set of graphics except that they are the variation that is displayed when the Playlist editor does not have focus, or is the inactive window.&lt;br /&gt;
&lt;br /&gt;
The first two graphics in this next row are for the vertical stretching of the Playlist editor window. The leftmost graphic is for the left side of the Playlist window, and the one to its right allows the right side of the editor to stretch. To the right of those two graphics are the images for the clicked version of the close button with the clicked version of the WindowShade button to its right. Directly beneath those buttons are the un-clicked and clicked versions of the Playlist editor's vertical scrollbar button. To the right of those button images are the graphics necessary for the WindowShade mode of the Playlist Editor.&lt;br /&gt;
&lt;br /&gt;
There are two rows of images that compose the WindowShade mode. The top set of images make up the leftmost side of the WindowShaded version of the Playlist Editor, followed by the rightmost part of the editor. Directly beneath the image that makes the left side is the graphic necessary for the stretching of the WindowShaded Playlist window. To the right of that is the inactive version of the right side of the editor.&lt;br /&gt;
&lt;br /&gt;
Beneath the WindowShade mode graphics are two fairly large graphics that create the bottom side of the Playlist Editor window while in non-WindowShade mode. The left one consists of button controls for the Playlist Editor when not in use. The right graphic is the image for the right side of the Playlist with the time displays, player controls, as well as the window resizing control.&lt;br /&gt;
&lt;br /&gt;
The next set of graphics are all the buttons in both states, pressed and not pressed, that allow you to modify the Playlist. They are all self explanatory in what they do. These images are individually layed over the Playlist window. Note: transparencies are not supported.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_XML_Intro</id>
		<title>Modern Skin: XML Intro</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_XML_Intro"/>
				<updated>2008-09-25T13:06:45Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: XML Intro&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In this section, I will give a short introduction to XML. You may ask: what does XML have to do with Winamp? Well, XML is fully implemented in Winamp. From the skinning files to the playlist, it's all XML based. I will go over XML basics in this section. If you know XML, go ahead and skip to the [[Modern_Skin:_Simple_Skin_Tutorial_(Continued)|next section]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==So What is XML?==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
XML stands for ''e'''X'''tensible '''M'''arkup '''L'''anguage'' ('''XML'''). You hear about XML everywhere. We're going to give you a quick and dirty guide to XML and its relevance to Winamp. XML is just like HTML. If you know HTML, you can pick up XML very quickly. So don't be afraid.&lt;br /&gt;
&lt;br /&gt;
HTML and XML are from the same family of what is called '''SGML''' ('''''S'''tandard '''G'''eneralized '''M'''arkup '''L'''anguage''). SGML was invented as a text-based language that can be used to '''mark up''' data - that is, add metadata - in a way that is '''self describing'''. What does this mean? Basically SGML is a way for programmers to transfer and display information. The best known application of SGML is ''HyperText Markup Language'', or '''HTML'''. HTML is a universal markup language for the display of information and the linking of different pieces of information. The idea was that any HTML document (or web page) would be presentable in any application that was capable understanding HTML (namely a '''web browser''').&lt;br /&gt;
&lt;br /&gt;
Although HTML has been incredbly successful, it's also limited in its scope: it is only intended for displaying documents in a browser. It is not particularly useful as a medium to convey information to other programs. Don't understand? Here let me give you an example.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''For example'', if I want to tell everyone my name, there are many ways I can do this:&lt;br /&gt;
&lt;br /&gt;
'''a)''' I can create a text file on a computer that look like this. When I send you this text file, you can read it or write a program to parse it. By reading &amp;quot;Ken Chen&amp;quot; in the text file, you can guess that it's my name. But then again, are you sure? It's not really clear, right? Lets look at the next example.&lt;br /&gt;
&lt;br /&gt;
Ken Chen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''b)''' For the web, I can create an HTML file like this. I can put it on a web site and you can see the page in your browser. Once again, by just reading &amp;quot;Ken Chen&amp;quot; you're not really sure that it's my name.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;HTML&amp;gt;&lt;br /&gt;
   &amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;Name&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&lt;br /&gt;
   &amp;lt;BODY&amp;gt;&lt;br /&gt;
     &amp;lt;nowiki&amp;gt;&amp;lt;P&amp;gt;Ken Chen&amp;lt;/P&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   &amp;lt;/BODY&amp;gt;&lt;br /&gt;
 &amp;lt;/HTML&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''c)''' XML is a standard for conveying information. I might create an XML file like this. Looking at this file, you can see that it looks very much like an HTML file. The style is very similar. The difference is that in XML, you can design or come up with any tag you want to convey the information you want. Reading this simple example, you can tell that my first name is Ken and my last name is Chen.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Name&amp;gt;&lt;br /&gt;
   &amp;lt;First&amp;gt;Ken&amp;lt;/First&amp;gt;&lt;br /&gt;
   &amp;lt;Last&amp;gt;Chen&amp;lt;/Last&amp;gt;&lt;br /&gt;
 &amp;lt;/Name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From this simple example you can see why markup language like SGML and XML are called self-describing. Looking at the data, you can easily tell that this is information about a &amp;lt;'''name'''&amp;gt; and you can see that there is data called &amp;lt;'''first'''&amp;gt; and another data called &amp;lt;'''last'''&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''d)''' You could write a shorter version of the previous XML by using element attributes. like so:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Name First=&amp;quot;Ken&amp;quot; Last=&amp;quot;Chen&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and it could equate to the one in C, if the Name element had those attributes (first and last). The reason for this is that you get tired of typing open and closing tags. Once you open a tag, you can have attributes for that tag. Many Winamp3 skin XML files are in this style. Here's an example from the Default skin.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;button&lt;br /&gt;
   id=&amp;quot;Previous&amp;quot;&lt;br /&gt;
   action=&amp;quot;prev&amp;quot;&lt;br /&gt;
   x=&amp;quot;0&amp;quot; y=&amp;quot;0&amp;quot;&lt;br /&gt;
   image=&amp;quot;player.button.previous&amp;quot;&lt;br /&gt;
   downImage=&amp;quot;player.button.previous.pressed&amp;quot;&lt;br /&gt;
   tooltip=&amp;quot;Previous&amp;quot;&lt;br /&gt;
 /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==XML Hierarchy==&lt;br /&gt;
&lt;br /&gt;
The beauty of XML is that you can design whatever format you want to describe your data. The key is that you follow the XML hierarchy (we'll describe in the next section. Other than that, make sure you close the tag when you open one. (ie: make sure you have &amp;lt;/'''name'''&amp;gt; if you open a &amp;lt;'''name'''&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
XML has a hierarchy that you need to follow. This is much like the HTML code where you embed a tag within a tag. By doing that, you're creating another level in the hierarchy. Make sure you close your tags correctly. Check out this example.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Winamp Employee&amp;gt;&lt;br /&gt;
   &amp;lt;Name&amp;gt;&lt;br /&gt;
     &amp;lt;First&amp;gt;Ken&amp;lt;/First&amp;gt;&lt;br /&gt;
     &amp;lt;Last&amp;gt;Chen&amp;lt;/Last&amp;gt;&lt;br /&gt;
   &amp;lt;/Name&amp;gt;&lt;br /&gt;
   &amp;lt;Email&amp;gt;Ken@Winamp.com&amp;lt;/Email&amp;gt;&lt;br /&gt;
   &amp;lt;Location&amp;gt;San Francisco, CA&amp;lt;/Location&amp;gt;&lt;br /&gt;
 &amp;lt;/Winamp Employee&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Xml.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In this example, we have &amp;lt;'''Name'''&amp;gt;, &amp;lt;'''Email'''&amp;gt; and &amp;lt;'''Location'''&amp;gt; as level 1 tags. Within the &amp;lt;'''Name'''&amp;gt; tag, we have two level 2 tags: &amp;lt;'''First'''&amp;gt; and &amp;lt;'''Last'''&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==XML &amp;amp; Winamp==&lt;br /&gt;
&lt;br /&gt;
XML is basically a way to store data. Now we've shown you what XML is, you may ask: what does that have to do with Winamp? Well, XML is fully implemented in Winamp. From the skinning files to the playlist, it's all XML based. I've gone over the basics of XML. I'll go over Winamp XML elements and dissect apart a simple skin example in the [[Modern_Skin:_Simple_Skin_Tutorial_(Continued)|next section]].&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Skin_Scripting</id>
		<title>Modern Skin: Skin Scripting</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Skin_Scripting"/>
				<updated>2008-09-25T13:06:37Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Skin Scripting&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Here are some quick notes on Winamp's modern skins scripting engine (called MAKI) to get you started:&lt;br /&gt;
&lt;br /&gt;
*MAKI stands for Make A Killer Interface.&lt;br /&gt;
*MAKI is a scripting engine for creating custom behavior from a Wasabi skin and set of components.&lt;br /&gt;
*MAKI scripts are precompiled into cross-platform bytecode. This means that the set of skin XML, elements and compiled scripts are completely cross-platform.&lt;br /&gt;
*Scripts can attach to any event of any object in the UI. Scripts can be loaded and unloaded in any order. &lt;br /&gt;
&lt;br /&gt;
For more about MAKI, please read the MAKI Overview.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''MAKI Script Organization'''&lt;br /&gt;
&lt;br /&gt;
Before we go over MAKI code, I'd like to go over the overall flow of a MAKI script. Please refer to the picture below. It shows what a typical MAKI script should look like.&lt;br /&gt;
&lt;br /&gt;
*Part 1: Script Comments&lt;br /&gt;
*Part 2: #include Section&lt;br /&gt;
*Part 3: Variable Declaration&lt;br /&gt;
*Part 4: system.onUnloading() Section&lt;br /&gt;
*Part 5: system.onScriptLoaded() Section&lt;br /&gt;
*Part 6: Your own functions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:MAKI Script Organization.png]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Relative_Positioning</id>
		<title>Modern Skin: Relative Positioning</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Relative_Positioning"/>
				<updated>2008-09-25T13:06:23Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Relative Positioning&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What is Relative Positioning?==&lt;br /&gt;
&lt;br /&gt;
===A. Introduction===&lt;br /&gt;
Modern Winamp skinning offers unparalleled flexibility in element placement. You're no longer restricted to specifying X&amp;amp;Y coordinates for an element. Instead, you can define the position of the element relative to your component. When the component resizes, the element will stretch or move with the component. This flexibility frees the skin designer from the hassel of retooling or redrawing the graphic assets over and over again to different size and width. Winamp will do that for you. =)&lt;br /&gt;
&lt;br /&gt;
===B. Add relativepos.xml to your SimpleTutorial ===&lt;br /&gt;
&lt;br /&gt;
For this section, I have made another XML file called &amp;quot;relativepos.xml&amp;quot; that you need to include in your SimpleTutorial skin. Download the relativepos.xml here.(Please right-click on the link and choose 'Save As...' or 'Save Link Target As...')&lt;br /&gt;
&lt;br /&gt;
Place this file in the same directory as your SimpleTutorial skin directory. For most people, the path is &amp;quot;C:\Program Files\Winamp\Skins\SimpleTutorial&amp;quot;. Add this line to your Skin.xml in SimpleTutorial:&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos_include.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is what your skin.xml should look like after the change: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos_skinxml.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==RelativePos.xml==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:rpos_xmlcode1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Relativepos.xml uses elements from the SimpleTutorial skin. I am using the &amp;quot;blue-vis-layer.png&amp;quot; and &amp;quot;red-vis-layer.png&amp;quot; in the Player directory. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos xmlcode2.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Blue-vis-layer.png]]&lt;br /&gt;
[[Image:Red-vis-layer.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Relative Position 1: Defining X&amp;amp;Y Coordinates==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos xmlcode3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===A. Register_autopopup=&amp;quot;1&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
Before we delve into the code, I want to go over one feature. Take a look at this tag: [[Image:Rpos autopopup.png]]. When you add this tag to a groupdef, Winamp automatically wraps a container and layout around it and allow you to see the group in a separate window. This is particularly useful when you want to test the behavior of that group separate from everything else. To open that window, right click on the Main Player to bring up the menu. Go to the &amp;quot;Windows&amp;quot; submenu and you'll see the extra windows relativepos.xml has created. Open them up and try them out.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos menu.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===B. Defining X&amp;amp;Y Coordinates===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Line 11-19 defines a group with a &amp;quot;blue-vis&amp;quot; layer at the coordinate of (20,30). This is probably what you've been doing all along. As you can see, that the blue-vis layer's location doesn't change if you resize the window. The position is fixed. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos1 small.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; Small size window&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos1 big.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; Large size window; Blue-vis layer position did not change&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I encourage you to play with this XML file. If you change the X&amp;amp;Y coordinates on line 14 to (-20, -30), your blue-vis layer will disappear. The reason is that the coordinate specified will be outside the context of your component window and therefore will not be rendered. &lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos1 left.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Relative Position 2: Specify the Height and Width==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos xmlcode4.png]]&lt;br /&gt;
&lt;br /&gt;
In group 2, we're defining the height and width of the blus-vis layer that is larger than the image. When you do that, Winamp will stretch the image to that size. Likewise, if you specify height or width that is smaller than the image, Winamp will shrink the image to fit to that size. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos2 1.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; RPOS1 window: Height and Width not specified&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos2 2.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;* RPOS2 window: Height and Width defined&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Relative Position 3: RelatX &amp;amp; Negative X Coordinate==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos xmlcode5.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Line 30-39 defines a group with a &amp;quot;blue-vis&amp;quot; layer at the coordinate of (-120,30). Notice that we have an extra line on line 34: &amp;quot;relatx=1&amp;quot;. By setting relatx to 1, you're telling Winamp to start the x-coordinate from the right edge of the window. Note that the X-Coordinate should be negative; otherwise the blue-vis layer will not show up.&lt;br /&gt;
&lt;br /&gt;
This is a convenient feature if you want an element stick to a specific distance relative to the right edge of the window. Notice that when I resize the window, the blue-vis layer stays fixed distance relative to the right edge of the window. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos3 small.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; RPOS3 window with relatx=1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos3 big.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; RPOS3 window with relatx=1: window resized&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos3 right.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; RPOS3 window with relatx=1; coordinate (20,20)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Relative Position 4: RelatY &amp;amp; Negative Y Coordinate==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos xmlcode6.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Line 40-49 defines a group with a &amp;quot;blue-vis&amp;quot; layer at the coordinate of (20,-80). Notice theline on line 44: &amp;quot;relaty=1&amp;quot;. By setting relaty to 1, you're telling Winamp to start the y-coordinate from the bottom edge of the window. Note that the Y-Coordinate should be negative; otherwise the blue-vis layer will not show up.&lt;br /&gt;
&lt;br /&gt;
This is a convenient feature if you want an element stick to a specific distance relative to the bottom edge of the window. Notice that when I resize the window, the blue-vis layer stays fixed distance relative to the bottom edge of the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos4 small.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; RPOS4 window with relaty=1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos4 big.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; RPOS4 window with relaty=1: window resized&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos4 bottom.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; RPOS4 window with relaty=1: coordinate (20,50)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Relative Position 5: Relatw and RelatH==&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos xmlcode7.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Line 50-72 demonstrate the use of relath and relatw. From the beginning of this section we know that by defining height and width different from the original image size, Winamp will automatically stretch or shrink the image to fit that size constraint. What is powerful (and awesome) about modern skins is that you can also tell Winamp to adjust the height and width of an element with respect to the right and bottom edge of the window. This is accomplished through &amp;quot;relath&amp;quot; and &amp;quot;relatw&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In our example, we defined a blue-vis group (lines 52-60) and a red-vis group that encompasses the blue-vis group (lines 63-72). The blue-vis group is defined with no preset x, y, h or w because we will define them on line 71.&lt;br /&gt;
&lt;br /&gt;
The magic happens on line 71. With relath set to 1 and relatw set to 1, we're telling Winamp to stretch or shrink the blue-vis layer so that it is 50 pixels away from the right and bottom edge of the window. The blue-vis layer is stretched and the distance is maintained as I expanded the size of the window. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos5 small.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; RPOS5 window with relath=1 and relatw=1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Rpos5 big.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt;RPOS5 window with relath=1 and relatw=1; window resized; Blue-vis layer stretched&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Layer_Composition</id>
		<title>Modern Skin: Layer Composition</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Layer_Composition"/>
				<updated>2008-09-25T13:06:09Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Layer Composition&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Layer composition is the process by which several images lay on top of each other to produce a complex graphical visualization. It is similar to layers in Photoshop.&lt;br /&gt;
&lt;br /&gt;
The process is:&lt;br /&gt;
&lt;br /&gt;
#produce the images and save them in a file&lt;br /&gt;
#define an element to represent that image in your XML&lt;br /&gt;
#make a layer using that element&lt;br /&gt;
#if you put layers in same area, they will lay on top of each other based on the ordering of the xml code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Complex Tutorial'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Complexskin diag layercomp.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In Complex Tutorial, Group #1 (the first circle from the left), has blue triangle on top of the red circle. This is done through layer composition. Here's the process.&lt;br /&gt;
&lt;br /&gt;
*Make the graphics: the red circle and blue triangle.&lt;br /&gt;
*Define the elements in the XML code.&lt;br /&gt;
*Define layers using those elements.&lt;br /&gt;
*Place the layers in the same area.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lets go through in detail how do to each step:&lt;br /&gt;
&lt;br /&gt;
==Make the graphics: The Red Circle and Blue Triangle.==&lt;br /&gt;
&lt;br /&gt;
red-circle.png &amp;amp;nbsp;&amp;amp;nbsp; [[Image:Red-circle.png]]&lt;br /&gt;
&lt;br /&gt;
triangle.png &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;  [[Image:Triangle.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Define the Elements in the XML Code==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Layercomp xml.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Define Layers Using those Elements==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Layercomp xml2.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Layercomp xml3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Place the Layers in the Same Area==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Layercomp xml4.png]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Drawers</id>
		<title>Modern Skin: Drawers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Drawers"/>
				<updated>2008-09-25T13:05:54Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Drawers&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A Drawer is an animated layer that is normally hidden but can be shown when triggered by a user event (often a mouse click).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Flash3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Complex Tutorial Modern Skin'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In Complex Tutorial, Group #3 shows a triangle that slides out when you click on it. This group demonstrates the concept of a drawer. We will go over the XML code in this section. The script explaination is covered in the next section. Here's the process.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lets go through in detail how do to each step&lt;br /&gt;
&lt;br /&gt;
==Make the Graphics: Rotating Arrow==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
red-circle.png &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; [[Image:Red-circle.png]]&lt;br /&gt;
&lt;br /&gt;
triangle-clickme.png &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;  [[Image:Triangle-clickme.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Define the Elements in the XML Code==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Drawer xml1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Define Layers using those Elements==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Drawer xml1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Making MAKI Script==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Two MAKI scripts function together to create the animations you see. Triangle.maki animates the sliding effect of the drawer. Anim.maki animates the moving arrow. We will go over the MAKI script for drawer in the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting trianglemaki1.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting trianglemaki2.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting trianglemaki3.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting trianglemaki4.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting trianglemaki5.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting trianglemaki6.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; Triangle.m MAKI file for Complex Tutorial Skin&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting animmaki1.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting animmaki2.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting animmaki3.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting animmaki4.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting animmaki5.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Scripting animmaki6.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; Anim.m MAKI file for Complex Tutorial Skin&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Complex_Skin</id>
		<title>Modern Skin: Complex Skin</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Complex_Skin"/>
				<updated>2008-09-25T13:05:45Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Complex Skin&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In section 3, I will show how to make a more complicated skin and teach you advanced Modern Winamp skin concepts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Complexskin diag.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Complex Tutorial Modern Skin'''&lt;br /&gt;
&lt;br /&gt;
We're going to show you how to make a simple skin like the one shown below. Download the &amp;quot;[http://media.winamp.com/5541/main/downloads/development/skinsmodern/ComplexTutorial.wal Complex Tutorial Modern Skin]&amp;quot; example.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Flash.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you save the file, make sure that the type of the file is selected to &amp;quot;All Type&amp;quot; and NOT &amp;quot;Winzip&amp;quot; filetype. You should save the file into your skin subdirectory in your Winamp directory. For most people, that path is &amp;quot;C:\Program Files\Winamp\Skins&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Simpletutsave.png]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Modern_Skin:_Alpha_Channels</id>
		<title>Modern Skin: Alpha Channels</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Modern_Skin:_Alpha_Channels"/>
				<updated>2008-09-25T13:05:39Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Modern Skin: Alpha Channels&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Modern Skin --&amp;gt; [[Modern Skin: Intro|Intro]] --&amp;gt; [[Modern Skin: Winamp 2 to W3+|Winamp 2 to Winamp 3+]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial|Simple Skin Tutorial]] --&amp;gt; [[Modern Skin: XML Intro|XML Intro]] --&amp;gt; [[Modern Skin: Simple Skin Tutorial (Continued)|Simple Skin Tutorial (Continued)]] --&amp;gt; [[Modern Skin: Container| Container]] --&amp;gt; [[Modern Skin: Group|Group]] --&amp;gt; [[Modern Skin: Relative Positioning| Relative Positioning]] --&amp;gt; [[Modern Skin: Complex Skin|Complex Skin]] --&amp;gt; [[Modern Skin: Non-Rect Player| Non-Rect Player]] --&amp;gt; [[Modern Skin: Layer Composition| Layer Composition]] --&amp;gt; [[Modern Skin: Alpha Channels| Alpha Channels]] --&amp;gt; [[Modern Skin: Animatedlayer|Animatedlayer]] --&amp;gt; [[Modern Skin: Snap Points|Snap Points]] --&amp;gt; [[Modern Skin: Drawers|Drawers]] --&amp;gt; [[Modern Skin: Skin Scripting| Skin Scripting]] --&amp;gt; [[Modern Skin: Drawer Scripting| Drawer Scripting]] --&amp;gt; [[Modern Skin: Animating a Skin|Animating a Skin]] --&amp;gt; [[Modern Skin: Maki Overview| Maki Overview]] --&amp;gt; [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Alpha channel controls the transparency value of an element. By adjusting the alpha value of an element, you can make the element totally transparent or not transparent at all. Winamp3 blends that element with the background image if the transparency of that element is increased.&lt;br /&gt;
&lt;br /&gt;
Take a look at the two images below. Both images have a red rectangle layer on top of the Boxer skin. The red rectangle in the first image has no transparency: the result is an overlap of images. The second image uses alpha channel to create some transparency: the result is the blending of the red rectangle and the Boxer skin.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Layer-notblend.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; No transparency: images overlap.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Layer-blend.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; Some transparency: images blend.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Complex Tutorial'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Complexskin diag alpha.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In Complex Tutorial, Group #2 (the second circle from the left), has blue triangle blended with the red circle. This is done through Alpha Channel. Note that the graphical asset for this group is the same as the ones used to demonstrate Layer Composition. The only difference is that we adjusted the alpha value for the triangle in this section. Here's the process.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lets go through in detail how do to each step:&lt;br /&gt;
&lt;br /&gt;
==Make the Graphics: The Red Circle and Blue Triangle==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
red-circle.png &amp;amp;nbsp;&amp;amp;nbsp; [[Image:Red-circle.png]]&lt;br /&gt;
&lt;br /&gt;
triangle.png &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;  [[Image:Triangle.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Define the Elements in the XML Code==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Layercomp xml.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Define Layers Using those Elements==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Alpha xml1.png]]&lt;br /&gt;
&lt;br /&gt;
[[Image:Alpha xml2.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Place the Layers in the Same Area==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Alpha xml3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Change the Alpha Value for the Triangle==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Alpha xml4.png]]&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/MilkDrop_Preset_Authoring</id>
		<title>MilkDrop Preset Authoring</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/MilkDrop_Preset_Authoring"/>
				<updated>2008-09-25T13:05:31Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;MilkDrop Preset Authoring&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:Milkdrop.png|right|320px]]&lt;br /&gt;
== MILKDROP preset authoring guide ==&lt;br /&gt;
&lt;br /&gt;
Note that there is another, quite comprehensive, Preset Authoring Guide available on the web at http://www.milkdrop.co.uk/, which is continually updated and expanded through the hard work of a few dedicated preset authors.  Whereas this guide (the one you are currently viewing) gives the bare technical specifications for writing your own presets, the guide at milkdrop.co.uk 'starts at the beginning' and walks you through all of the mathematics and subtleties of 'rolling your own', explaining things in great detail.  The guide at milkdrop.co.uk is very highly recommended to anyone who wishes to learn more about creating their own presets.&lt;br /&gt;
&lt;br /&gt;
== About Presets ==&lt;br /&gt;
&lt;br /&gt;
When you watch MilkDrop, you are watching a series of Presets.  Each one has its own look and feel, draws the sound waves in a particular way, and has certain motions to it.  After some time, you will see a short blend transition, and then you will be watching a new preset.  &lt;br /&gt;
&lt;br /&gt;
A single 'preset' is a collection of parameters that tell MilkDrop how to draw the wave, how to warp the image around, and so on.  MilkDrop ships with over 100 built-in presets, each one having a distinct look and feel to it.  &lt;br /&gt;
    &lt;br /&gt;
Using MilkDrop's built-in &amp;quot;preset-editing menu&amp;quot; (the M key), you can edit presets on the fly, on-screen, from within the program.  You can make slight adjustments to existing presets, then save over them; or you can change lots of things, so the preset doesn't look anything like the original, and then save it under a new name.  You can even write insane new mathematical equations, of your own imagination, into your preset files and come up with things that MilkDrop has never done before!&lt;br /&gt;
    &lt;br /&gt;
Each preset is saved as a file with the &amp;quot;.milk&amp;quot; extension, so you can easily send them to your friends or post them on the web.  You can also go to http://www.nullsoft.com/free/milkdrop and then jump to the &amp;quot;preset sharing forum&amp;quot; to see what other people have come up with, or post your own cool, new presets.  milkdrop.co.uk/ is another great place to download collections of presets made by others like yourself.&lt;br /&gt;
&lt;br /&gt;
== Preset Authoring - Basic ==&lt;br /&gt;
&lt;br /&gt;
You can edit the properties of the current preset by hitting 'M', which brings up the &amp;quot;preset-editing menu&amp;quot;.  From this menu you can use the up and down arrow keys to select an item.  Press the RIGHT arrow key to move forward through the menu and select the item (note: you can also hit SPACE or RETURN to do this); ***press the LEFT arrow key to go back to the previous menu.***  &lt;br /&gt;
    &lt;br /&gt;
Pressing 'M' while the menu is already showing will hide the menu; pressing ESCAPE will do the same thing.  Press 'M' again to bring the menu back.    &lt;br /&gt;
&lt;br /&gt;
Once you've reached an item on the menu whose value can be edited, use the UP and DOWN arrow keys to increase or decrease its value, respectively.  Changes will register immediately.  Use PAGE UP and PAGE DOWN to increase the value more quickly.  Hold down SHIFT    and use the UP/DOWN arrow keys to change the value very slowly. Hit RETURN To keep the new value, or ESC to abort the change.&lt;br /&gt;
    &lt;br /&gt;
If the item you're editing is a text string, you can use the arrow keys to move around.  The Insert key can be used to toggle between insert and overtype modes.  You can hold shift and use the arrow keys (home, end, left, right) to make a selection, which will be identified by brackets [].  You can then use CTRL-C  or CTRL-X to copy or cut text.  CTRL-P pastes.  When finished editing, hit RETURN To keep the new string, or ESC to abort the change.&lt;br /&gt;
&lt;br /&gt;
You'll want to get into the habit of using SCROLL LOCK whenever you're making changes to a preset that you intend to save; &lt;br /&gt;
otherwise, MilkDrop is sure to move you along to a new (random) preset, over time.  When the menus are showing, the preset is&lt;br /&gt;
automatically temporarily locked, but BE CAREFUL - if you're not also using SCROLL LOCK, then 0.1 seconds after you hide the menu&lt;br /&gt;
to take a look at your new masterpiece, MilkDrop might load a random new preset on you, and you'd lose your changes!  And you &lt;br /&gt;
might then ask me: &amp;quot;how large is large?&amp;quot;  And I will tell you: &amp;quot;thirty.&amp;quot;&lt;br /&gt;
    &lt;br /&gt;
    There are also some hotkeys that will allow you to change certain&lt;br /&gt;
    common parameters to the current preset.  These are listed below.&lt;br /&gt;
    &lt;br /&gt;
    MOTION&lt;br /&gt;
        i/I - zoom in/out&lt;br /&gt;
        [ / ] - push motion to the left/right (dx)&lt;br /&gt;
        { / } - push motion up/down (dy)&lt;br /&gt;
        &amp;lt; / &amp;gt; - rotate left/right (rot)&lt;br /&gt;
        o/O - shrink/grow the amplitude of the warp effect&lt;br /&gt;
&lt;br /&gt;
    WAVEFORM&lt;br /&gt;
        W   - cycle through waveforms&lt;br /&gt;
        j/J - scale waveform down/up&lt;br /&gt;
        e/E - make the waveform more transparent/more solid&lt;br /&gt;
&lt;br /&gt;
    BRIGHTNESS **&lt;br /&gt;
        g/G - decrease, increase gamma (brightness) **&lt;br /&gt;
&lt;br /&gt;
    VIDEO ECHO effect **&lt;br /&gt;
        q/Q - scale 2nd graphics layer down/up **&lt;br /&gt;
        F - flip 2nd graphics layer (cycles through 4 fixed orientations) **&lt;br /&gt;
&lt;br /&gt;
    ** these keys only have an effect if you are running a &lt;br /&gt;
       MilkDrop 1-era preset.  In MilkDrop 2-era presets,&lt;br /&gt;
       these values are embedded in the shader, so you need&lt;br /&gt;
       to go into the composite shader and tweak the code.&lt;br /&gt;
&lt;br /&gt;
== Preset Authoring - Advanced ==&lt;br /&gt;
&lt;br /&gt;
This section describes how to use the 'per-frame' and 'per-vertex' equations to develop unique new presets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
=== PER-FRAME EQUATIONS ===&lt;br /&gt;
    &lt;br /&gt;
When you hit 'm' to show the preset-editing menu, several items&lt;br /&gt;
show up.  If you explore the sub-menus, you'll see that&lt;br /&gt;
all of the properties that make up the preset you're currently&lt;br /&gt;
viewing are there.  The values you can specify here (such as&lt;br /&gt;
zoom amount, rotation amount, wave color, etc.) are all static&lt;br /&gt;
values, meaning that they don't change in time.  For example, &lt;br /&gt;
take the 'zoom amount' option under the 'motion' submenu.  &lt;br /&gt;
If this value is 1.0, there is no zoom.  If the value is 1.01, &lt;br /&gt;
the image zooms in 1% every frame.  If the value is 1.10, the &lt;br /&gt;
image zooms in 10% every frame.  If the value is 0.9, the image &lt;br /&gt;
zooms out 10% every frame; and so on.&lt;br /&gt;
&lt;br /&gt;
However, presets get far more interesting if you can take these &lt;br /&gt;
parameters (such as the zoom amount) and animate them (make them &lt;br /&gt;
change over time).  For example, if you could take the 'zoom &lt;br /&gt;
amount' parameter and make it oscillate (vary) between 0.9 and &lt;br /&gt;
1.1 over time, the image would cyclically zoom in and out, in &lt;br /&gt;
time.&lt;br /&gt;
&lt;br /&gt;
You can do this - by writing 'per-frame' and 'per-vertex' &lt;br /&gt;
equations.  Let's start with 'per-frame' equations.  These are&lt;br /&gt;
executed once per frame.  So, if you were to type the following&lt;br /&gt;
equation in:&lt;br /&gt;
        &lt;br /&gt;
 zoom = zoom + 0.1*sin(time);&lt;br /&gt;
    &lt;br /&gt;
...then the zoom amount would oscillate between 0.9 and 1.1&lt;br /&gt;
over time.  (Recall from your geometry classes that sin()&lt;br /&gt;
returns a value between -1 and 1.)  The equation says: &amp;quot;take&lt;br /&gt;
the static value of 'zoom', then replace it with that value,&lt;br /&gt;
plus some variation.&amp;quot;  This particular equation would oscillate &lt;br /&gt;
(cycle) every 6.28 seconds, since the sin() function's &lt;br /&gt;
period is 6.28 (PI*2) seconds.  If you wanted it to make it &lt;br /&gt;
cycle every 2 seconds, you could use: &lt;br /&gt;
    &lt;br /&gt;
 zoom = zoom + 0.1*sin(time*3.14);&lt;br /&gt;
    &lt;br /&gt;
Now, let's say you wanted to make the color of the waveform&lt;br /&gt;
(sound wave) that gets plotted on the screen vary through time.&lt;br /&gt;
The color is defined by three values, one for each of the main&lt;br /&gt;
color components (red, green, and blue), each in the range 0 to 1&lt;br /&gt;
(0 is dark, 1 is full intensity).  You could use something like this:&lt;br /&gt;
    &lt;br /&gt;
 wave_r = wave_r + 0.5*sin(time*1.13);&lt;br /&gt;
 wave_g = wave_g + 0.5*sin(time*1.23);&lt;br /&gt;
 wave_b = wave_b + 0.5*sin(time*1.33);&lt;br /&gt;
    &lt;br /&gt;
It's nice to stagger the frequencies (1.13, 1.23, and 1.33) of&lt;br /&gt;
the sine functions for the red, green, and blue color components&lt;br /&gt;
of the wave so that they cycle at different rates, to avoid them&lt;br /&gt;
always being all the same (which would create a greyscale wave).&lt;br /&gt;
    &lt;br /&gt;
Here is a full list of the variables available for writing per-frame &lt;br /&gt;
equations:&lt;br /&gt;
    &lt;br /&gt;
    NAME       WRITABLE?  RANGE  DESCRIPTION&lt;br /&gt;
    ----       ---------  -----  -----------                                                                   &lt;br /&gt;
    zoom           yes    &amp;gt;0     controls inward/outward motion.  0.9=zoom out 10% per frame, 1.0=no zoom, 1.1=zoom in 10%&lt;br /&gt;
    zoomexp        yes    &amp;gt;0     controls the curvature of the zoom; 1=normal&lt;br /&gt;
    rot            yes           controls the amount of rotation.  0=none, 0.1=slightly right, -0.1=slightly clockwise, 0.1=CCW&lt;br /&gt;
    warp           yes    &amp;gt;0     controls the magnitude of the warping; 0=none, 1=normal, 2=major warping...&lt;br /&gt;
    cx             yes    0..1   controls where the center of rotation and stretching is, horizontally.  0=left, 0.5=center, 1=right&lt;br /&gt;
    cy             yes    0..1   controls where the center of rotation and stretching is, vertically.  0=top, 0.5=center, 1=bottom&lt;br /&gt;
    dx             yes           controls amount of constant horizontal motion; -0.01 = move left 1% per frame, 0=none, 0.01 = move right 1%&lt;br /&gt;
    dy             yes           controls amount of constant vertical motion; -0.01 = move up 1% per frame, 0=none, 0.01 = move down 1%&lt;br /&gt;
    sx             yes    &amp;gt;0     controls amount of constant horizontal stretching; 0.99=shrink 1%, 1=normal, 1.01=stretch 1%           &lt;br /&gt;
    sy             yes    &amp;gt;0     controls amount of constant vertical stretching; 0.99=shrink 1%, 1=normal, 1.01=stretch 1%             &lt;br /&gt;
    wave_mode      yes    0,1,2,3,4,5,6,7  controls which of the 8 types of waveform is drawn&lt;br /&gt;
    wave_x         yes    0..1   position of the waveform: 0 = far left edge of screen, 0.5 = center, 1 = far right&lt;br /&gt;
    wave_y         yes    0..1   position of the waveform: 0 = very bottom of screen, 0.5 = center, 1 = top&lt;br /&gt;
    wave_r         yes    0..1   amount of red color in the wave (0..1),&lt;br /&gt;
    wave_g         yes    0..1   amount of green color in the wave (0..1)    &lt;br /&gt;
    wave_b         yes    0..1   amount of blue color in the wave (0..1)    &lt;br /&gt;
    wave_a         yes    0..1   opacity of the wave (0..1) [0=transparent, 1=opaque]&lt;br /&gt;
    wave_mystery   yes    -1..1  what this parameter does is a mystery.  (honestly, though, this value does different things for each waveform; for example, it could control angle at which the waveform was drawn.)&lt;br /&gt;
    wave_usedots   yes    0/1    if 1, the waveform is drawn as dots (instead of lines)&lt;br /&gt;
    wave_thick     yes    0/1    if 1, the waveform's lines (or dots) are drawn with double thickness&lt;br /&gt;
    wave_additive  yes    0/1    if 1, the wave is drawn additively, saturating the image at white&lt;br /&gt;
    wave_brighten  yes    0/1    if 1, all 3 r/g/b colors will be scaled up until at least one reaches 1.0&lt;br /&gt;
    ob_size        yes    0..0.5 thickness of the outer border drawn at the edges of the screen every frame&lt;br /&gt;
    ob_r           yes    0..1   amount of red color in the outer border&lt;br /&gt;
    ob_g           yes    0..1   amount of green color in the outer border&lt;br /&gt;
    ob_b           yes    0..1   amount of blue color in the outer border&lt;br /&gt;
    ob_a           yes    0..1   opacity of the outer border (0=transparent, 1=opaque)&lt;br /&gt;
    ib_size        yes    0..0.5 thickness of the inner border drawn at the edges of the screen every frame&lt;br /&gt;
    ib_r           yes    0..1   amount of red color in the inner border                                   &lt;br /&gt;
    ib_g           yes    0..1   amount of green color in the inner border                                 &lt;br /&gt;
    ib_b           yes    0..1   amount of blue color in the inner border                                  &lt;br /&gt;
    ib_a           yes    0..1   opacity of the inner border (0=transparent, 1=opaque)                     &lt;br /&gt;
    mv_r           yes    0..1   amount of red color in the motion vectors&lt;br /&gt;
    mv_g           yes    0..1   amount of green color in the motion vectors&lt;br /&gt;
    mv_b           yes    0..1   amount of blue color in the motion vectors&lt;br /&gt;
    mv_a           yes    0..1   opacity of the motion vectors (0=transparent, 1=opaque)                     &lt;br /&gt;
    mv_x           yes    0..64  the number of motion vectors in the X direction&lt;br /&gt;
    mv_y           yes    0..48  the number of motion vectors in the Y direction&lt;br /&gt;
    mv_l           yes    0..5   the length of the motion vectors (0=no trail, 1=normal, 2=double...)&lt;br /&gt;
    mv_dx          yes    -1..1  horizontal placement offset of the motion vectors&lt;br /&gt;
    mv_dy          yes    -1..1  vertical placement offset of the motion vectors&lt;br /&gt;
    decay          yes    0..1   controls the eventual fade to black; 1=no fade, 0.9=strong fade, 0.98=recommended&lt;br /&gt;
    gamma          yes    &amp;gt;0     controls display brightness; 1=normal, 2=double, 3=triple, etc.&lt;br /&gt;
    echo_zoom      yes    &amp;gt;0     controls the size of the second graphics layer&lt;br /&gt;
    echo_alpha     yes    &amp;gt;0     controls the opacity of the second graphics layer; 0=transparent (off), 0.5=half-mix, 1=opaque&lt;br /&gt;
    echo_orient    yes    0,1,2,3 selects an orientation for the second graphics layer.  0=normal, 1=flip on x, 2=flip on y, 3=flip on both&lt;br /&gt;
    darken_center  yes    0/1    if 1, help keeps the image from getting too bright by continually dimming the center point&lt;br /&gt;
    wrap           yes    0/1    sets whether or not screen elements can drift off of one side and onto the other&lt;br /&gt;
    invert         yes    0/1    inverts the colors in the image&lt;br /&gt;
    brighten       yes    0/1    brightens the darker parts of the image (nonlinear; square root filter)&lt;br /&gt;
    darken         yes    0/1    darkens the brighter parts of the image (nonlinear; squaring filter)&lt;br /&gt;
    solarize       yes    0/1    emphasizes mid-range colors&lt;br /&gt;
    monitor        yes    any    set this value for debugging your preset code; if you hit the 'N' key, &lt;br /&gt;
                                    the value of 'monitor' will be posted in the upper-right corner of milkdrop.&lt;br /&gt;
                                    for example, setting &amp;quot;monitor = q3;&amp;quot; would let you keep an eye on q3's value.&lt;br /&gt;
        &lt;br /&gt;
    time           NO     &amp;gt;0     retrieves the current time, in seconds, since MilkDrop started running&lt;br /&gt;
    fps            NO     &amp;gt;0     retrieves the current framerate, in frames per second.&lt;br /&gt;
    frame          NO            retrieves the number of frames of animation elapsed since the program started&lt;br /&gt;
    progress       NO     0..1   progress through the current preset; if preset was just loaded, this is closer to 0; if preset is about to end, this is closer to 1.&lt;br /&gt;
                                   -note that if Scroll Lock is on, 'progress' will freeze!&lt;br /&gt;
                   &lt;br /&gt;
    bass           NO     &amp;gt;0     retrieves the current amount of bass.  1 is normal; below ~0.7 is quiet; above ~1.3 is loud bass&lt;br /&gt;
    mid            NO     &amp;gt;0       -same, but for mids (middle frequencies)&lt;br /&gt;
    treb           NO     &amp;gt;0       -same, but for treble (high) frequencies&lt;br /&gt;
    bass_att       NO     &amp;gt;0     retrieves an attenuated reading on the bass, meaning that it is damped in time and doesn't change so rapidly.&lt;br /&gt;
    mid_att        NO     &amp;gt;0       -same, but for mids (middle frequencies)&lt;br /&gt;
    treb_att       NO     &amp;gt;0       -same, but for treble (high) frequencies&lt;br /&gt;
&lt;br /&gt;
    meshx          NO     8-128  tells you the user's mesh size in the X direction.  always an integer value.&lt;br /&gt;
    meshy          NO     6-96   tells you the user's mesh size in the Y direction.  always an integer value.&lt;br /&gt;
    pixelsx        NO     16-4096 width of the viz window, in pixels.  If Canvas Stretch is on, this is the pre-stretched size.  (same as &amp;quot;texsize.x&amp;quot; for shaders)&lt;br /&gt;
    pixelsy        NO     16-4096 height of the viz window, in pixels.  If Canvas Stretch is on, this is the pre-stretched size.  (same as &amp;quot;texsize.y&amp;quot; for shaders)&lt;br /&gt;
    aspectx        NO     &amp;gt;0     multiply an x-coordinate by this to make the preset look the same at any aspect (window height:width) ratio.&lt;br /&gt;
                                   -value: if widescreen, 1; if window is tall, h/w.&lt;br /&gt;
    aspecty        NO     &amp;gt;0     multiply a y-coordinate by this to make the preset look the same at any aspect (window height:width) ratio.&lt;br /&gt;
                                   -value: if widescreen, w/h; if window is tall, 1.&lt;br /&gt;
    &lt;br /&gt;
    blur1_min      yes    0..1   Normally these are set to 0 (min) and 1 (max).&lt;br /&gt;
    blur2_min      yes    0..1   You can clamp the values in the blur texture to a tighter&lt;br /&gt;
    blur3_min      yes    0..1     range, though.  &lt;br /&gt;
    blur1_max      yes    0..1   This will increase the precision in the blur textures,&lt;br /&gt;
    blur2_max      yes    0..1     but you run the risk of clamping values to your min/max.&lt;br /&gt;
    blur3_max      yes    0..1   If you use the GetBlur1() .. GetBlur3() functions to sample&lt;br /&gt;
    blur1_edge_darken yes 0..1     the blur texture, they will automatically &amp;quot;unpack&amp;quot; the&lt;br /&gt;
                                   values for you in the end!&lt;br /&gt;
    &lt;br /&gt;
    q1             yes    any    } Used to carry values along a chain                                         &lt;br /&gt;
    q2             yes    any    }  from the preset init code,                                                &lt;br /&gt;
    q3             yes    any    }  to the preset per-frame code, then on                                     &lt;br /&gt;
    q4             yes    any    }    to the preset per-vertex code;                                          &lt;br /&gt;
    q5             yes    any    }    or to the custom shape per-frame code,                                  &lt;br /&gt;
    q6             yes    any    }    or to the custom wave per-frame code,                                   &lt;br /&gt;
    q7             yes    any    }      then to the custom wave per-vertex code;                              &lt;br /&gt;
    ...                          }    or to the [pixel] shader code.                                          &lt;br /&gt;
    q31            yes    any    } Click here to see a diagram for the Q vars.&lt;br /&gt;
    q32            yes    any    } &lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    Some of the variables are read-only, meaning that you shouldn't change&lt;br /&gt;
    their values them through the equations.  You can; it won't stop you; &lt;br /&gt;
    but the results are unpredictable.&lt;br /&gt;
            &lt;br /&gt;
    You can also make up to 30 of your own variables.  For example:&lt;br /&gt;
    &lt;br /&gt;
        my_volume = (bass + mid + treb)/3;&lt;br /&gt;
        zoom = zoom + 0.1*(my_volume - 1);&lt;br /&gt;
&lt;br /&gt;
    This would make the zoom amount increase when the music is loud,&lt;br /&gt;
    and decrease when the music is quiet.  &lt;br /&gt;
    &lt;br /&gt;
    HOWEVER, custom variables do not carry over from per-frame equations&lt;br /&gt;
    to per-vertex equations; if you set a custom variable's value in the&lt;br /&gt;
    per-frame equations, and try to read it in the per-vertex equations,&lt;br /&gt;
    you will not get the correct value.  Instead, you have to &amp;quot;bridge the&lt;br /&gt;
    gap&amp;quot; using 32 special variables: q1 through q32.  This is usually only&lt;br /&gt;
    used when you want to precompute some custom values in the per-frame &lt;br /&gt;
    equations for later use in the per-vertex equations (or for use in&lt;br /&gt;
    the pixel shaders).  For a good example of this, see the 'dynamic swirls' &lt;br /&gt;
    preset.  See below for more information on q1-q32.&lt;br /&gt;
&lt;br /&gt;
=== PER-VERTEX EQUATIONS ===&lt;br /&gt;
    &lt;br /&gt;
    So far we've discussed only how to change parameters based on&lt;br /&gt;
    time.  What if you wanted to also vary a parameter, such as the&lt;br /&gt;
    zoom amount, in different ways, for different locations on the&lt;br /&gt;
    screen?  For example, normally, the result of the 'zoom' parameter&lt;br /&gt;
    is to just do a flat zoom.  This doesn't look very realistic, &lt;br /&gt;
    because you don't see any perspective in the zoom.  It would be&lt;br /&gt;
    better if we could give a unique zoom amount to each pixel on &lt;br /&gt;
    the screen; we could make the pixels far away from the center&lt;br /&gt;
    zoom more, and this would give it more perspective.  In order&lt;br /&gt;
    to do this, we use &amp;quot;per-vertex&amp;quot; equations, instead of per-frame&lt;br /&gt;
    equations.&lt;br /&gt;
    &lt;br /&gt;
    The code for this per-vertex equation is simple:&lt;br /&gt;
    &lt;br /&gt;
        zoom = zoom + rad*0.1;&lt;br /&gt;
        &lt;br /&gt;
    Where 'rad' is the radius of the pixel if it were cast into&lt;br /&gt;
    polar coordinates; from another perspective, 'rad' is the distance &lt;br /&gt;
    of the pixel from the center of the screen.  'rad is zero at the&lt;br /&gt;
    center, and 1 at the corners.  So if we run the above code,&lt;br /&gt;
    the image will be zoomed into 10% more at the edges of the screen&lt;br /&gt;
    than at the center.&lt;br /&gt;
    &lt;br /&gt;
    The per-vertex equations are really just like the per-frame equations,&lt;br /&gt;
    except for a variables.  The following variables are available&lt;br /&gt;
    exclusively to per-vertex equations (and not to per-frame equations):&lt;br /&gt;
    &lt;br /&gt;
    NAME   WRITEABLE? RANGE    DESCRIPTION&lt;br /&gt;
    ----   ---------- -----    -----------                                                                   &lt;br /&gt;
    x          NO     0..1     retrieves the x-position of the current pixel.  At the very left edge of the screen this would be 0; in the middle, 0.5; and at the right, 1.   &lt;br /&gt;
    y          NO     0..1     retrieves the y-position of the current pixel.  At the very top edge of the screen this would be 0; in the middle, 0.5; and at the bottom, 1.   &lt;br /&gt;
    rad        NO     0..1     retrives the distance of the pixel from the center of the screen.  At the center of the screen this will be zero, and at the corners, 1.  &lt;br /&gt;
                                  (The middle of the edges will be 0.707 (half of the square root of 2).&lt;br /&gt;
    ang        NO     0..6.28  retrieves the angle of the current pixel, with respect to the center of the screen.  &lt;br /&gt;
                                  If the point is to the right of the center, this is zero; above it, it is PI/2 (1.57); to the left, it is PI (3.14); and below, it is 4.71 (PI*3/2).  &lt;br /&gt;
                                  If it is just a dab below being directly to the right of the center of the screen, the value will approach 6.28 (PI*2).  &lt;br /&gt;
                                  (note: this is simply the arctangent of y over x, precomputed for you.)&lt;br /&gt;
    &lt;br /&gt;
    zoom       yes    &amp;gt;0       controls inward/outward motion.  0.9=zoom out 10% per frame, 1.0=no zoom, 1.1=zoom in 10%&lt;br /&gt;
    zoomexp    yes    &amp;gt;0       controls the curvature of the zoom; 1=normal&lt;br /&gt;
    rot        yes             controls the amount of rotation.  0=none, 0.1=slightly right, -0.1=slightly clockwise, 0.1=CCW&lt;br /&gt;
    warp       yes    &amp;gt;0       controls the magnitude of the warping; 0=none, 1=normal, 2=major warping...&lt;br /&gt;
    cx         yes    0..1     controls where the center of rotation and stretching is, horizontally.  0=left, 0.5=center, 1=right&lt;br /&gt;
    cy         yes    0..1     controls where the center of rotation and stretching is, vertically.  0=top, 0.5=center, 1=bottom&lt;br /&gt;
    dx         yes             controls amount of constant horizontal motion; -0.01 = move left 1% per frame, 0=none, 0.01 = move right 1%&lt;br /&gt;
    dy         yes             controls amount of constant vertical motion; -0.01 = move up 1% per frame, 0=none, 0.01 = move down 1%&lt;br /&gt;
    sx         yes    &amp;gt;0       controls amount of constant horizontal stretching; 0.99=shrink 1%, 1=normal, 1.01=stretch 1%           &lt;br /&gt;
    sy         yes    &amp;gt;0       controls amount of constant vertical stretching; 0.99=shrink 1%, 1=normal, 1.01=stretch 1%             &lt;br /&gt;
    &lt;br /&gt;
    time       NO     &amp;gt;0       retrieves the current time, in seconds, since MilkDrop started running&lt;br /&gt;
    fps        NO     &amp;gt;0       retrieves the current framerate, in frames per second.&lt;br /&gt;
    frame      NO              retrieves the number of frames of animation elapsed since the program started&lt;br /&gt;
    progress   NO     0..1     progress through the current preset; if preset was just loaded, this is closer to 0; if preset is about to end, this is closer to 1.&lt;br /&gt;
                                 -note that if Scroll Lock is on, 'progress' will freeze!&lt;br /&gt;
&lt;br /&gt;
    bass       NO     &amp;gt;0       retrieves the current amount of bass.  1 is normal; below ~0.7 is quiet; above ~1.3 is loud bass&lt;br /&gt;
    mid        NO     &amp;gt;0         -same, but for mids (middle frequencies)&lt;br /&gt;
    treb       NO     &amp;gt;0         -same, but for treble (high) frequencies&lt;br /&gt;
    bass_att   NO     &amp;gt;0       retrieves an attenuated reading on the bass, meaning that it is damped in time and doesn't change so rapidly.&lt;br /&gt;
    mid_att    NO     &amp;gt;0         -same, but for mids (middle frequencies)&lt;br /&gt;
    treb_att   NO     &amp;gt;0         -same, but for treble (high) frequencies&lt;br /&gt;
&lt;br /&gt;
    meshx      NO     8-192    tells you the user's mesh size in the X direction.  always an integer value.&lt;br /&gt;
    meshy      NO     6-144    tells you the user's mesh size in the Y direction.  always an integer value.&lt;br /&gt;
    pixelsx    NO     16-4096  width of the viz window, in pixels.  If Canvas Stretch is on, this is the pre-stretched size.  (same as &amp;quot;texsize.x&amp;quot; for shaders)&lt;br /&gt;
    pixelsy    NO     16-4096  height of the viz window, in pixels.  If Canvas Stretch is on, this is the pre-stretched size.  (same as &amp;quot;texsize.y&amp;quot; for shaders)&lt;br /&gt;
    aspectx    NO     &amp;gt;0     multiply an x-coordinate by this to make the preset look the same at any aspect (window height:width) ratio.&lt;br /&gt;
                               -value: if widescreen, 1; if window is tall, h/w.&lt;br /&gt;
    aspecty    NO     &amp;gt;0     multiply a y-coordinate by this to make the preset look the same at any aspect (window height:width) ratio.&lt;br /&gt;
                               -value: if widescreen, w/h; if window is tall, 1.&lt;br /&gt;
            &lt;br /&gt;
    q1         yes    any      } Used to carry values along a chain           &lt;br /&gt;
    q2         yes    any      }  from the preset init code,                        &lt;br /&gt;
    q3         yes    any      }  to the preset per-frame code, then on             &lt;br /&gt;
    q4         yes    any      }    to the preset per-vertex code;            &lt;br /&gt;
    q5         yes    any      }    or to the custom shape per-frame code,          &lt;br /&gt;
    q6         yes    any      }    or to the custom wave per-frame code,      &lt;br /&gt;
    q7         yes    any      }      then to the custom wave per-vertex code;&lt;br /&gt;
    ...                        }    or to the [pixel] shader code.            &lt;br /&gt;
    q31        yes    any      } Click here to see a diagram for the Q vars.&lt;br /&gt;
    q32        yes    any      } &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    The main reason for distinction between per-frame and per-vertex equations&lt;br /&gt;
    is simple: SPEED.  If you have a per-vertex equation that doesn't make use&lt;br /&gt;
    of the x, y, rad, or ang variables, then there's no reason for it to be&lt;br /&gt;
    executed per-vertex; it could be executed once per frame, and the result&lt;br /&gt;
    would be the same.  So, here's a maxim to write on the wall:&lt;br /&gt;
    &lt;br /&gt;
        &amp;quot;If a per-vertex equation doesn't use at least one of the variables&lt;br /&gt;
         { x, y, rad, ang }, then it should be actually be a per-frame &lt;br /&gt;
         equation.&amp;quot;&lt;br /&gt;
    &lt;br /&gt;
    You might be wondering how on earth all these formulas could be computed&lt;br /&gt;
    for every pixel on the screen, every frame, and still yield a high frame&lt;br /&gt;
    rate.  Well, that's the magic of the hamster.  And the fact that it really&lt;br /&gt;
    does the processing only at certain points on the screen, then interpolates&lt;br /&gt;
    the results across the space between the points.  In the config panel,&lt;br /&gt;
    the &amp;quot;mesh size&amp;quot; option defines how many points (in X and Y) there are at&lt;br /&gt;
    which the per-vertex equations are actually computed.  When you crank this&lt;br /&gt;
    option up, you start eating up CPU cycles rather quickly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
=== VARIABLE POOLS; DECLARING YOUR OWN VARIABLES; PERSISTENCE OF VALUES ===&lt;br /&gt;
    -----------------------&lt;br /&gt;
    Declaring and using your own variables is easy - in some bit of code &lt;br /&gt;
    (init equations, per-frame equations, etc.) you just write something like&lt;br /&gt;
    the following:&lt;br /&gt;
    &lt;br /&gt;
        billy = 5.3;&lt;br /&gt;
    &lt;br /&gt;
    This creates a variable called 'billy' and sets its value to 5.3.  You can&lt;br /&gt;
    then freely read and/or modify the value of 'billy' within that section&lt;br /&gt;
    of code.&lt;br /&gt;
    &lt;br /&gt;
    However, sometimes it is desireable to create (really, initialize) a variable &lt;br /&gt;
    in an &amp;quot;init&amp;quot; equations, then use and/or update it in the &amp;quot;per-frame&amp;quot; equations.&lt;br /&gt;
    You can always do this, because paired init and per-frame equations&lt;br /&gt;
    share the same variable pool.  In addition, the values of user-defined&lt;br /&gt;
    variables will persist from frame to frame.&lt;br /&gt;
    &lt;br /&gt;
    There are three variable &amp;quot;pools&amp;quot; in MilkDrop:&lt;br /&gt;
&lt;br /&gt;
      1. preset init code + preset per-frame code&lt;br /&gt;
      2. custom wave init + custom wave per-frame code&lt;br /&gt;
      3. custom shape init + custom shape per-frame code&lt;br /&gt;
    &lt;br /&gt;
    So, you can probably guess that if you declare a variable in the preset&lt;br /&gt;
    init code, you can then read it in the preset per-frame code.  You can&lt;br /&gt;
    also write to it (update it), and its value will persist to the next&lt;br /&gt;
    frame.  All three pools work this way.&lt;br /&gt;
&lt;br /&gt;
    As explained, though, you can't read the value of 'billy' in when in another &lt;br /&gt;
    variable pool.  (This is intentional, and keeps MilkDrop running nice and &lt;br /&gt;
    fast.)  If you want to pass values around between variable pools, you need &lt;br /&gt;
    to use a set of special variables: q1, q2, q3, etc. on up to q32.  See&lt;br /&gt;
    the next section for details on how they work and how to properly use them.&lt;br /&gt;
    Just remember: the Q variables (and later, the T variables) are the only ones &lt;br /&gt;
    that you can use to &amp;quot;jump&amp;quot; between (carry values between) variable pools.&lt;br /&gt;
    &lt;br /&gt;
    You might notice that there are two other types of equations that weren't &lt;br /&gt;
    listed above.  They are:&lt;br /&gt;
    &lt;br /&gt;
      * preset per-vertex code&lt;br /&gt;
      * custom wave per-point code&lt;br /&gt;
    &lt;br /&gt;
    For these two code sections, persistent values don't really make sense,&lt;br /&gt;
    because there is no way to properly initialize them.  Any user-defined&lt;br /&gt;
    variables in these code sections should just be treated as scratch&lt;br /&gt;
    variables, not persisting from frame to frame, from vertex to vertex,&lt;br /&gt;
    or from point to point (even though technically, they will... but it&lt;br /&gt;
    probably won't be what you want).  The only thing that really makes sense&lt;br /&gt;
    here is when you want to carry values along from point to point as&lt;br /&gt;
    you run the custom wave per-point code; to do this, use q1-q32.  (See&lt;br /&gt;
    the next section for a more detailed explanation.)  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
=== PRESET INIT CODE; CARRYING VALUES BETWEEN VARIABLE POOLS, USING q1-q32 ===&lt;br /&gt;
    As we've just seen, you can't normally pass values around between variable &lt;br /&gt;
    pools.  However, there is one mechanism for bridging this gap: the 'Q'&lt;br /&gt;
    variables.  They are named q1, q2, q3, and so on, through q32.  Their&lt;br /&gt;
    main function is to bridge the gap between various variable pools.&lt;br /&gt;
    &lt;br /&gt;
    In MilkDrop 1.03 and later, you can write code that is executed only once,&lt;br /&gt;
    when a preset is loaded (switched to).  This 'preset initialization' code &lt;br /&gt;
    does two useful things:&lt;br /&gt;
      &lt;br /&gt;
      1. It allows you to set the initial value of your own (user-defined) &lt;br /&gt;
         variables (such as 'my_variable'), as just explained.  &lt;br /&gt;
         &lt;br /&gt;
      2. It allows you to write the default (&amp;quot;sticky&amp;quot;) values for q1, q2, q3... &lt;br /&gt;
         through q32.  Whatever these values end up at after the init code, &lt;br /&gt;
         those are the values that q1-q32 will be reset to at the start of &lt;br /&gt;
         each frame (...the input to the per-frame equations).  If the&lt;br /&gt;
         per-frame equations change the values of q1-q32, those new values will&lt;br /&gt;
         propagate on to other variable pools (see the diagram below), but on&lt;br /&gt;
         the next frame, the values will be reset to the original &amp;quot;sticky&amp;quot; &lt;br /&gt;
         defaults.&lt;br /&gt;
         &lt;br /&gt;
    See the flow chart below for a brief, and complete, glance at how the values&lt;br /&gt;
    of the Q variables flow throughout MilkDrop.&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    Let's walk through the flow of the chart.  &lt;br /&gt;
    &lt;br /&gt;
    If you write to the values of q1..q32 from the &amp;quot;preset init code&amp;quot;, the values &lt;br /&gt;
    you write will become the new 'base values' to which q1..q32 are initialized &lt;br /&gt;
    at the start of each frame, for the per-frame code.  So when you access (read) &lt;br /&gt;
    q1-q32 in the per-frame code, you'll get the values that were *initially* set -&lt;br /&gt;
    over and over, every frame.  You can then modify them (or not) in the per-frame &lt;br /&gt;
    code, and the (possibly modified values) will then be readable by the per-vertex &lt;br /&gt;
    code - as well as by all pixel shader code, and others.  However, any modified &lt;br /&gt;
    values will not persist to the next frame; they will be reset again, at the &lt;br /&gt;
    start of the next frame, to the values they had at the end of the preset init &lt;br /&gt;
    code.&lt;br /&gt;
&lt;br /&gt;
    In the per-vertex code, the q1-q32 values start (for the first vertex &lt;br /&gt;
    in any frame) as the values they had at the end of the per-frame code.  If you &lt;br /&gt;
    modify q1-q32 in the per-vertex code, those modified values will carry over &lt;br /&gt;
    from vertex to vertex.  (This isn't a very desireable effect; you should avoid &lt;br /&gt;
    writing to the Q variables from the per-vertex equations.)  Next frame, they &lt;br /&gt;
    will be reset to whatever value they had at the end of the [next frame's &lt;br /&gt;
    execution of the] per-frame code.  (It's all in the diagram... look at that, &lt;br /&gt;
    and you'll just get it.)&lt;br /&gt;
&lt;br /&gt;
    There is one trick here.  You might notice that the custom wave/shape&lt;br /&gt;
    init boxes are missing from the diagram.  That's because the q&lt;br /&gt;
    variables coming out of them don't go anywhere.  The Q values that come&lt;br /&gt;
    into the per-frame wave/shape equations come from the preset per-frame&lt;br /&gt;
    equations, as you can see.  But, just to humor you: in the wave/shape init code, &lt;br /&gt;
    the Q values coming in are the results from the preset init code.  Any Q values &lt;br /&gt;
    you write to there (in the wave/shape init code) will be meaningless; although&lt;br /&gt;
    you can write to (initialize) your own custom variables, and read those in &lt;br /&gt;
    later, in the wave/shape per-frame equations!  So, really, you can still route&lt;br /&gt;
    data that way, if you really want to.&lt;br /&gt;
        &lt;br /&gt;
    Side note: when you edit the preset init code and apply it (by hitting &lt;br /&gt;
    CTRL+ENTER), the init code will re-execute immediately.  However, when you &lt;br /&gt;
    edit the regular per-frame/per-vertex code and hit CTRL+ENTER, the preset init &lt;br /&gt;
    code will NOT be re-executed; the results of the last execution will persist.&lt;br /&gt;
    If you change per-frame/per-vertex code and want to re-execute the initialization&lt;br /&gt;
    code (i.e. to randomize it or reset the preset), you'll have to save the preset&lt;br /&gt;
    and then re-load it.&lt;br /&gt;
&lt;br /&gt;
    (Historical note: nothing here has changed since MilkDrop 1; these diagrams were&lt;br /&gt;
    just re-designed to be much simpler to read.  Actually, there was a bug in &lt;br /&gt;
    the old diagrams that is now fixed: on frame 0, they showed the Q values &lt;br /&gt;
    going straight from the (frame 0!?) per-frame code, into the custom &lt;br /&gt;
    wave/shape init code.  On frame 0, those Q values actually come straight from &lt;br /&gt;
    the preset init code.  HOWEVER, they are virtually useless, as discussed above.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
=== CUSTOM SHAPES AND WAVES ===&lt;br /&gt;
    ----------------------&lt;br /&gt;
    As of MilkDrop 1.04, two new features are available: custom shapes, and custom &lt;br /&gt;
    waves.  A preset can have up to 4 of each.  &lt;br /&gt;
    &lt;br /&gt;
    With custom shapes, you can draw an n-sided shape (with 3-100 sides) anywhere &lt;br /&gt;
    on the screen, at any angle and size, in any color, and at any opacity.  You &lt;br /&gt;
    even have the option to map the previous frame's image onto the shape, which &lt;br /&gt;
    makes for some incredible possibilities (such as realtime hardware fractals - &lt;br /&gt;
    see the 'Geiss - Feedback' preset).  You can also write per-frame code to &lt;br /&gt;
    control all of these things about the shape(s).  This way, they can react to&lt;br /&gt;
    the audio or change over time - whatever you can imagine.  You are limited to&lt;br /&gt;
    four custom shapes per preset, however, each one of those can be instanced,&lt;br /&gt;
    which lets you draw a huge number (up to 1024) of them each frame, if you &lt;br /&gt;
    want to, and each one can be totally different (as long as the value of&lt;br /&gt;
    the 'instance' variable ends up influencing the other properties).&lt;br /&gt;
    &lt;br /&gt;
    With custom waves, you can draw the waveform (or the frequency spectrum)&lt;br /&gt;
    wherever, whenever, and however you want; a great addition since MilkDrop &lt;br /&gt;
    1.03, where only the built-in waveforms were possible.  With custom waves&lt;br /&gt;
    you can also write per-frame code to control the waves, and per-point code&lt;br /&gt;
    to place every point (or line segment) on the wave exactly where you want,&lt;br /&gt;
    and in exactly the color you want, and so on.&lt;br /&gt;
&lt;br /&gt;
    Remember those q1-q32 variables that were committed at the end of the preset&lt;br /&gt;
    initialization code, then reset (to those values) at the beginning of each&lt;br /&gt;
    frame, and then (potentially) modified in the preset per-frame code?  Those&lt;br /&gt;
    (potentially modified) values of q1-q32 - as they were at the end of the&lt;br /&gt;
    preset's per-frame code, each frame - are piped into the custom wave &amp;amp; custom &lt;br /&gt;
    shape per-frame code.  So if you read 'q3' in the custom wave per-frame &lt;br /&gt;
    code, what you're really reading is the value of 'q3' as it was left at the &lt;br /&gt;
    end of this frame's per-frame code.  Again, see the q_vars.gif image &lt;br /&gt;
    for a diagram of the flow of the values of the q1-q32 varibles.&lt;br /&gt;
&lt;br /&gt;
    For custom waves and shapes, you can modify q1-q32, if you like, in the per-&lt;br /&gt;
    frame equations.  As usual, the values of the Q variables will not persist &lt;br /&gt;
    from frame to frame, though - they are reset on each new frame, to match&lt;br /&gt;
    the values they had at the end of the *preset's* per-frame code, this frame. &lt;br /&gt;
    &lt;br /&gt;
    For custom waves, you also have one more link in the chain: per-point&lt;br /&gt;
    (aka per-vertex) code.  This code is executed once for each data point in the &lt;br /&gt;
    waveform.  The initial values of q1-q32 coming in (for the first point)&lt;br /&gt;
    are the values that stood at the end of the custom wave per-frame code,&lt;br /&gt;
    this frame.  If you then modify q1-q32 in the per-point code (or even if you&lt;br /&gt;
    don't), the values will pass on to the next point.  You could, for example, &lt;br /&gt;
    smooth out a waveform using this.&lt;br /&gt;
&lt;br /&gt;
    THE 'T' VARIABLES&lt;br /&gt;
    ----------------------&lt;br /&gt;
    There are 8 additional variables available for custom waves and shapes:&lt;br /&gt;
    t1-t8.  These are very similar to the Q variables, but they exist only&lt;br /&gt;
    for custom waves &amp;amp; shapes.  To see how the data flows from variable pool&lt;br /&gt;
    to variable pool for the T vars, take a look at the diagram below.  Like&lt;br /&gt;
    the Q variables, they exist to help you bridge some gaps between variable&lt;br /&gt;
    pools.  However, the T variables are a bit simpler to understand than the &lt;br /&gt;
    Q's.  The diagram below should explain it all.&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    CUSTOM SHAPE PER-FRAME VARIABLES&lt;br /&gt;
    ----------------------&lt;br /&gt;
        NAME    WRITABLE? RANGE    DESCRIPTION&lt;br /&gt;
        ----    --------- -----    -----------                                                                   &lt;br /&gt;
        num_inst   no     1-1024   The total # of instances (the number of times to repeat the per-frame equations for, &amp;amp; draw, this shape).&lt;br /&gt;
        instance   no     0..num_inst-1   The current instance number that the equations are being executed for.&lt;br /&gt;
        sides      yes    3-100    the default number of sides that make up the polygonal shape&lt;br /&gt;
        thick      yes    0/1      if ON, the border will be overdrawn 4X to make it thicker, bolder, and more visible&lt;br /&gt;
        additive   yes    0/1      if ON, the shape will add color to sature the image toward white; otherwise, it will replace what's there.&lt;br /&gt;
        x          yes    0..1     default x position of the shape (0..1; 0=left side, 1=right side)&lt;br /&gt;
        y          yes    0..1     default y position of the shape (0..1; 0=bottom, 1=top of screen)&lt;br /&gt;
        rad        yes    0+       default radius of the shape (0+)&lt;br /&gt;
        ang        yes    0..6.28  default rotation angle of the shape (0...2*pi)&lt;br /&gt;
        textured   yes    0/1      if ON, the shape will be textured with the image from the previous frame&lt;br /&gt;
        tex_zoom   yes    &amp;gt;0       the portion of the previous frame's image to use with the shape&lt;br /&gt;
        tex_ang    yes    0..6.28  the angle at which to rotate the previous frame's image before applying it to the shape&lt;br /&gt;
        r          yes    0..1     default amount of red color toward the center of the shape (0..1)&lt;br /&gt;
        g          yes    0..1     default amount of green color toward the center of the shape (0..1)&lt;br /&gt;
        b          yes    0..1     default amount of blue color toward the center of the shape (0..1)&lt;br /&gt;
        a          yes    0..1     default opacity of the center of the shape; 0=transparent, 1=opaque&lt;br /&gt;
        r2         yes    0..1     default amount of red color toward the outer edge of the shape (0..1)&lt;br /&gt;
        g2         yes    0..1     default amount of green color toward the outer edge of the shape (0..1)&lt;br /&gt;
        b2         yes    0..1     default amount of blue color toward the outer edge of the shape (0..1)&lt;br /&gt;
        a2         yes    0..1     default opacity of the outer edge of the shape; 0=transparent, 1=opaque&lt;br /&gt;
        border_r   yes    0..1     default amount of red color in the shape's border (0..1)&lt;br /&gt;
        border_g   yes    0..1     default amount of green color in the shape's border (0..1)&lt;br /&gt;
        border_b   yes    0..1     default amount of blue color in the shape's border (0..1)&lt;br /&gt;
        border_a   yes    0..1     default opacity of the shape's border; 0=transparent, 1=opaque&lt;br /&gt;
&lt;br /&gt;
        time       NO     &amp;gt;0       retrieves the current time, in seconds, since MilkDrop started running&lt;br /&gt;
        fps        NO     &amp;gt;0       retrieves the current framerate, in frames per second.&lt;br /&gt;
        frame      NO              retrieves the number of frames of animation elapsed since the program started&lt;br /&gt;
        progress   NO     0..1     progress through the current preset; if preset was just loaded, this is closer to 0; if preset is about to end, this is closer to 1.&lt;br /&gt;
                                     -note that if Scroll Lock is on, 'progress' will freeze!&lt;br /&gt;
&lt;br /&gt;
        bass       NO     &amp;gt;0       retrieves the current amount of bass.  1 is normal; below ~0.7 is quiet; above ~1.3 is loud bass&lt;br /&gt;
        mid        NO     &amp;gt;0         -same, but for mids (middle frequencies)&lt;br /&gt;
        treb       NO     &amp;gt;0         -same, but for treble (high) frequencies&lt;br /&gt;
        bass_att   NO     &amp;gt;0       retrieves an attenuated reading on the bass, meaning that it is damped in time and doesn't change so rapidly.&lt;br /&gt;
        mid_att    NO     &amp;gt;0         -same, but for mids (middle frequencies)&lt;br /&gt;
        treb_att   NO     &amp;gt;0         -same, but for treble (high) frequencies&lt;br /&gt;
&lt;br /&gt;
        q1         yes    any      } Used to carry values along a chain                                         &lt;br /&gt;
        q2         yes    any      }  from the preset init code,                                                &lt;br /&gt;
        q3         yes    any      }  to the preset per-frame code, then on                                     &lt;br /&gt;
        q4         yes    any      }    to the preset per-vertex code;                                          &lt;br /&gt;
        q5         yes    any      }    or to the custom shape per-frame code,                                  &lt;br /&gt;
        q6         yes    any      }    or to the custom wave per-frame code,                                   &lt;br /&gt;
        q7         yes    any      }      then to the custom wave per-vertex code;                              &lt;br /&gt;
        ...                        }    or to the [pixel] shader code.                                          &lt;br /&gt;
        q31        yes    any      } Click here to see a diagram for the Q vars.&lt;br /&gt;
        q32        yes    any      } &lt;br /&gt;
&lt;br /&gt;
        t1         yes    any      } Used to carry information                                                  &lt;br /&gt;
        t2         yes    any      }  from the custom shape init code                                           &lt;br /&gt;
        t3         yes    any      }    to the custom shape per-frame code.                                       &lt;br /&gt;
        t4         yes    any      } Click here to see a diagram for the T vars.&lt;br /&gt;
        t5         yes    any      } &lt;br /&gt;
        t6         yes    any      } &lt;br /&gt;
        t7         yes    any      } &lt;br /&gt;
        t8         yes    any      } &lt;br /&gt;
                                     &lt;br /&gt;
    &lt;br /&gt;
    CUSTOM WAVE PER-FRAME VARIABLES&lt;br /&gt;
    ---------------------&lt;br /&gt;
        NAME   WRITABLE?  RANGE    DESCRIPTION&lt;br /&gt;
        ----   ---------  -----    -----------                                                                   &lt;br /&gt;
        r          yes    0..1     base amount of red color in the wave (0..1)&lt;br /&gt;
        g          yes    0..1     base amount of green color in the wave (0..1)&lt;br /&gt;
        b          yes    0..1     base amount of blue color in the wave (0..1)&lt;br /&gt;
        a          yes    0..1     base opacity of the waveform; 0=transparent, 1=opaque&lt;br /&gt;
        samples    yes    0-512    read: retrieves the # of samples specified for this custom wave (from the menu).&lt;br /&gt;
                                   write: lets you dynamically change that #, frame to frame.&lt;br /&gt;
&lt;br /&gt;
        time       NO     &amp;gt;0       retrieves the current time, in seconds, since MilkDrop started running&lt;br /&gt;
        fps        NO     &amp;gt;0       retrieves the current framerate, in frames per second.&lt;br /&gt;
        frame      NO              retrieves the number of frames of animation elapsed since the program started&lt;br /&gt;
        progress   NO     0..1     progress through the current preset; if preset was just loaded, this is closer to 0; if preset is about to end, this is closer to 1.&lt;br /&gt;
                                     -note that if Scroll Lock is on, 'progress' will freeze!&lt;br /&gt;
&lt;br /&gt;
        bass       NO     &amp;gt;0       retrieves the current amount of bass.  1 is normal; below ~0.7 is quiet; above ~1.3 is loud bass&lt;br /&gt;
        mid        NO     &amp;gt;0         -same, but for mids (middle frequencies)&lt;br /&gt;
        treb       NO     &amp;gt;0         -same, but for treble (high) frequencies&lt;br /&gt;
        bass_att   NO     &amp;gt;0       retrieves an attenuated reading on the bass, meaning that it is damped in time and doesn't change so rapidly.&lt;br /&gt;
        mid_att    NO     &amp;gt;0         -same, but for mids (middle frequencies)&lt;br /&gt;
        treb_att   NO     &amp;gt;0         -same, but for treble (high) frequencies&lt;br /&gt;
&lt;br /&gt;
        q1         yes    any      } Used to carry values along a chain                                         &lt;br /&gt;
        q2         yes    any      }  from the preset init code,                                                &lt;br /&gt;
        q3         yes    any      }  to the preset per-frame code, then on                                     &lt;br /&gt;
        q4         yes    any      }    to the preset per-vertex code;                                          &lt;br /&gt;
        q5         yes    any      }    or to the custom shape per-frame code,                                  &lt;br /&gt;
        q6         yes    any      }    or to the custom wave per-frame code,                                   &lt;br /&gt;
        q7         yes    any      }      then to the custom wave per-vertex code;                              &lt;br /&gt;
        ...                        }    or to the [pixel] shader code.                                          &lt;br /&gt;
        q31        yes    any      } Click here to see a diagram for the Q vars.&lt;br /&gt;
        q32        yes    any      } &lt;br /&gt;
    &lt;br /&gt;
        t1         yes    any      } Used to carry information                                                  &lt;br /&gt;
        t2         yes    any      }  from the custom wave init code,                                           &lt;br /&gt;
        t3         yes    any      }    to the custom wave per-frame code,                                      &lt;br /&gt;
        t4         yes    any      }      then on to the custom wave per-point code                             &lt;br /&gt;
        t5         yes    any      }      (and from point to point, too, if you write                           &lt;br /&gt;
        t6         yes    any      }      to the values from the per-point equations).                          &lt;br /&gt;
        t7         yes    any      } Click here to see a diagram for the T vars.&lt;br /&gt;
        t8         yes    any      } &lt;br /&gt;
    &lt;br /&gt;
       &lt;br /&gt;
    CUSTOM WAVE PER-POINT (aka PER-VERTEX) VARIABLES&lt;br /&gt;
    ---------------------&lt;br /&gt;
        NAME   WRITABLE?  RANGE    DESCRIPTION&lt;br /&gt;
        ----   ---------  -----    -----------                                                                   &lt;br /&gt;
        x          yes    0..1     the x position of this point that makes up the wave (0=left, 1=right)&lt;br /&gt;
        y          yes    0..1     the y position of this point that makes up the wave (0=bottom, 1=top)&lt;br /&gt;
        sample     no     0..1     how far along we are, through the samples that make up the waveform: 0=first sample, 0.5 = half-way through; 1=last sample.&lt;br /&gt;
        value1     no     any      the value of the Left audio channel sample at this point in the waveform (or freq. spectrum).&lt;br /&gt;
        value2     no     any      the value of the Right audio channel sample at this point in the waveform (or freq. spectrum).&lt;br /&gt;
        r          yes    0..1     amount of red color in this point of the wave (0..1)&lt;br /&gt;
        g          yes    0..1     amount of green color in this point of the wave (0..1)&lt;br /&gt;
        b          yes    0..1     amount of blue color in this point of the wave (0..1)&lt;br /&gt;
        a          yes    0..1     opacity of this point of the waveform; 0=transparent, 1=opaque&lt;br /&gt;
&lt;br /&gt;
        time       NO     &amp;gt;0       retrieves the current time, in seconds, since MilkDrop started running&lt;br /&gt;
        fps        NO     &amp;gt;0       retrieves the current framerate, in frames per second.&lt;br /&gt;
        frame      NO              retrieves the number of frames of animation elapsed since the program started&lt;br /&gt;
        progress   NO     0..1     progress through the current preset; if preset was just loaded, this is closer to 0; if preset is about to end, this is closer to 1.&lt;br /&gt;
                                     -note that if Scroll Lock is on, 'progress' will freeze!&lt;br /&gt;
&lt;br /&gt;
        bass       NO     &amp;gt;0       retrieves the current amount of bass.  1 is normal; below ~0.7 is quiet; above ~1.3 is loud bass&lt;br /&gt;
        mid        NO     &amp;gt;0         -same, but for mids (middle frequencies)&lt;br /&gt;
        treb       NO     &amp;gt;0         -same, but for treble (high) frequencies&lt;br /&gt;
        bass_att   NO     &amp;gt;0       retrieves an attenuated reading on the bass, meaning that it is damped in time and doesn't change so rapidly.&lt;br /&gt;
        mid_att    NO     &amp;gt;0         -same, but for mids (middle frequencies)&lt;br /&gt;
        treb_att   NO     &amp;gt;0         -same, but for treble (high) frequencies&lt;br /&gt;
&lt;br /&gt;
        q1         yes    any      } Used to carry values along a chain                                         &lt;br /&gt;
        q2         yes    any      }  from the preset init code,                                                &lt;br /&gt;
        q3         yes    any      }  to the preset per-frame code, then on                                     &lt;br /&gt;
        q4         yes    any      }    to the preset per-vertex code;                                          &lt;br /&gt;
        q5         yes    any      }    or to the custom shape per-frame code,                                  &lt;br /&gt;
        q6         yes    any      }    or to the custom wave per-frame code,                                   &lt;br /&gt;
        q7         yes    any      }      then to the custom wave per-vertex code;                              &lt;br /&gt;
        ...                        }    or to the [pixel] shader code.                                          &lt;br /&gt;
        q31        yes    any      } Click here to see a diagram for the Q vars.&lt;br /&gt;
        q32        yes    any      } &lt;br /&gt;
&lt;br /&gt;
        t1         yes    any      } Used to carry information                      &lt;br /&gt;
        t2         yes    any      }  from the custom wave init code,               &lt;br /&gt;
        t3         yes    any      }    to the custom wave per-frame code,          &lt;br /&gt;
        t4         yes    any      }      then on to the custom wave per-point code&lt;br /&gt;
        t5         yes    any      }      (and from point to point, too, if you write&lt;br /&gt;
        t6         yes    any      }      to the values from the per-point equations).&lt;br /&gt;
        t7         yes    any      } Click here to see a diagram for the T vars.&lt;br /&gt;
        t8         yes    any      } &lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
=== PIXEL SHADERS ===&lt;br /&gt;
&lt;br /&gt;
The world of realtime computer graphics made a huge stride around 2002-2003, with the advent of pixel shaders.  Lots of people want to learn how to use pixel shaders; writing presets for MilkDrop is a great way to learn them, because you get to see the effects of your code instantly,on the screen.&lt;br /&gt;
    &lt;br /&gt;
MilkDrop 1 ran on what is called the &amp;quot;fixed function&amp;quot; graphics pipeline. That meant that certain common graphics operations - and very few of them - could be executed for each pixel.  You could do a few things - maybe multiply by a texture or a color, then maybe one more simple operation - but that was about it.  &lt;br /&gt;
    &lt;br /&gt;
Newer presets (MilkDrop 2 and later) can take advantage of programmable pixel shaders.  GPUs (graphics processing units) are now capable of executing dozens, even thousands (on more expensive hardware) of instructions per pixel.  To tell the GPU what to do at each pixel, you write some code called a &amp;quot;pixel shader&amp;quot;.  It looks a lot like C, except you'll see the types float3 (...often representing a color, or maybe a 3D coordinate), as well as float2 and float4, as often as you'll see the simple &amp;quot;float&amp;quot; type.  There is also a lot of emphasis on sampling from textures.&lt;br /&gt;
    Textures can either be procedural (like the image from the previous&lt;br /&gt;
    frame, or a nicely gaussian-blurred version of it, or a procedurally-&lt;br /&gt;
    generated noise texture), or they can be loaded from disk.  To sample&lt;br /&gt;
    from a texture on disk (...but cached in video memory, of course), &lt;br /&gt;
    in the shader, you simply specify the name of the image file you want to load,&lt;br /&gt;
    and how you want to sample it (what kind of filtering &amp;amp; wrapping) as well as&lt;br /&gt;
    where (the UV coordinates, like XY coordinates, always in the [0..1] range).&lt;br /&gt;
    It reads the sample (as a float4 - some image formats have four channels&lt;br /&gt;
    instead of just r/g/b).  You can then do whatever you like (mathematically)&lt;br /&gt;
    with that sample, take other samples, combine them, and so on.  The final&lt;br /&gt;
    output of the shader is always a color value, and it is this color value&lt;br /&gt;
    that is written to the render target (an internal texture, or the screen).&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    SHADER MODELS - 2.0, 3.0, etc.&lt;br /&gt;
    ------------------------------&lt;br /&gt;
    Since pixel shaders were born, there have been a few revisions.  Each new&lt;br /&gt;
    model has more capabilities than the last.  &lt;br /&gt;
    &lt;br /&gt;
    MilkDrop 1 only supports fixed-function graphics - i.e. no pixel shaders.&lt;br /&gt;
    MilkDrop 2 supports shader model 2 at the lowest level.  (If your GPU&lt;br /&gt;
    doesn't support this, MilkDrop 2 should still run - it just won't show&lt;br /&gt;
    you any presets that use pixel shaders.)  Shader model 2 has a limit of&lt;br /&gt;
    64 instructions (per shader), though.  &lt;br /&gt;
    &lt;br /&gt;
    Presets can be authored to use Shader Model 3, however.  This shader&lt;br /&gt;
    model is not as widely supported (...so be careful writing presets for&lt;br /&gt;
    it - half of the GPUs out there don't support it yet, so the preset&lt;br /&gt;
    won't show up in the preset list on those computers).  However, it is&lt;br /&gt;
    much more powerful, with a virtually unlimited number of instructions.&lt;br /&gt;
    (You're just limited by the speed of your GPU and the number of pixels&lt;br /&gt;
    you need to draw each frame!)  On a GeForce 8000-series, believe it&lt;br /&gt;
    or not, you can easily achieve smooth framerates running shaders with &lt;br /&gt;
    THOUSANDS of instructions!&lt;br /&gt;
    &lt;br /&gt;
    Shader Model 4.0 also exists, but only in DirectX 10; and DirectX 10&lt;br /&gt;
    is only available with Windows Vista.  Because not many people have&lt;br /&gt;
    Vista yet, we've decided to wait (a damn long time) until going down&lt;br /&gt;
    that path.  Shader Model 3 has virtually everything we need in it&lt;br /&gt;
    anyway.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    PRESET FILE VERSIONS &amp;amp; COMPATIBILITY&lt;br /&gt;
    ------------------------------------&lt;br /&gt;
    Note that if you load a MilkDrop 1 preset, you can save it back to disk&lt;br /&gt;
    (even after changing code, variables, etc.) and it will still be readable&lt;br /&gt;
    by MilkDrop 1.  Only if you select the menu option to &amp;quot;Upgrade [its] &lt;br /&gt;
    Pixel Shader Version&amp;quot; will you be making it no longer backwards-compatible.&lt;br /&gt;
    Once you've done this, though, you'll notice that the menus look slightly&lt;br /&gt;
    different - some new shader-based options will appear, and some old stuff&lt;br /&gt;
    (video echo, gamma, etc. - all things that are now folded into the &lt;br /&gt;
    composite shader) are all gone.  You'll also notice that two nice little&lt;br /&gt;
    default shaders (warp and composite) have been written for you, and that &lt;br /&gt;
    the relevant values and options from the old preset (gamma, decay, video &lt;br /&gt;
    echo, texture wrap, etc.) have all been set correctly in the new shaders, &lt;br /&gt;
    so that the preset does exactly what it did before.  The only difference &lt;br /&gt;
    is that now, the preset takes advantage of the full programmability of &lt;br /&gt;
    pixel shaders (and you have a lot of freedom to tweak it), instead of &lt;br /&gt;
    being restricted by the highly restrictive DX8 fixed-function graphics &lt;br /&gt;
    pipeline.&lt;br /&gt;
    &lt;br /&gt;
    Some of the mash-up functions (discussed later) will mix old and new&lt;br /&gt;
    presets together.  In this case, the newly-created preset file will only&lt;br /&gt;
    look correct on MilkDrop 1.xx if it uses neither a warp nor composite shader.&lt;br /&gt;
    It will still run in MilkDrop 1, but without shaders, so whatever random &lt;br /&gt;
    values gamma, video echo, etc. were left at, will all kick back in.&lt;br /&gt;
&lt;br /&gt;
    One last note: keep in mind that MilkDrop 2 is smart enough to not show&lt;br /&gt;
    you any presets that your GPU can't support.  MilkDrop 1, though, isn't&lt;br /&gt;
    so smart - it will let you look at MilkDrop 2 presets.  It will &lt;br /&gt;
    ignore all the shader stuff, and probably not display correctly, though.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
==== A PIXEL SHADER - CONCEPTUAL OVERVIEW ====&lt;br /&gt;
&lt;br /&gt;
Games are what have driven the Hardware Graphics revolution, and games work by projecting many thousands of 3D triangles onto your screen and rasterizing (pixelizing) &amp;amp; shading them.  In MilkDrop, also, your graphics processing unit (GPU) is told to draw many triangle onto your screen.  Each is described by three vertices (points).  The interior of the triangle is a bunch of pixels.  The GPU runs your &amp;quot;shader&amp;quot; code on each pixel to determine how to shade the pixel - i.e., light it, or determine its color.  (The terminology is more geared toward the idea that these triangles were originally in 3D and require realistic lighting and shading.)&lt;br /&gt;
    &lt;br /&gt;
In MilkDrop, the shaders are run on a dumb, regular grid of triangles that covers the entire visualizer window.  The results of the preset's per-vertex equations are interpolated across the face of each of these triangles, and your pixel shader will see the interpolated results. They come in in the form of &amp;quot;UV&amp;quot; coordinates - they tell you where to sample (read) the source image, in order to create the desired warping effect each frame - the long-term effect of which is to create perceived motion. &lt;br /&gt;
    &lt;br /&gt;
You can then sample that image (or others), do some math on the result, sample some other textures, do some more math, etc.  By the end of the shader, whatever value is in &amp;quot;ret&amp;quot; (a float3 - three floating-point values) is the color that will be written for that pixel.&lt;br /&gt;
    &lt;br /&gt;
    Each preset in MilkDrop 2 has two pixel shaders: the warp shader,&lt;br /&gt;
    which warps the image from frame to frame, and the composite shader,&lt;br /&gt;
    which draws the frame to the screen (with or without special effects).&lt;br /&gt;
    &lt;br /&gt;
    To edit or experiment with these shaders, while MilkDrop is running, &lt;br /&gt;
    hit 'M' to view the preset editing menu.  The scroll down to either &lt;br /&gt;
        [edit warp shader]&lt;br /&gt;
    or &lt;br /&gt;
        [edit composite shader] &lt;br /&gt;
    and hit ENTER.  If you don't see either of these options, it means &lt;br /&gt;
    the current preset is an old MilkDrop 1 preset; in this case, you can &lt;br /&gt;
    either try a different preset, or you can upgrade the current preset &lt;br /&gt;
    by selecting &lt;br /&gt;
&lt;br /&gt;
        update preset's pixel shader version&lt;br /&gt;
&lt;br /&gt;
    toward the bottom of the menu.  Keep in mind that if you upgrade&lt;br /&gt;
    a preset's pixel shader version and then save it to disk, it might &lt;br /&gt;
    not be usable anymore on other computers with older graphics chips.&lt;br /&gt;
&lt;br /&gt;
    Now go edit one of the two shaders.  Once you're in there, editing,&lt;br /&gt;
    hit F9 - this will toggle the onscreen quick reference for writing&lt;br /&gt;
    shaders.  It's very handy.  Press F9 again to hide it.&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
==== WARP SHADER ====&lt;br /&gt;
&lt;br /&gt;
    Here is an example of a simple WARP shader.  It is run over every pixel of&lt;br /&gt;
    the internal canvas, with the output being back to the canvas itself (it's&lt;br /&gt;
    a double-buffered texture).  Any special effects that happen here get &amp;quot;baked&amp;quot; &lt;br /&gt;
    into the image, and will persist into the next frame.&lt;br /&gt;
        &lt;br /&gt;
        shader_body&lt;br /&gt;
        {&lt;br /&gt;
            // sample a pixel from the previous frame.  &lt;br /&gt;
            // uv coord is slightly warped (driven by the per-vertex equations),&lt;br /&gt;
            //   and is what creates the main &amp;quot;movement&amp;quot; in our preset.&lt;br /&gt;
            ret = tex2D( sampler_main, uv ).xyz;&lt;br /&gt;
&lt;br /&gt;
            // darken over time&lt;br /&gt;
            ret *= 0.97;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    There are only two instructions here... sample the old frame, and &lt;br /&gt;
    darken the old color value (color values are always in the 0..1 range)&lt;br /&gt;
    to prevent the screen from turning white over time.&lt;br /&gt;
    &lt;br /&gt;
    This code is run on every pixel on the screen.  If the UV's coming in&lt;br /&gt;
    were just [0..1] on X and Y, corresponding exactly to the location of&lt;br /&gt;
    the pixel on the screen, there would be no movement (or warp).  &lt;br /&gt;
    What creates the warp is that the UV coordinates are slightly &amp;quot;off&amp;quot;.&lt;br /&gt;
    Each frame, MilkDrop executes the per-vertex equations for the current &lt;br /&gt;
    preset at all the vertices on a grid covering the screen.  The resulting&lt;br /&gt;
    UV coordinates are then interpolated (by the GPU) between the vertices,&lt;br /&gt;
    and this shader code is executed at each pixel, with the UV coordinates&lt;br /&gt;
    smoothly interpolated for you to do your sampling.  Note that the &lt;br /&gt;
    original, un-distorted UV coordinates are always available in uv_orig.&lt;br /&gt;
    If the preset had no motion in it, or if we used uv_orig instead of uv, &lt;br /&gt;
    we would just see pixels getting darker over time, with no apparent motion.&lt;br /&gt;
    &lt;br /&gt;
    Note that MilkDrop's internal canvas (texture) can only store colors&lt;br /&gt;
    in the [0..1] range, so if your shader outputs values beyond that range,&lt;br /&gt;
    the values will be clipped to 0 or 1.  Within the body of the shader,&lt;br /&gt;
    you can go nuts, using any number ranges you want; this restriction only&lt;br /&gt;
    applies to the final output.&lt;br /&gt;
    &lt;br /&gt;
    Note that there are several ways to darken pixels over time, and the &lt;br /&gt;
    color precision (8 bits per color channel, or 256 shades, or [0..1] &lt;br /&gt;
    in increments of 0.004) means you have to be careful about darkening &lt;br /&gt;
    the color over time.  If you're going to darken using this:&lt;br /&gt;
&lt;br /&gt;
        ret *= 0.97;&lt;br /&gt;
&lt;br /&gt;
    then you shouldn't use a multiplier above 0.98, because, due to precision,&lt;br /&gt;
    dark-ish pixels will never become fully dark.  Another way to do it&lt;br /&gt;
    is this: &lt;br /&gt;
&lt;br /&gt;
        ret -= 0.004;&lt;br /&gt;
&lt;br /&gt;
    The above darkening method will make the pixels go dark, although, &lt;br /&gt;
    sometimes too quickly.  One way around this is to use error diffusion &lt;br /&gt;
    dithering (discussed later in this guide).  &lt;br /&gt;
    &lt;br /&gt;
    Probably the best thing is to combine the two:&lt;br /&gt;
&lt;br /&gt;
        ret = (ret - 0.002)*0.99;&lt;br /&gt;
&lt;br /&gt;
    This gives you a partially constant, partially linear darkening effect,&lt;br /&gt;
    and it tends to look the best.  Tweak the values as needed.&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
==== COMPOSITE SHADER ====&lt;br /&gt;
&lt;br /&gt;
    Here is an example of a simple COMPOSITE shader.  It is run over every&lt;br /&gt;
    pixel in the visualizer window, the output being the actual screen that&lt;br /&gt;
    you see.  Anything you do here will NOT affect the subsequent frame - &lt;br /&gt;
    it will only affect the display of the current frame.&lt;br /&gt;
        &lt;br /&gt;
        shader_body&lt;br /&gt;
        {&lt;br /&gt;
            // sample the corresponding pixel from the internal rendering canvas&lt;br /&gt;
            // note that, here, 'uv' is undistorted.&lt;br /&gt;
            // in the warp shader, 'uv' is warped, and 'uv_orig' is undistorted!&lt;br /&gt;
            ret = tex2D(sampler_main, uv).xyz;&lt;br /&gt;
            &lt;br /&gt;
            // make it a little bit &amp;quot;overbright&amp;quot;&lt;br /&gt;
            ret *= 1.8;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    The composite shader is easy to understand.  We just sample the&lt;br /&gt;
    internal canvas at the uv coords (undistorted here - but we could&lt;br /&gt;
    play with them if we want!), and manipulate the result if we want&lt;br /&gt;
    (here we brighten it a bit).  The &amp;quot;overbrightening&amp;quot; here is nice because &lt;br /&gt;
    pixels in the brighter ranges will (for display to the user only)&lt;br /&gt;
    wash out to a white color; however, they can stay that way&lt;br /&gt;
    for a bit.  If we just displayed the color as-is here, and &lt;br /&gt;
    instead drew our waveforms twice as bright, they would likely&lt;br /&gt;
    start out at white but very quickly fade to shades of grey.&lt;br /&gt;
    &lt;br /&gt;
    Note that we could do other fancy stuff here instead, like:&lt;br /&gt;
            &lt;br /&gt;
            float2 uv_flipped = 1 - uv;    // '1' auto-replicates to float2(1,1)&lt;br /&gt;
            ret = max( tex2D(sampler_main, uv).xyz, &lt;br /&gt;
                       tex2D(sampler_main, uv_flipped).xyz );&lt;br /&gt;
            ret = pow(ret, float3(0.5, 1, 2));&lt;br /&gt;
            &lt;br /&gt;
    This would flip the image about its diagonal, always show you&lt;br /&gt;
    the brighter pixel from the two orientations, and then ramp&lt;br /&gt;
    the R/G/B channels at different exponents to create a bit of &lt;br /&gt;
    a cepia color tone.  Not too tough!&lt;br /&gt;
    &lt;br /&gt;
    Now that you have an understanding of what the two shaders do,&lt;br /&gt;
    let's look at all the intrinsic types and operators you can use&lt;br /&gt;
    in shaders.&lt;br /&gt;
   &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
==== PIXEL SHADER REFERENCE ====&lt;br /&gt;
    ----------------------&lt;br /&gt;
    Here is a list of all the shader functions and operations at your disposal.&lt;br /&gt;
&lt;br /&gt;
    Data types&lt;br /&gt;
    ----------&lt;br /&gt;
      float       1-4 component full-precision floating-point values.&lt;br /&gt;
      float2        Use these for most things except color values.&lt;br /&gt;
      float3        (When working with UV coords, time values, or big ranges &lt;br /&gt;
      float4        of values, for example.)&lt;br /&gt;
      &lt;br /&gt;
      half        1-4 component half-precision floating-point values.&lt;br /&gt;
      half2         Much faster on some older hardware; although drivers usually &lt;br /&gt;
      half3         automatically substitute the 'half' type on you (behind your back) &lt;br /&gt;
      half4         wherever it is prudent.  Use 'half' for color values, or other &lt;br /&gt;
                    computations where precision is largely unimportant.&lt;br /&gt;
      &lt;br /&gt;
      float2x2    2d transformation matrix.  (Rotate and/or scale.)&lt;br /&gt;
      float3x2    2d transformation matrix.  (Rotate, scale, translation.)&lt;br /&gt;
      float3x3    3d transformation matrix.  (Rotate and/or scale.)&lt;br /&gt;
      float4x3    3d transformation matrix.  (Rotate, scale, translation.)&lt;br /&gt;
&lt;br /&gt;
    Operators  &lt;br /&gt;
    ----------&lt;br /&gt;
      + - * /     typical arithmetic operators.&lt;br /&gt;
      &lt;br /&gt;
      a += b      same as &amp;quot;a = a + b&amp;quot;.  Also valid:  -=  *=  /=&lt;br /&gt;
      &lt;br /&gt;
      ==          equality test.&lt;br /&gt;
      &amp;lt;           less than.&lt;br /&gt;
      &amp;lt;=          less than or equal to.&lt;br /&gt;
      &amp;gt;           greater than.&lt;br /&gt;
      &amp;gt;=          your mom is soo fat.&lt;br /&gt;
      &lt;br /&gt;
      var.x       swizzle operators.  You can stick a dot after any variable&lt;br /&gt;
      var.y       and put up to four letters after it.  If the variable is&lt;br /&gt;
      var.z       a float4, you can choose from x, y, z, and w; if it's a float2,&lt;br /&gt;
      var.w       just x and y; and so on.  The data type yielded can be different &lt;br /&gt;
      var.xy      than the input, and is determined by the number of letters after &lt;br /&gt;
      var.wzxy    the dot, and which fields (from the input) you chose.&lt;br /&gt;
      etc.        For example, if you had:&lt;br /&gt;
                    float  alpha = 104.37;&lt;br /&gt;
                    float2 bravo = float2(1,2);&lt;br /&gt;
                    float3 chuck = float3(10,20,30);&lt;br /&gt;
                    float4 delta = float4(5,6,7,8);&lt;br /&gt;
                  Then these swizzles would yield:&lt;br /&gt;
                    alpha.xxx  -&amp;gt;  float3(104.37, 104.37, 104.37)&lt;br /&gt;
                    bravo.yx   -&amp;gt;  float2(2,1)&lt;br /&gt;
                    chuck.z    -&amp;gt;  30&lt;br /&gt;
                    delta.wywy -&amp;gt;  float4(8,6,8,6)&lt;br /&gt;
&lt;br /&gt;
    Preprocessor&lt;br /&gt;
    ------------&lt;br /&gt;
      If you're familiar with C/C++, you can use simple things like&lt;br /&gt;
      #define, #if (condition) / #endif, #if / #elif/#else / #endif, and so on.&lt;br /&gt;
      &lt;br /&gt;
    &lt;br /&gt;
===== Intrinsic Instructions =====&lt;br /&gt;
&lt;br /&gt;
    Unless otherwise noted, these instructions all work on float, float2, float3, &lt;br /&gt;
    or float4 operands.&lt;br /&gt;
    &lt;br /&gt;
    math operations&lt;br /&gt;
    ---------------&lt;br /&gt;
    abs(a)        Absolute value.  Returns max(a, -a).&lt;br /&gt;
    frac(a)       Fractional value.  Returns (a - (int)a).  (the part after the decimal)&lt;br /&gt;
    floor(a)      Floor.  Returns ((int)a).  (the part before the decimal)&lt;br /&gt;
                    Only works on single floats.&lt;br /&gt;
    saturate(a)   Clamps a to the [0..1] range.  Often FREE (costs no extra instructions).&lt;br /&gt;
    max(a,b)      Returns the greater of each component between a and b.&lt;br /&gt;
    min(a,b)      Returns the lesser of each component between a and b.&lt;br /&gt;
    sqrt(a)       Returns square root of input(s).  Input should be &amp;gt;= 0.  Output always positive.&lt;br /&gt;
    pow(a,b)      Returns a^b.  b can be same type as a, or just a scalar (single float).&lt;br /&gt;
    exp(a)        Returns 2^a.&lt;br /&gt;
    log(a)        Returns log2(a).&lt;br /&gt;
    lerp(a,b,c)   Linear interpolate... blends from a to b based on the value of c[0..1].&lt;br /&gt;
                    (Or extrapolates, if c is outside [0..1] range.)&lt;br /&gt;
                    a and b must be same type; can can be that same type, or just float.&lt;br /&gt;
                    Returns a + c*(b-a).  Return type is same as a and b.&lt;br /&gt;
    dot(a,b)      Dot product.  All versions return A SINGLE FLOAT.&lt;br /&gt;
                    dot(float  a, float  b) returns a+b.&lt;br /&gt;
                    dot(float2 a, float2 b) returns a.x*b.x + a.y*b.y.&lt;br /&gt;
                    dot(float3 a, float3 b) returns a.x*b.x + a.y*b.y + a.z*b.z.&lt;br /&gt;
                    dot(float4 a, float4 b) returns a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w.&lt;br /&gt;
    lum(a)        Converts a color (float3) to greyscale, or &amp;quot;luminance&amp;quot;, for the human eye.&lt;br /&gt;
                    Returns dot(a, float3(0.32,0.49,0.29)).&lt;br /&gt;
                    Tip: oversaturate a color using &amp;quot;col = lerp(lum(col), col, 2);&amp;quot;&lt;br /&gt;
    length(a)     Input is float2, float3, or float4 vector; returns the length of the vector.&lt;br /&gt;
                    Returns sqrt(&lt;br /&gt;
    normalize(a)  Input is float2, float3, or float4 vector; normalizes it to unit length (1.0).&lt;br /&gt;
                    Returns a / length(a).&lt;br /&gt;
&lt;br /&gt;
    texture operations&lt;br /&gt;
    ------------------&lt;br /&gt;
    tex2D(sampler_name, uv)  &lt;br /&gt;
                  Samples a 2D texture at the coordinates 'uv', where UV is a float2.&lt;br /&gt;
                    Returns a float4 (r,g,b,alpha).&lt;br /&gt;
    &lt;br /&gt;
    tex3D(sampler_name, uvw)  &lt;br /&gt;
                  Samples a volume (3D) texture at the coordinates 'uvw', where UVW is a float3.&lt;br /&gt;
                  You could use this to sample a built-in &amp;quot;noise volume&amp;quot; or a volume texture &lt;br /&gt;
                    from a .DDS texture (that holds a 3D texture).&lt;br /&gt;
                    Returns a float4 (r,g,b,alpha).&lt;br /&gt;
&lt;br /&gt;
    GetBlur1(uv)  Samples a slightly-blurred version of the main texture &lt;br /&gt;
                    (internal canvas).  Input is float2; outputs (returns) a float3.&lt;br /&gt;
    GetBlur2(uv)  Samples a more-blurred version. &lt;br /&gt;
    GetBlur3(uv)  Samples a very blurry version.&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    mega-slow operations&lt;br /&gt;
    --------------------&lt;br /&gt;
    sin(a)        Returns cos(a), where a is in radians.  Output is in -1..1 range.&lt;br /&gt;
                    SLOW - use with care.&lt;br /&gt;
    cos(a)        Returns sin(a), where a is in radians.  Output is in -1..1 range.&lt;br /&gt;
                    SLOW - use with care.&lt;br /&gt;
    atan2(y,x)    Returns the arctangent of y/x.  In english, this means that if you give&lt;br /&gt;
                    it a Y and X coordinate (with the origin at zero), it will tell you&lt;br /&gt;
                    the angle you are at, with respect to the origin.  The signs of x and y &lt;br /&gt;
                    are used to determine the quadrant of the return values in the range &lt;br /&gt;
                    [-pi, pi].  atan2 is well-defined for every point other than the origin.&lt;br /&gt;
                    You basically always want to use it like this:&lt;br /&gt;
                        float2 uv2 = (uv-0.5)*aspect.xy;  // widescreen- or 4:3-friendly&lt;br /&gt;
                        float ang = atan2(uv2.y,uv2.x);&lt;br /&gt;
                    SLOW - use with care.&lt;br /&gt;
    mul(a,b)      Multiplies a vector and a matrix together.  You can treat the matrix&lt;br /&gt;
                    as row-major or column-major based on whether you do mul(vec,mat) &lt;br /&gt;
                    or mul(mat,vec).&lt;br /&gt;
    cross(a,b)    Cross product.  Returns (a.yzx*b.zxy - a.zxy*b.yzx).  &lt;br /&gt;
                    Input and output must be float3's.&lt;br /&gt;
                    Slow - use with care.&lt;br /&gt;
    if (a == b)   'If' blocks work in pixel shaders, although they can be very slow;&lt;br /&gt;
    {               the full code is always executed, whether the branch is taken or not.&lt;br /&gt;
      ...           You can use the equality operator, == (note the two equals signs! &lt;br /&gt;
    }               very important!) or the &amp;gt;, &amp;gt;=, &amp;lt;, or &amp;lt;= comparators.&lt;br /&gt;
    else &lt;br /&gt;
    { &lt;br /&gt;
      ... &lt;br /&gt;
    }&lt;br /&gt;
         &lt;br /&gt;
    Keep in mind that cos(), sin(), and atan2() are incredibly slow (~8 instructions).  &lt;br /&gt;
    Almost everything else (even divide, taking a reciprocal square root, etc.) is 1 &lt;br /&gt;
    or maybe, at most, 2 instructions.&lt;br /&gt;
              &lt;br /&gt;
    Note that the saturate() instruction, as well as multiplying by 2, 4, or 8, &lt;br /&gt;
    or dividing by 2, 4, or 8, is a free operation on many GPUs.  And the ALUs&lt;br /&gt;
    inside a GPU almost always do a multiply + add (both) in a single instruction.&lt;br /&gt;
    &lt;br /&gt;
    Also, you can divide by an integer constant without suffixing it with &amp;quot;.0&amp;quot;; &lt;br /&gt;
    in C/C++, &amp;quot;float x = 1/5;&amp;quot; will give you ZERO; but in shader language, it&lt;br /&gt;
    will give you what you expect: 0.2.&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
===== PER-VERTEX SHADER INPUTS =====&lt;br /&gt;
    ------------------------&lt;br /&gt;
    &lt;br /&gt;
    Warp shader:&lt;br /&gt;
    &lt;br /&gt;
      float2 uv;          // .xy = warped UV coords, ~[0..1]&lt;br /&gt;
      float2 uv_orig;     // .xy = original (un-warped) UV coords. [0..1]&lt;br /&gt;
      float  rad;         // radius of the current pixel from center of screen [0..1]&lt;br /&gt;
      float  ang;         // angle of the current pixel from center of screen [0..2*PI]&lt;br /&gt;
    &lt;br /&gt;
    Composite shader:&lt;br /&gt;
    &lt;br /&gt;
      float2 uv;          // .xy = [un-warped] UV coords.&lt;br /&gt;
      float  rad;         // radius of the current pixel from center of screen [0..1]&lt;br /&gt;
      float  ang;         // angle of the current pixel from center of screen [0..2*PI]&lt;br /&gt;
      float3 hue_shader;  // .xyz = a color that varies across the screen &lt;br /&gt;
                          //          (the old 'hue shader' effect from MilkDrop 1).&lt;br /&gt;
    &lt;br /&gt;
    Note that for both shaders, the vertex-interpolated angle value (ang) &lt;br /&gt;
    gets a bit wonky near the center of the screen, where it is very difficult to &lt;br /&gt;
    interpolate well (because it wraps suddenly from 0 to PI*2 at 9 o'clock on your &lt;br /&gt;
    screen).  If you see artifacts due to this, just use&lt;br /&gt;
    &lt;br /&gt;
      float better_ang = atan2(uv.y - 0.5, uv.x - 0.5);&lt;br /&gt;
      &lt;br /&gt;
    It's very slow, but will give you perfect results.  Also, if you want a slightly&lt;br /&gt;
    higher-quality value for the radius, use:&lt;br /&gt;
    &lt;br /&gt;
      float better_rad = length(uv - 0.5);&lt;br /&gt;
      &lt;br /&gt;
    The unwarped UV values will always be of impeccable quality, though, &lt;br /&gt;
    because they will be interpolated in the direction that they vary, &lt;br /&gt;
    and the rectilinear mesh is aligned perfectly for this.&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
===== PER-FRAME SHADER INPUTS =====&lt;br /&gt;
&lt;br /&gt;
    MilkDrop feeds lots of data into the the shaders.  Here is a list of everything&lt;br /&gt;
    that the shaders can access.&lt;br /&gt;
    &lt;br /&gt;
      float4 rand_preset;  // 4 random floats [0..1], updated once per preset&lt;br /&gt;
      float4 rand_frame;   // 4 random floats [0..1], updated each frame&lt;br /&gt;
      float  time;         // the time, in seconds, starting at zero when the *preset* starts.  &lt;br /&gt;
                           //   (wraps back to zero after 10,000 seconds locked on a single preset.)&lt;br /&gt;
      float  fps;          // the current framerate (frames per second).&lt;br /&gt;
      float  frame;        // the current frame #.&lt;br /&gt;
      float  progress;     // the progress through the current preset.  [0..1]&lt;br /&gt;
      &lt;br /&gt;
      float  bass;         // immediate info about audio levels,&lt;br /&gt;
      float  mid;          //  just like in the per-frame equations,&lt;br /&gt;
      float  treb;         //   etc.&lt;br /&gt;
      float  vol;          // &lt;br /&gt;
      float  bass_att;     // slightly dampened info about audio levels.&lt;br /&gt;
      float  mid_att;      //  look at bass/bass_att, for example;&lt;br /&gt;
      float  treb_att;     //   if it's &amp;gt;1, then the bass is spiking.&lt;br /&gt;
      float  vol_att;      // &lt;br /&gt;
      &lt;br /&gt;
      float4 aspect        // .xy: multiplier to use on UV's to paste an image fullscreen, *aspect-aware*; .zw = inverse.&lt;br /&gt;
      float4 texsize       // info about the size of the internal canvas, in pixels.&lt;br /&gt;
                           //   .xy = (width,height); .zw = (1/(float)w, 1/(float)h)&lt;br /&gt;
      &lt;br /&gt;
      // here are some values that roam around in the [0..1] range at varying speeds.&lt;br /&gt;
      float4 slow_roam_cos // .xyzw ~= 0.5 + 0.5*cos(time * float4(~0.005, ~0.008, ~0.013, ~0.022))&lt;br /&gt;
      float4 roam_cos      // .xyzw ~= 0.5 + 0.5*cos(time * float4(~0.3, ~1.3, ~5, ~20))           &lt;br /&gt;
      // here are the corresponding sine values, in case you want them.&lt;br /&gt;
      // pick a cos/sin pair and use the same accessor on it (.x, .z, etc.)&lt;br /&gt;
      // to get plot a point making a circle over time.&lt;br /&gt;
      float4 slow_roam_sin // .xyzw ~= same, but using sin()                                       &lt;br /&gt;
      float4 roam_sin      // .xyzw ~= same, but using sin()                                       &lt;br /&gt;
      // of course, if you want anything more complicated, just generate it&lt;br /&gt;
      // yourself in the per-frame equations, save it in q1-q32, and it will&lt;br /&gt;
      // be available to your shaders!&lt;br /&gt;
&lt;br /&gt;
      float  q1;           // The values of the q1-q32 variables, &lt;br /&gt;
      float  q2;           //  as output by the preset's per-frame equations.&lt;br /&gt;
      //...                //&lt;br /&gt;
      float  q31;          //&lt;br /&gt;
      float  q32;          //&lt;br /&gt;
      &lt;br /&gt;
      float4 _qa;          // q1-q4    The values of the q1-q32 variables,&lt;br /&gt;
      float4 _qb;          // q5-q8     grouped into float4's &lt;br /&gt;
      float4 _qc;          // q9-q12     for more convenient access.&lt;br /&gt;
      float4 _qd;          // q13-q16&lt;br /&gt;
      float4 _qe;          // q17-q20&lt;br /&gt;
      float4 _qf;          // q21-q24&lt;br /&gt;
      float4 _qg;          // q25-q28&lt;br /&gt;
      float4 _qh;          // q29-q32&lt;br /&gt;
      &lt;br /&gt;
      float  blur1_min     // these are the values of the min/max&lt;br /&gt;
      float  blur1_max     //  allowable color values for the 3 blur passes,&lt;br /&gt;
      float  blur2_min     //   as set from the onscreen menus.&lt;br /&gt;
      float  blur2_max     //    more info below.&lt;br /&gt;
      float  blur3_min     // &lt;br /&gt;
      float  blur3_max     // &lt;br /&gt;
      &lt;br /&gt;
      // note/warning: in general, don't use the current time value&lt;br /&gt;
      // as an input to the *dynamic* rotations; as time gets large,&lt;br /&gt;
      // the results will become total chaos.&lt;br /&gt;
      float4x3 rot_s1;  // four random, static rotations.  &lt;br /&gt;
      float4x3 rot_s2;  //  randomized @ preset load time.&lt;br /&gt;
      float4x3 rot_s3;  //   minor translation component (&amp;lt;1).&lt;br /&gt;
      float4x3 rot_s4;&lt;br /&gt;
      &lt;br /&gt;
      float4x3 rot_d1;  // four random, slowly changing rotations.&lt;br /&gt;
      float4x3 rot_d2;  &lt;br /&gt;
      float4x3 rot_d3;&lt;br /&gt;
      float4x3 rot_d4;&lt;br /&gt;
      &lt;br /&gt;
      float4x3 rot_f1;  // faster-changing.&lt;br /&gt;
      float4x3 rot_f2;&lt;br /&gt;
      float4x3 rot_f3;&lt;br /&gt;
      float4x3 rot_f4;&lt;br /&gt;
      &lt;br /&gt;
      float4x3 rot_vf1;  // very-fast-changing.&lt;br /&gt;
      float4x3 rot_vf2;&lt;br /&gt;
      float4x3 rot_vf3;&lt;br /&gt;
      float4x3 rot_vf4;&lt;br /&gt;
      &lt;br /&gt;
      float4x3 rot_uf1;  // ultra-fast-changing.&lt;br /&gt;
      float4x3 rot_uf2;&lt;br /&gt;
      float4x3 rot_uf3;&lt;br /&gt;
      float4x3 rot_uf4;&lt;br /&gt;
      &lt;br /&gt;
      float4x3 rot_rand1; // random every frame&lt;br /&gt;
      float4x3 rot_rand2;&lt;br /&gt;
      float4x3 rot_rand3;&lt;br /&gt;
      float4x3 rot_rand4;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
==== TEXTURE SAMPLING ====&lt;br /&gt;
    We've already used one texture: the internal canvas, also called &amp;quot;Main&amp;quot;.&lt;br /&gt;
    Because it's always being used, you don't have to declare it.  You can&lt;br /&gt;
    just sample it.  However, you have some options for how to sample it.&lt;br /&gt;
    There are four samplers tied to the Main canvas:&lt;br /&gt;
      &lt;br /&gt;
                                                 BEHAVIOR OUTSIDE &lt;br /&gt;
        SAMPLER NAME       FILTERING METHOD      [0..1] UV RANGE&lt;br /&gt;
        ------------       ----------------      ----------------&lt;br /&gt;
        sampler_fw_main*   bilinear filtering    wrap&lt;br /&gt;
        sampler_fc_main    bilinear filtering    clamp&lt;br /&gt;
        sampler_pw_main    point sampling        wrap&lt;br /&gt;
        sampler_pc_main    point sampling        clamp&lt;br /&gt;
        &lt;br /&gt;
        * you can also just use &amp;quot;sampler_main&amp;quot; for this one,&lt;br /&gt;
          since it's by far the most common.&lt;br /&gt;
      &lt;br /&gt;
    When you go to sample a texture, the GPU finds the exact spot&lt;br /&gt;
    in the texture that the UV coordinates point to.  The chances&lt;br /&gt;
    are good that it falls in between 4 texels (pixels) rather than&lt;br /&gt;
    perfectly on one of them.  If you use bilinear filtering to &lt;br /&gt;
    sample, it will return a properly-weighted average of the four &lt;br /&gt;
    pixels.  If you use point sampling, it will just return the &lt;br /&gt;
    nearest single pixel (also called &amp;quot;nearest neighbor&amp;quot;).&lt;br /&gt;
    &lt;br /&gt;
    Wrap vs. clamp is also pretty simple: if you specify a UV coord&lt;br /&gt;
    of float2(-0.1, 0.5), the wrap mode would map this to (0.9, 0.5),&lt;br /&gt;
    while the clamp mode would clamp it at (0.0, 0.5).  Wrap mode&lt;br /&gt;
    tends to create tiled images, while clamp mode takes the border&lt;br /&gt;
    color and extends it out infinitely.&lt;br /&gt;
    &lt;br /&gt;
    In general, other textures can be sampled similarly, using these &lt;br /&gt;
    same two-letter prefixes (&amp;quot;_fw&amp;quot;, &amp;quot;_pc&amp;quot;, etc.).  Or, you can &lt;br /&gt;
    always just leave off the prefix, and MilkDrop will assume you &lt;br /&gt;
    want to do &amp;quot;_fw&amp;quot; - bilinear filtering and wrap mode - the defaults.&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
===== MILKDROP'S BUILT-IN TEXTURES - MAIN, BLUR, and NOISE =====&lt;br /&gt;
    MilkDrop has several built-in textures you can sample from.  &lt;br /&gt;
    &lt;br /&gt;
    MAIN&lt;br /&gt;
    ----&lt;br /&gt;
    First, there is the Main texture (the internal canvas).  As already &lt;br /&gt;
    mentioned, you can sample from it by using sampler_main or one&lt;br /&gt;
    of its variants.&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
===== BLUR1, BLUR2, BLUR3 =====&lt;br /&gt;
&lt;br /&gt;
    Next, there are several blurred versions of the main texture.&lt;br /&gt;
    These are called Blur1, Blur2, and Blur3.  Each one is &lt;br /&gt;
    progressively blurrier.  You can access them using these special&lt;br /&gt;
    functions: &lt;br /&gt;
&lt;br /&gt;
        GetBlur1(uv)     // these take a float2 as input&lt;br /&gt;
        GetBlur2(uv)     // &amp;amp; return a float3 color value&lt;br /&gt;
        GetBlur3(uv)    &lt;br /&gt;
        &lt;br /&gt;
    GetBlur1 returns a slightly blurred image, GetBlur2 a more blurry image, &lt;br /&gt;
    and GetBlur3 an extremely blurry image.  A call to one of the GetBlur &lt;br /&gt;
    functions is very fast, but keep in mind that the blur textures are only &lt;br /&gt;
    generated each frame if the shaders actually use them, and the results&lt;br /&gt;
    find their way into the final output color value of the pixel shader!&lt;br /&gt;
    Blur1 is the fastest to generate; then Blur2 (because it is generated&lt;br /&gt;
    from Blur1); and finally, Blur3 is the slowest (generated from Blur2).    &lt;br /&gt;
    &lt;br /&gt;
    Here is an example of how to use one:&lt;br /&gt;
    &lt;br /&gt;
        float3 blurry = GetBlur2(uv);&lt;br /&gt;
    &lt;br /&gt;
    You could add this to your sample from the Main texture to&lt;br /&gt;
    produce a softer-looking image, for example.  Or, you could&lt;br /&gt;
    do an edge detect in the composite shader, by taking the &lt;br /&gt;
    [absolute value of the] difference between the crisp and blurred&lt;br /&gt;
    main textures:&lt;br /&gt;
    &lt;br /&gt;
        float3 crisp = tex2D(sampler_main, uv).xyz;&lt;br /&gt;
        float3 blurry = GetBlur1(uv);&lt;br /&gt;
        ret = abs( crisp - blurry )*4;&lt;br /&gt;
    &lt;br /&gt;
    The &amp;quot;skin dots&amp;quot; effect in some of the presets (it makes spots &lt;br /&gt;
    and stripes like you might see on fish or leopards, in nature)&lt;br /&gt;
    is based on a very mild edge-detect in the *warp* shader,&lt;br /&gt;
    and uses it to enforce a certain amount of variance in the &lt;br /&gt;
    color values.  It also serves to break up large areas of solid&lt;br /&gt;
    white pixels.&lt;br /&gt;
    &lt;br /&gt;
    Note that you can do some cool glow effects by raising the&lt;br /&gt;
    &amp;quot;min&amp;quot; values above 0.  Say, for example, you set blur1_min&lt;br /&gt;
    to 0.5.  That means that any pixels with color values below &lt;br /&gt;
    0.5 will get clipped to 0.5.  So, when you call GetBlur1(),&lt;br /&gt;
    it's going to give you values in the range [0.5 .. 1.0].  &lt;br /&gt;
    However, because you were only using half the range of possible&lt;br /&gt;
    values, the precision of these values will be twice as good.&lt;br /&gt;
    That's the purpose of the min/max values.  Watch out, though -&lt;br /&gt;
    having your values clipped to a minimum of 0.5 would look bad&lt;br /&gt;
    if you actually had colors that are over 0.5, and you're not &lt;br /&gt;
    subtracting that 0.5 off.&lt;br /&gt;
    &lt;br /&gt;
    However, if you do set a min and then subtract it off, you can &lt;br /&gt;
    also get some great glow effects, where only really&lt;br /&gt;
    bright pixels contribute to the &amp;quot;glow&amp;quot;  If you set the min to &lt;br /&gt;
    0.7, for example, and then sample like this:&lt;br /&gt;
        &lt;br /&gt;
        ret += (GetBlur1(uv) - blur1_min)*2;&lt;br /&gt;
        &lt;br /&gt;
    It will subtract off the 0.7 minimum threshold, but because&lt;br /&gt;
    of the clipping, you will basically just see the bright&lt;br /&gt;
    pixels &amp;quot;glowing&amp;quot;.  The *2 is just for a little extra glow.&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
===== NOISE TEXTURES =====&lt;br /&gt;
&lt;br /&gt;
    There are also &amp;quot;noise&amp;quot; (random value) textures built in to MilkDrop.  &lt;br /&gt;
    They are generated when MilkDrop starts, but only so the large amount&lt;br /&gt;
    of (random) data wouldn't bloat the size of the MilkDrop download.&lt;br /&gt;
    They vary in the quality (smoothness) of the noise, as well as&lt;br /&gt;
    how often the pattern repeats itself.  Always use the smallest&lt;br /&gt;
    possible noise texture (_lite or _lq versions) when possible.&lt;br /&gt;
    &lt;br /&gt;
    Here are the details on the six textures:&lt;br /&gt;
    &lt;br /&gt;
    NAME           DIMS  PIXELS    QUALITY&lt;br /&gt;
    ----           ----  ------    ---------&lt;br /&gt;
    noise_lq       2D    256x256   low&lt;br /&gt;
    noise_lq_lite  2D    32x32     low&lt;br /&gt;
    noise_mq       2D    64x64     medium&lt;br /&gt;
    noise_hq       2D    32x32     high&lt;br /&gt;
    noisevol_lq    3D    32x32x32  low&lt;br /&gt;
    noisevol_hq    3D    8x8x8     high&lt;br /&gt;
    &lt;br /&gt;
    Notice that four of them are two-dimensional (use tex2D(float2 uv) &lt;br /&gt;
    to sample them), and two of them are three-dimensional (use &lt;br /&gt;
    tex3D(float3 uvw) to sample them).  &lt;br /&gt;
    &lt;br /&gt;
    They come in at various sizes.  You should always use the smallest&lt;br /&gt;
    one necessary, to be video memory cache-friendly!&lt;br /&gt;
    &lt;br /&gt;
    The _lq, _mq, and _hq suffixes denote low, medium, or high quality.&lt;br /&gt;
    The _lq textures have one random value at every texel in the &lt;br /&gt;
    texture.  But the _mq textures have (generally) about four texels&lt;br /&gt;
    per random value, with high-quality [cubic] filtering baked into the &lt;br /&gt;
    texture.  (Sometimes you just want something better than bilinear&lt;br /&gt;
    filtering, you know?)  The high-quality textures usually have about&lt;br /&gt;
    8 texels for every random value.  The sizes given here, in pixels,&lt;br /&gt;
    are actually abstractions - they are the conceptual # of pixels&lt;br /&gt;
    (values) before repetition.  In reality, the textures are bigger &lt;br /&gt;
    (for medium &amp;amp; high quality), and the extra texels are all filled &lt;br /&gt;
    in using high-quality interpolation.  &lt;br /&gt;
    &lt;br /&gt;
    The higher-quality textures aren't any slower to use, as long as&lt;br /&gt;
    you're sampling them at the right frequency.  If you sample any&lt;br /&gt;
    of these at too high a frequency (i.e. tile them like crazy /&lt;br /&gt;
    multiply the UV's by a large number) your video memory texture&lt;br /&gt;
    cache will bring your GPU to a grinding halt.  Don't do it!&lt;br /&gt;
&lt;br /&gt;
    If using Noise textures with the default sampler settings (filtering &lt;br /&gt;
    and wrap), you don't need to declare them above the shader_body; they &lt;br /&gt;
    are always available.  However, if you want to sample them with &lt;br /&gt;
    special options (clamping or point sampling), then you do have to.  &lt;br /&gt;
    (ex: &amp;quot;sampler sampler_fc_noise_lq&amp;quot;, or &amp;quot;sampler_pw_noise_lq&amp;quot;).&lt;br /&gt;
    &lt;br /&gt;
    To sample a color value from a noise texture, add code like this:&lt;br /&gt;
    &lt;br /&gt;
        float4 noiseVal = tex2D(sampler_noise_lq, uv_orig );&lt;br /&gt;
        &lt;br /&gt;
    This returns a float4 of values in the [0..1] range.  However, the noise&lt;br /&gt;
    image will be stretched up so the 64x64 pixels cover the screen.  What we'd &lt;br /&gt;
    really like is to tile it so the noise values map 1:1 to pixels on the&lt;br /&gt;
    screen.  &lt;br /&gt;
    &lt;br /&gt;
    To do this, we need to invoke another handy feature: you can fetch the size &lt;br /&gt;
    of any texture in MilkDrop.  Just declare a float4 (still outside the shader &lt;br /&gt;
    body) with the name of the texture, preceded by &amp;quot;texsize_&amp;quot; - like this:&lt;br /&gt;
    &lt;br /&gt;
        float4  texsize_noise_lq;  // .xy = (w,h); .zw = (1/(float)w, 1/(float)h)&lt;br /&gt;
    &lt;br /&gt;
    Also, recall that the size of the Main canvas is universally available to&lt;br /&gt;
    all shaders, and looks like this: (this is auto-declared for you, by the way)&lt;br /&gt;
      &lt;br /&gt;
        float4 texsize       // .xy = (w,h); .zw = (1/(float)w, 1/(float)h)&lt;br /&gt;
    &lt;br /&gt;
    So, if we change our sampling code to look like this:&lt;br /&gt;
    &lt;br /&gt;
        float4 noiseVal = tex2D(sampler_noise_lq, uv_orig*texsize.xy*texsize_noise_lq.zw );&lt;br /&gt;
    &lt;br /&gt;
    It's going to do exactly that.  This is a very common and useful technique.  &lt;br /&gt;
    uv_orig gives you the original (unwarped)&lt;br /&gt;
    UV coordinates [0..1].  If we then multiply by texsize.xy, we get the &lt;br /&gt;
    pixel number we are on.  For example, if the screen was 1280 x 1024 pixels,&lt;br /&gt;
    we'd get float2 in the range [0..1279, 0..1023].  If we then multiply by&lt;br /&gt;
    texsize_noise_lq.zw, we're dividing by the size of the noise texture,&lt;br /&gt;
    in pixels (this one is 256x256).  So, we'd end up with UV coords roughly &lt;br /&gt;
    in the range [0..5, 0..4] - our image has been perfect tiled onto the&lt;br /&gt;
    screen, with the pixels displaying 1:1.&lt;br /&gt;
    &lt;br /&gt;
    This can be used to mix a bit of random noise into the image each frame, &lt;br /&gt;
    which can increase image quality - it's similar to error diffusion &lt;br /&gt;
    dithering (which is one of the things that set the original Geiss &lt;br /&gt;
    plugin/screensaver apart from the others, image-quality wise!).   You &lt;br /&gt;
    can ponder the reasons why.  Also, further adding &amp;quot;rand_frame.xy&amp;quot; to the &lt;br /&gt;
    UV coords will reposition the noise values every frame, making it seem&lt;br /&gt;
    like truly random [changing] noise:&lt;br /&gt;
    &lt;br /&gt;
        float2 noise_uv = uv_orig*texsize.xy*texsize_noise_lq.zw + rand_frame.xy;&lt;br /&gt;
        float4 noiseVal = tex2D(sampler_noise_lq, noise_uv);&lt;br /&gt;
    &lt;br /&gt;
    To add random dithering (which, statistically, is the same as error-&lt;br /&gt;
    diffusion dithering), try this:&lt;br /&gt;
    &lt;br /&gt;
        float2 uv_noise = uv_orig*texsize.xy*texsize_noise_lq.zw + rand_frame.xy;&lt;br /&gt;
        half4 noiseVal = tex2D(sampler_noise_lq, uv_noise);&lt;br /&gt;
        ret = tex2D(sampler_main, uv);&lt;br /&gt;
        ret += (noiseVal.xyz*2-1) * 0.01;&lt;br /&gt;
        &lt;br /&gt;
    This will add a good deal of noise into the image each frame.  Adding&lt;br /&gt;
    'rand_frame.xy' to the UV coordinate serves to randomly place&lt;br /&gt;
    the noise texture each frame, preventing the noise imprint from being&lt;br /&gt;
    exactly the same each frame, which would cause artifact buildup.&lt;br /&gt;
&lt;br /&gt;
    Important: Note that the medium- and high-quality textures should never be &lt;br /&gt;
    used for 1:1 mapping! - it is a huge waste.  You will only benefit from their&lt;br /&gt;
    higher quality if you are *zoomed in* on these textures, seeing them&lt;br /&gt;
    magnified, sampling them at a low frequency.  If they are minified &lt;br /&gt;
    (sampled at a high frequency / zoomed out of) or even displayed at 1:1, &lt;br /&gt;
    you will thrash your video memory cache and the preset will run very &lt;br /&gt;
    slow.&lt;br /&gt;
        &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
===== READING TEXTURES FROM DISK =====&lt;br /&gt;
&lt;br /&gt;
    Declaring and sampling from your own textures is easy.  First,&lt;br /&gt;
    create your texture.  If you plan on sharing your presets with&lt;br /&gt;
    other people, please make your texture SMALL (256x256 or less)&lt;br /&gt;
    and save it as a JPG file at 95% quality.  The file size should&lt;br /&gt;
    be between 10k and 50k (kilobytes).  Of course, the textures&lt;br /&gt;
    could be huge, crisp photos if you want - they will just be&lt;br /&gt;
    heavy (to send to other people) and will cause a little delay&lt;br /&gt;
    when you switch to a preset that uses them (and loads the texture).  &lt;br /&gt;
    &lt;br /&gt;
    Save the texture to the folder:&lt;br /&gt;
    &lt;br /&gt;
        c:\program files\winamp\plugins\milkdrop2\textures&lt;br /&gt;
        &lt;br /&gt;
    or wherever you installed Winamp and MilkDrop to.  Let's imagine&lt;br /&gt;
    you called your texture billy.jpg.&lt;br /&gt;
    &lt;br /&gt;
    Then, in any shader, above the shader_body section, declare a sampler &lt;br /&gt;
    for the texture:&lt;br /&gt;
    &lt;br /&gt;
        sampler sampler_billy;&lt;br /&gt;
        &lt;br /&gt;
    That's all you have to do.  It will find the file (billy.jpg)&lt;br /&gt;
    and load it.  Note that the sampler name DOES have to start with &lt;br /&gt;
    &amp;quot;sampler_&amp;quot;, and if you want, you could prefix it with &amp;quot;sampler_pc_&amp;quot; &lt;br /&gt;
    or &amp;quot;sampler_fw_&amp;quot; (or whatever) to turn on texture clamp and/or point &lt;br /&gt;
    sampling.  &lt;br /&gt;
    &lt;br /&gt;
    Texture formats supported include: [in order of priority]&lt;br /&gt;
        &lt;br /&gt;
        jpg   (great compression)&lt;br /&gt;
        dds   (a microsoft/directx format - very flexible - can even do 3D)&lt;br /&gt;
        png   (portable network graphics; can give you compress w/an alpha channel)&lt;br /&gt;
        tga   (truevision Targa - 1, 3, or 4 channels)&lt;br /&gt;
        bmp   (puke)&lt;br /&gt;
        dib   (puke)&lt;br /&gt;
        &lt;br /&gt;
    Now that you've declared the texture, you can sample it like this, &lt;br /&gt;
    from within the shader_body section:&lt;br /&gt;
    &lt;br /&gt;
        float3 mypixel = tex2D(sampler_billy, uv2).xyz;&lt;br /&gt;
        &lt;br /&gt;
    So first it will try to find billy.jpg; then billy.dds; and so&lt;br /&gt;
    on, until it finds a valid texture.  If the texture can not be&lt;br /&gt;
    found in the &amp;quot;milkdrop2\textures&amp;quot; directory, it will then also try&lt;br /&gt;
    to find it **in the current preset directory**; this is done so that&lt;br /&gt;
    preset downloaders can be lazy and just put the presets, along&lt;br /&gt;
    with the textures that come with them, into the same directory.&lt;br /&gt;
    &lt;br /&gt;
    If your shader wants to know how big the texture is, declare this&lt;br /&gt;
    (also above the shader_body section):&lt;br /&gt;
    &lt;br /&gt;
        float4 texsize_billy;    // .xy = (w,h); .zw = (1/w, 1/h)&lt;br /&gt;
        &lt;br /&gt;
    MilkDrop will see the &amp;quot;texsize_&amp;quot; prefix and automatically know what&lt;br /&gt;
    to do.  (You don't have to include the //comment, of course.)&lt;br /&gt;
    &lt;br /&gt;
    To stretch this texture to cover the screen, do this (in the shader&lt;br /&gt;
    body):&lt;br /&gt;
&lt;br /&gt;
        ret = tex2D(sampler_billy, uv).xyz;&lt;br /&gt;
    &lt;br /&gt;
    Or to map it fitted to the screen, aspect-aware:&lt;br /&gt;
    &lt;br /&gt;
        ret = tex2D(sampler_billy, uv * aspect.xy).xyz;&lt;br /&gt;
    &lt;br /&gt;
    Or to tile it so the pixels are represented 1:1:&lt;br /&gt;
    &lt;br /&gt;
        ret = tex2D(sampler_billy, uv * texsize.xy * texsize_billy.zw).xyz;&lt;br /&gt;
        &lt;br /&gt;
    Or to map it tiled exactly 5 times:&lt;br /&gt;
&lt;br /&gt;
        ret = tex2D(sampler_billy, uv * 5).xyz;&lt;br /&gt;
&lt;br /&gt;
    Or to zoom into the center 20% of the image:&lt;br /&gt;
&lt;br /&gt;
        ret = tex2D(sampler_billy, (uv-0.5)*0.2 + 0.5 ).xyz;&lt;br /&gt;
        &lt;br /&gt;
    Of course, you could also declare sampler_pw_billy, to do point&lt;br /&gt;
    sampling, or sampler_fc_billy, for clamping, and so on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
===== RANDOM TEXTURE SELECTION =====&lt;br /&gt;
    ------------------------&lt;br /&gt;
    You can also load in a random texture.  Just use the name &amp;quot;rand00&amp;quot;&lt;br /&gt;
    through &amp;quot;rand15&amp;quot; as the filename, and MilkDrop will pick a random&lt;br /&gt;
    file and do the rest.  The texsize_ parameters work too.  For example:&lt;br /&gt;
    &lt;br /&gt;
        sampler sampler_rand07;&lt;br /&gt;
        float4  texsize_rand07;&lt;br /&gt;
                &lt;br /&gt;
        shader_body &lt;br /&gt;
        {    &lt;br /&gt;
          ...&lt;br /&gt;
          float3 color = tex2D(sampler_rand07, uv);&lt;br /&gt;
          ...&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    You can also choose from random subsets of textures on disk!  Say you&lt;br /&gt;
    have a whole slew of random textures in your textures\ subdirectory,&lt;br /&gt;
    but you have a subset in there that begin with the word &amp;quot;smalltiled&amp;quot;.&lt;br /&gt;
    If you specify:&lt;br /&gt;
    &lt;br /&gt;
        sampler sampler_rand02_smalltiled;&lt;br /&gt;
        float4  texsize_rand02;    // ...it's smart enough to get it from just this.&lt;br /&gt;
        &lt;br /&gt;
        shader_body &lt;br /&gt;
        {    &lt;br /&gt;
          ...&lt;br /&gt;
          float3 color = tex2D(sampler_rand07_smalltiled, uv);&lt;br /&gt;
          ...&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
    Then every time the preset loads (or the shader is recompiled), it's&lt;br /&gt;
    going to pick a new random texture, but it will choose only from the&lt;br /&gt;
    subset of those textures whose names begin with &amp;quot;smalltiled&amp;quot;.  &lt;br /&gt;
&lt;br /&gt;
    One last thing, a tip: if you are working in windowed mode (or multimon)&lt;br /&gt;
    and added textures to the directory and haven't yet exited the plugin, &lt;br /&gt;
    to force the list of textures to update itself, edit one of the shaders &lt;br /&gt;
    (any shader) and then hit CTRL+ENTER (accept).  That will trigger it&lt;br /&gt;
    to rescan the directory (but only if it needs to, because your shaders&lt;br /&gt;
    ask for random textures).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
==== MISC. COOL SHADER TRICKS ====&lt;br /&gt;
    &lt;br /&gt;
AUTO CENTER DARKENING&lt;br /&gt;
&lt;br /&gt;
MilkDrop 1 had a cool feature, &amp;quot;center darken&amp;quot;, that would quickly dampen &lt;br /&gt;
bright pixels placed at the center of the screen, because in &amp;quot;zoomy&amp;quot; &lt;br /&gt;
(forward motion) presets, the screen would quickly become all white&lt;br /&gt;
if you didn't.  As presets get more sophisticated, though, where the&lt;br /&gt;
&amp;quot;center&amp;quot; of the zooming motion is can be very hard to pinpoint.&lt;br /&gt;
        &lt;br /&gt;
You can actually find it algorithmically.  Wherever on the screen you&lt;br /&gt;
have warped UV coordinates that are very close to the original UV&lt;br /&gt;
coordinates, it means there's either no motion there, or it's the&lt;br /&gt;
center of motion - you'll know, based on what kind of preset you're&lt;br /&gt;
writing.  If it's a &amp;quot;zoomy&amp;quot; preset, it's probably the latter.  In this&lt;br /&gt;
case, just use something like this in your warp shader:&lt;br /&gt;
        &lt;br /&gt;
 // this darkens the pixels at the center of the zoom, only&lt;br /&gt;
 ret *= 0.97 + 0.03*saturate( length(uv - uv_orig)*200 );  &lt;br /&gt;
&lt;br /&gt;
RANDOM DIFFUSION DITHER&lt;br /&gt;
&lt;br /&gt;
See above, in the &amp;quot;noise&amp;quot; section.&lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
SOFT MAX&lt;br /&gt;
&lt;br /&gt;
The max(a,b) function returns the max. value for each channel &lt;br /&gt;
of the two inputs, however, this can have a discontinuous&lt;br /&gt;
look sometimes, as it switches from a to b or back suddenly.&lt;br /&gt;
If you want a not-so-accurate, but smoother, max function,&lt;br /&gt;
try this:&lt;br /&gt;
        &lt;br /&gt;
 a + b - a*b&lt;br /&gt;
        &lt;br /&gt;
Note that the inputs must be in the [0..1] range.&lt;br /&gt;
&lt;br /&gt;
==== QUALITY ASSURANCE FOR SHADERS ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*Please*&amp;lt;/nowiki&amp;gt; adhere to these guidelines when writing shaders...&lt;br /&gt;
# use small (256x256 or less) textures; save as jpg 95% so your presets are small to download, and so they load w/o a pause.&lt;br /&gt;
# make sure your shaders are zippy.  &lt;br /&gt;
#* avoid 'if' statements.&lt;br /&gt;
#* avoid &amp;quot;massive zoom-outs&amp;quot; of any texture.  Sampling textures at too high a frequency thrashes your texture cache and will drop your framerate like mad.  Sample things near 1:1, or feel free to zoom in close on them, but avoid extreme zoom-outs.&lt;br /&gt;
#* avoid sin() and cos() functions if you can.  If their inputs don't vary from pixel to pixel, calculate the sin/cos values in the per-frame equations, then store them in q1-q32, and read them into your shader from there.&lt;br /&gt;
#* any calculation that results in the same value for all pixels on the screen should be offloaded into MilkDrop's per-frame equations, then passed to the shader via the q1-q32 variables. These variables are directly accessible from all shaders (q1, q2, etc.) and can also be read in as float4's for convenience (q1-q4 make up a float4 called _qa; q5-q8 come together in _qb; etc.).&lt;br /&gt;
#* also avoid doing motion/warping calculations in the warp shader, that you could do in the per-vertex equations.  Those run on the CPU, which is a huge resource that is almost never completely used; the GPU, although processing 1,000 times as much math because it works per-pixel instead of per-vertex, can use as much of a break as it can get.  Any low-frequency effects (values that vary slowly over the screen) should go in the per-vertex equations, and only the high-frequency component of the motion or warping should come from the pixel shader.&lt;br /&gt;
#* keep in mind that the DirectX shader compiler is superb at optimizing; anything that can be thrown out, will be.  Things like &lt;br /&gt;
 ret *= 1.0;&lt;br /&gt;
 ret += 0;&lt;br /&gt;
 ret += tex2D(mytex, uv).xyz * 0;&lt;br /&gt;
will completely disappear.  If you sample a texture and then the&lt;br /&gt;
sample doesn't end up making it into the final output color value,&lt;br /&gt;
the texture will never even get bound (or loaded from disk), &lt;br /&gt;
let alone sampled.  And so on.&lt;br /&gt;
#* you can use the 'half' type wherever you don't need full 'float' &lt;br /&gt;
precision.  Generally use 'float' for UVs and time values, and &lt;br /&gt;
'half' for almost everything else.  However, don't stress about it &lt;br /&gt;
too much, because most GPUs run&lt;br /&gt;
everything at full-precision &amp;amp; full-speed nowadays - and for the&lt;br /&gt;
older GPUs that don't, the driver is probably very smart (if it's&lt;br /&gt;
an Nvidia or ATI card) about auto-substituting halfs for floats&lt;br /&gt;
wherever possible.            &lt;br /&gt;
# before sharing your presets, please make sure they look good in a &lt;br /&gt;
SQUARE or WIDESCREEN window.  If they don't, scan these guidelines&lt;br /&gt;
and you will probably be able to easily fix it.&lt;br /&gt;
          &lt;br /&gt;
The overall design goal in MilkDrop, concerning aspect ratio, is to &lt;br /&gt;
fit the preset to the long axis of the window, and to crop the rest, &lt;br /&gt;
but to do all of this without any stretching or zooming (so all internal &lt;br /&gt;
canvas pixels map 1:1 to screen pixels).  &lt;br /&gt;
          &lt;br /&gt;
-per-frame/per-vertex equations: &lt;br /&gt;
* multiply XY coords by the values &amp;quot;aspectx&amp;quot; and &amp;quot;aspecty&amp;quot;, respectively.&lt;br /&gt;
          &lt;br /&gt;
-shader code: &lt;br /&gt;
* multiply UV coordinates by 'aspect.xy', prior to using them&lt;br /&gt;
to sample a texture, to make the texture fit on the screen properly.&lt;br /&gt;
(For example, if the screen is wide, the image will be fitted to cover&lt;br /&gt;
the width of the screen, and it will be cropped at the top and bottom.)&lt;br /&gt;
            &lt;br /&gt;
* multiply by 'aspect.zw' to make it fit the other way (it will fit&lt;br /&gt;
the image to be completely visible in one dimension, and tiled in the&lt;br /&gt;
other direction).	 &lt;br /&gt;
            &lt;br /&gt;
* any time you perturb the UV coordinates in the warp shader, prior to&lt;br /&gt;
sampling the Main texture, you should multiply the &amp;quot;delta&amp;quot; you are applying&lt;br /&gt;
by aspect.xy.  Otherwise, in a widescreen window, the &amp;quot;delta&amp;quot; will actually&lt;br /&gt;
be dramatically squished, or in a tall window, the change would be &lt;br /&gt;
elongated very vertically.  &lt;br /&gt;
&lt;br /&gt;
* the 'ang' value is aspect-aware, in the per-vertex equations, as well&lt;br /&gt;
as in the warp and composite shaders.  However, if you generate your own&lt;br /&gt;
high-quality &amp;quot;ang&amp;quot; value using atan2(), beware - you really&lt;br /&gt;
should multiply the UV's by aspect.xy beforehand, like this:&lt;br /&gt;
 float2 uv2 = (uv-0.5)*aspect.xy;&lt;br /&gt;
 float ang = atan2(uv2.y,uv2.x);&lt;br /&gt;
&lt;br /&gt;
=== QUALITY ASSURANCE ===&lt;br /&gt;
When designing presets, please adhere to the pixel shader 'quality assurance'&lt;br /&gt;
guidelines in the above section, as they are very important.  But, in order &lt;br /&gt;
to make sure the presets you create work well on other systems, please&lt;br /&gt;
also keep in mind:&lt;br /&gt;
        &lt;br /&gt;
# Keep your presets fast.  There's nothing to spoil the mood like a preset popping up that chokes at 10 fps.  Since division is 11 times slower than multiplication (or addition/subtraction), if you divide a bunch of values by one other value, pre-divide that value (&amp;quot;inv = 1/myval;&amp;quot;) and then multiply those other values by that inverse.  Also, never put computations in the per-vertex code that are the same for every pixel; move these into the per-frame code, and carry the results to the per-vertex code using the q1-q32 variables.  Remember that maxim: &amp;quot;If a per-vertex equation doesn't use at least one of the variables { x, y, rad, ang }, then it should be actually be a per-frame equation.&amp;quot;&lt;br /&gt;
# Design your presets using the default mesh size option from the config panel, or at least check, before you distribute them, to make sure they look correct at the default mesh size.  If your mesh is too coarse (small), then a viewer with the default mesh size might see unexpected &amp;quot;bonus&amp;quot; effects that you might not have intended, and might mess up your preset.  If your mesh is too fine, then a viewer with the default might not see all the detail you intended, and it might look bad.&lt;br /&gt;
# Try to design your presets in a 32-bit video mode, so that its brightness levels are standard.  The thing to really watch out for is designing your presets in 16-bit color when the &amp;quot;fix pink/white color saturation artifact&amp;quot; checkbox is checked.   checkbox keeps the image extra dark to avoid color saturation, which is only necessary on some cards, in 16-bit color.  If this is the case for you, and you write a preset, then when you run it on another machine, it might appear insanely bright.        &lt;br /&gt;
# Don't underestimate the power of the 'dx' and 'dy' parameters (in the per-vertex equations).  Some of the best presets are based on using these.  If you strip everything out of a preset so that there's no motion at all, then you can use the dx and dy parameters to have precise manual control over the motion.  Basically, all the other effects (zoom, warp, rot, etc.) are just complicated abstractions; they could all be simulated by using only { x, y, rad, ang } and { dx, dy }.        &lt;br /&gt;
# If you use the 'progress' variable in a preset, make sure you try the preset out with several values for 'Time Between Auto Preset Changes'.  The biggest thing to avoid is using something like sin(progress), since the rate at which 'progress' increases can vary drastically from system to system, dependong on the user's setting for 'Time Between Auto Preset Changes'.&lt;br /&gt;
# if writing shaders, please also see the 'Quality Assurance for Shaders' section above.&lt;br /&gt;
&lt;br /&gt;
=== DEBUGGING ===&lt;br /&gt;
One feature that preset authors should definitely be aware of is the variable monitoring feature, which lets you monitor (watch) the value of any per-frame variable you like.  First, hit the 'N' key to show the monitor value, which will probably display zero.  Then all you have to do is add a line like this to the per-frame equations:&lt;br /&gt;
&lt;br /&gt;
        monitor = x;&lt;br /&gt;
&lt;br /&gt;
where 'x' is the variable or expression you want to monitor.  Once you hit CTRL+ENTER to accept the changes, you should see the value of the per-frame variable or expression in the upper-right corner of the screen!&lt;br /&gt;
&lt;br /&gt;
Once again, note that it only works for *per-frame* equations, and NOT for per-vertex equations.&lt;br /&gt;
&lt;br /&gt;
=== FUNCTION REFERENCE ===&lt;br /&gt;
Following is a list of the functions supported by the expression evaluator (for preset init, per-frame, and per-vertex equations; NOT for pixel shaders).  The list was blatently ripped from the help box of Justin Frankel's AVS plug-in, since MilkDrop uses the expression evaluator that he wrote.&lt;br /&gt;
    &lt;br /&gt;
        Format your expressions using a semicolon (;) to delimit between statements.        &lt;br /&gt;
        Use parenthesis ['(' and ')'] to denote precedence if you are unsure.        &lt;br /&gt;
        The following operators are available:        &lt;br /&gt;
            = : assign        &lt;br /&gt;
            +,-,/,* : plus, minus, divide, multiply        &lt;br /&gt;
            | : convert to integer, and do bitwise or        &lt;br /&gt;
            &amp;amp; : convert to integer, and do bitwise and        &lt;br /&gt;
            % : convert to integer, and get remainder        &lt;br /&gt;
        The following functions are available:        &lt;br /&gt;
            int(var)   :  returns the integer value of 'var' (rounds toward zero)&lt;br /&gt;
            abs(var)   :  returns the absolute value of var&lt;br /&gt;
            sin(var)   :  returns the sine of the angle var (expressed in radians)        &lt;br /&gt;
            cos(var)   :  returns the cosine of the angle var        &lt;br /&gt;
            tan(var)   :  returns the tangent of the angle var        &lt;br /&gt;
            asin(var)  :  returns the arcsine of var        &lt;br /&gt;
            acos(var)  :  returns the arccosine of var        &lt;br /&gt;
            atan(var)  :  returns the arctangent of var        &lt;br /&gt;
            sqr(var)   :  returns the square of var        &lt;br /&gt;
            sqrt(var)  :  returns the square root of var        &lt;br /&gt;
            pow(var,var2) : returns var to the power of var2        &lt;br /&gt;
            log(var)      : returns the log base e of var        &lt;br /&gt;
            log10(var)    : returns the log base 10 of var        &lt;br /&gt;
            sign(var)     : returns the sign of var or 0        &lt;br /&gt;
            min(var,var2) : returns the smalest value        &lt;br /&gt;
            max(var,var2) : returns the greatest value        &lt;br /&gt;
            sigmoid(var,var2) : returns sigmoid function value of x=var (var2=constraint)        &lt;br /&gt;
            rand(var)     : returns a random integer modulo 'var'; e.g. rand(4) will return 0, 1, 2, or 3.&lt;br /&gt;
            bor(var,var2) : boolean or, returns 1 if var or var2 is != 0        &lt;br /&gt;
            bnot(var)  : boolean not, returns 1 if var == 0 or 0 if var != 0        &lt;br /&gt;
            if(cond,vartrue,varfalse) : if condition is nonzero, returns valtrue, otherwise returns valfalse        &lt;br /&gt;
            equal(var,var2) : returns 1 if var = var2, else 0        &lt;br /&gt;
            above(var,var2) : returns 1 if var &amp;gt; var2, else 0        &lt;br /&gt;
            below(var,var2) : returns 1 if var &amp;lt; var2, else 0            &lt;br /&gt;
            &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
return to top&lt;br /&gt;
return to milkdrop.html&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Media_Library_API</id>
		<title>Media Library API</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Media_Library_API"/>
				<updated>2008-09-25T13:05:23Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Media Library API&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Messages sent to your plugin's MessageProc ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// return values from the winampUninstallPlugin(HINSTANCE hdll, HWND parent, int param)&lt;br /&gt;
// which determine if we can uninstall the plugin immediately or on winamp restart&lt;br /&gt;
//&lt;br /&gt;
// uninstall support was added from 5.0+ and uninstall now support from 5.5+&lt;br /&gt;
// it is down to you to ensure that if uninstall now is returned that it will not cause a crash&lt;br /&gt;
// (ie don't use if you've been subclassing the main window)&lt;br /&gt;
#define ML_PLUGIN_UNINSTALL_NOW    0x1&lt;br /&gt;
#define ML_PLUGIN_UNINSTALL_REBOOT 0x0&lt;br /&gt;
&lt;br /&gt;
// messages your plugin may receive on MessageProc()&lt;br /&gt;
&lt;br /&gt;
#define ML_MSG_TREE_BEGIN 0x100&lt;br /&gt;
  #define ML_MSG_TREE_ONCREATEVIEW 0x100 // param1 = param of tree item, param2 is HWND of parent. return HWND if it is us&lt;br /&gt;
&lt;br /&gt;
  #define ML_MSG_TREE_ONCLICK  0x101 // param1 = param of tree item, param2 = action type (below), param3 = HWND of main window&lt;br /&gt;
    #define ML_ACTION_RCLICK 0    // return value should be nonzero if ours&lt;br /&gt;
    #define ML_ACTION_DBLCLICK 1&lt;br /&gt;
    #define ML_ACTION_ENTER 2&lt;br /&gt;
		#define ML_ACTION_LCLICK 3&lt;br /&gt;
&lt;br /&gt;
  #define ML_MSG_TREE_ONDROPTARGET 0x102 // param1 = param of tree item, param2 = type of drop (ML_TYPE_*), param3 = pointer to data (or NULL if querying).&lt;br /&gt;
                                      // return -1 if not allowed, 1 if allowed, or 0 if not our tree item&lt;br /&gt;
&lt;br /&gt;
  #define ML_MSG_TREE_ONDRAG 0x103 // param1 = param of tree item, param2 = POINT * to the mouse position, and param3 = (int *) to the type&lt;br /&gt;
                                  // set *(int*)param3 to the ML_TYPE you want and return 1, if you support drag&amp;amp;drop, or -1 to prevent d&amp;amp;d.&lt;br /&gt;
&lt;br /&gt;
  #define ML_MSG_TREE_ONDROP 0x104 // param1 = param of tree item, param2 = POINT * to the mouse position&lt;br /&gt;
                                  // if you support dropping, send the appropriate ML_IPC_HANDLEDROP using SendMessage() and return 1, otherwise return -1.&lt;br /&gt;
&lt;br /&gt;
  #define  ML_MSG_TREE_ONKEYDOWN 0x105  // Send when key pressed &lt;br /&gt;
										// param1 = param of tree item;&lt;br /&gt;
										// param2 = pointer to NMTVKEYDOWN&lt;br /&gt;
										// param3 = tree hwnd&lt;br /&gt;
										// return 0 if it's not yours, 1 if it is&lt;br /&gt;
&lt;br /&gt;
#define ML_MSG_TREE_END 0x1FF // end of tree specific messages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define ML_MSG_ONSENDTOBUILD 0x300 // you get sent this when the sendto menu gets built&lt;br /&gt;
// param1 = type of source, param2 param to pass as context to ML_IPC_ADDTOSENDTO&lt;br /&gt;
// be sure to return 0 to allow other plugins to add their context menus&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// if your sendto item is selected, you will get this with your param3 == your user32 (preferably some&lt;br /&gt;
// unique identifier (like your plugin message proc). See ML_IPC_ADDTOSENDTO&lt;br /&gt;
#define ML_MSG_ONSENDTOSELECT 0x301&lt;br /&gt;
// param1 = type of source, param2 = data, param3 = user32&lt;br /&gt;
&lt;br /&gt;
// return TRUE and do a config dialog using param1 as a HWND parent for this one&lt;br /&gt;
#define ML_MSG_CONFIG 0x400&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Messages you can send to the Media Library HWND ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define ML_TYPE_UNKNOWN			-1&lt;br /&gt;
#define ML_TYPE_ITEMRECORDLIST 0 // if this, cast obj to itemRecordList&lt;br /&gt;
#define ML_TYPE_FILENAMES 1 // double NULL terminated char * to files, URLS, or playlists&lt;br /&gt;
#define ML_TYPE_STREAMNAMES 2 // double NULL terminated char * to URLS, or playlists ( effectively the same as ML_TYPE_FILENAMES, but not for files)&lt;br /&gt;
#define ML_TYPE_CDTRACKS 3 // if this, cast obj to itemRecordList (CD tracks) -- filenames should be cda://&amp;lt;drive letter&amp;gt;,&amp;lt;track index&amp;gt;. artist/album/title might be valid (CDDB)&lt;br /&gt;
#define ML_TYPE_QUERYSTRING 4 // char * to a query string&lt;br /&gt;
#define ML_TYPE_PLAYLIST 5 // mlPlaylist *&lt;br /&gt;
#define ML_TYPE_ITEMRECORDLISTW 6 // if this, cast obj to itemRecordListW&lt;br /&gt;
// added from 5.36+&lt;br /&gt;
#define ML_TYPE_FILENAMESW 7 // double NULL terminated wchar_t * to files, URLS, or playlists&lt;br /&gt;
#define ML_TYPE_STREAMNAMESW 8 // double NULL terminated wchar_t * to URLS, or playlists ( effectively the same as ML_TYPE_FILENAMESW, but not for files)&lt;br /&gt;
#define ML_TYPE_PLAYLISTS 9 // mlPlaylist **, null terminated&lt;br /&gt;
#define ML_TYPE_TREEITEM 69 // uhh?&lt;br /&gt;
&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	const wchar_t *filename;&lt;br /&gt;
	const wchar_t *title;&lt;br /&gt;
	// only fill in the following two if already know.  don't calculate it just for the struct. &lt;br /&gt;
	// put -1 for &amp;quot;don't know&amp;quot;&lt;br /&gt;
	int numItems; &lt;br /&gt;
	int length; // in seconds.  &lt;br /&gt;
} mlPlaylist;&lt;br /&gt;
&lt;br /&gt;
// if you wish to put your tree items under &amp;quot;devices&amp;quot;, use this constant for ML_IPC_ADDTREEITEM&lt;br /&gt;
#define ML_TREEVIEW_ID_DEVICES 10000&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// children communicate back to the media library by SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,param,ML_IPC_X);&lt;br /&gt;
#define WM_ML_IPC WM_USER+0x1000&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
#define ML_IPC_GETCURRENTVIEW	0x090 // Returns HWND to the currently selected view or NULL if nothing selected or error. (WA 5.22 and higher)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
// Old Tree Item API  (deprecated)&lt;br /&gt;
//&lt;br /&gt;
#define ML_IPC_ADDTREEITEM		0x0101 // pass mlAddTreeItemStruct as the param&lt;br /&gt;
#define ML_IPC_SETTREEITEM		0x0102 // pass mlAddTreeItemStruct with id valid&lt;br /&gt;
#define ML_IPC_DELTREEITEM		0x0103 // pass param of tree item to remove&lt;br /&gt;
#define ML_IPC_GETCURTREEITEM	0x0104 // returns current tree item param or 0 if none&lt;br /&gt;
#define ML_IPC_SETCURTREEITEM	0x0105 // selects the tree item passed, returns 1 if found, 0 if not&lt;br /&gt;
#define ML_IPC_GETTREE			0x0106 // returns a HMENU with all the tree items. the caller needs to delete the returned handle! pass mlGetTreeStruct as the param&lt;br /&gt;
&lt;br /&gt;
/* deprecated. Use MLTREEITEM instead */&lt;br /&gt;
typedef struct {&lt;br /&gt;
  INT_PTR parent_id; //0=root, or ML_TREEVIEW_ID_*&lt;br /&gt;
  char *title;&lt;br /&gt;
  int has_children;&lt;br /&gt;
  INT_PTR this_id; //filled in by the library on ML_IPC_ADDTREEITEM&lt;br /&gt;
} mlAddTreeItemStruct;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int item_start;   // TREE_PLAYLISTS, TREE_DEVICES...&lt;br /&gt;
  int cmd_offset;   // menu command offset if you need to make a command proxy, 0 otherwise&lt;br /&gt;
  int max_numitems; // maximum number of items you wish to insert or -1 for no limit&lt;br /&gt;
} mlGetTreeStruct;&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
/// For Predixis, with Love&lt;br /&gt;
/// deprecatded (never use!!!)&lt;br /&gt;
///&lt;br /&gt;
#define ML_IPC_ADDTREEITEM_EX 0x0111 // pass mlAddTreeItemStructEx as the param&lt;br /&gt;
#define ML_IPC_SETTREEITEM_EX 0x0112 // pass mlAddTreeItemStructEx with this_id valid&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  INT_PTR parent_id; //0=root, or ML_TREEVIEW_ID_*&lt;br /&gt;
  char *title;&lt;br /&gt;
  int has_children;&lt;br /&gt;
  INT_PTR this_id; //filled in by the library on ML_IPC_ADDTREEITEM&lt;br /&gt;
  int imageIndex;  // index of the image you want to be associated with your item&lt;br /&gt;
} mlAddTreeItemStructEx;&lt;br /&gt;
&lt;br /&gt;
/// deprecatded (never use!!!)&lt;br /&gt;
#define ML_IPC_ADDTREEIMAGE 0x110 // adds tree image to the ml. Use mlAddTreeImageStruct as the param.&lt;br /&gt;
/// end of predixis special&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
// Tree Item API  (starting from 5.3)&lt;br /&gt;
//&lt;br /&gt;
#define ML_IPC_TREEITEM_GETHANDLE	0x120 // Gives you HANDLE to the item with specified ID in the param&lt;br /&gt;
#define ML_IPC_TREEITEM_GETCHILD		0x121 // Returns HANDLE to the child item for the item HANDLE specified as a param. &lt;br /&gt;
#define ML_IPC_TREEITEM_GETNEXT		0x122 // Returns HANDLE to the next item for the item HANDLE specified as a param.&lt;br /&gt;
#define ML_IPC_TREEITEM_GETSELECTED	0x123 // Returns HANDLE to selected item.&lt;br /&gt;
#define ML_IPC_TREEITEM_GETINFO		0x124 // Pass MLTREEITEMINFO as a param. return TRUE - if ok&lt;br /&gt;
#define ML_IPC_TREEITEM_SETINFO		0x125 // Pass MLTREEITEMINFO as a param. return TRUE - if ok&lt;br /&gt;
#define ML_IPC_TREEITEM_ADD			0x126 // Adds new item using MLTREEITEM passed as a param&lt;br /&gt;
#define ML_IPC_TREEITEM_DELETE		0x127 // Deletes tree item. Pass HANDLE as a param.&lt;br /&gt;
#define ML_IPC_TREEITEM_SELECT		0x128 // Selects tree item. Pass HANDLE as a param. &lt;br /&gt;
#define ML_IPC_TREEITEM_GETROOT		0x129 // Gets first item.&lt;br /&gt;
#define ML_IPC_TREEITEM_INSERT    0x130 // like ML_IPC_TREEITEM_ADD, but id becomes an &amp;quot;insert after&amp;quot; ID&lt;br /&gt;
#define ML_IPC_TREEITEM_GETCHILD_ID		0x131 // Returns ID to the child item for the item ID specified as a param. &lt;br /&gt;
#define ML_IPC_TREEITEM_GETNEXT_ID		0x132 // Returns ID to the next item for the item ID specified as a param.&lt;br /&gt;
#define ML_IPC_TREEITEM_ADDW			0x133 // Adds new item using MLTREEITEMW passed as a param&lt;br /&gt;
#define ML_IPC_TREEITEM_INSERTW    0x134 // like ML_IPC_TREEITEM_ADDW, but id becomes an &amp;quot;insert after&amp;quot; ID&lt;br /&gt;
#define ML_IPC_TREEITEM_SETINFOW    0x135 // Pass MLTREEITEMINFOW as a param. return TRUE - if ok&lt;br /&gt;
#define ML_IPC_TREEITEM_GETINFOW		0x136 // Pass MLTREEITEMINFO as a param. return TRUE - if ok&lt;br /&gt;
#define MLTI_ROOT			(INT_PTR)TVI_ROOT // can be used in ML_IPC_TREEITEM_GETCHILD&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  size_t	size;			// size of this struct&lt;br /&gt;
  UINT_PTR	id;				// depends on contxext&lt;br /&gt;
  UINT_PTR	parentId;		// 0 = root, or ML_TREEVIEW_ID_*&lt;br /&gt;
  char		*title;			// pointer to the buffer contained item name. &lt;br /&gt;
  size_t	titleLen;		// used for GetInfo &lt;br /&gt;
  BOOL		hasChildren;	// TRUE - has children&lt;br /&gt;
  int		imageIndex;		// index of the associated image&lt;br /&gt;
} MLTREEITEM;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  MLTREEITEM	item;	// item data&lt;br /&gt;
  UINT			mask;	// one or more of MLTI_* flags&lt;br /&gt;
  UINT_PTR		handle; // Handle to the item. If handle is NULL item-&amp;gt;id will be used&lt;br /&gt;
} MLTREEITEMINFO;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  size_t	size;			// size of this struct&lt;br /&gt;
  UINT_PTR		id;				// depends on context&lt;br /&gt;
  UINT_PTR		parentId;		// 0 = root, or ML_TREEVIEW_ID_*&lt;br /&gt;
  wchar_t	*title;			// pointer to the buffer contained item name. &lt;br /&gt;
  size_t	titleLen;		// used for GetInfo &lt;br /&gt;
  BOOL		hasChildren;	// TRUE - has children&lt;br /&gt;
  int		imageIndex;		// index of the associated image&lt;br /&gt;
} MLTREEITEMW;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  MLTREEITEMW	item;	// item data&lt;br /&gt;
  UINT			mask;	// one or more of MLTI_* flags&lt;br /&gt;
  UINT_PTR		handle; // Handle to the item. If handle is NULL item-&amp;gt;id will be used&lt;br /&gt;
} MLTREEITEMINFOW;&lt;br /&gt;
// Flags that used in the MLTREEITEMINFO struct&lt;br /&gt;
#define MLTI_CHILDREN	TVIF_CHILDREN&lt;br /&gt;
#define MLTI_IMAGE		TVIF_IMAGE&lt;br /&gt;
#define MLTI_TEXT		TVIF_TEXT&lt;br /&gt;
#define MLTI_ID			TVIF_PARAM&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
// Tree image (starting from 5.3)&lt;br /&gt;
//&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_TREEIMAGE_ADD 0x140 // adds tree image to the ml. Use MLTREEIMAGE as the param.&lt;br /&gt;
&lt;br /&gt;
typedef struct _COLOR24&lt;br /&gt;
{&lt;br /&gt;
	unsigned char rgbBlue;&lt;br /&gt;
	unsigned char rgbGreen;&lt;br /&gt;
	unsigned char rgbRed;&lt;br /&gt;
}COLOR24; // color struct &lt;br /&gt;
&lt;br /&gt;
typedef void (*BMPFILTERPROC)(const COLOR24*, const COLOR24*, COLOR24*); // color filter procedure &lt;br /&gt;
// you got two colors: color1 and color2 (usualy BG and FG colors) also you as a third parameter&lt;br /&gt;
// you get a pixel color value that you need (can) modify  &lt;br /&gt;
&lt;br /&gt;
#define FILTER_NO			((BMPFILTERPROC)NULL)&lt;br /&gt;
#define FILTER_DEFAULT1		((BMPFILTERPROC)1)&lt;br /&gt;
#define FILTER_DEFAULT2		((BMPFILTERPROC)2)&lt;br /&gt;
&lt;br /&gt;
#define MLTREEIMAGE_NONE					0&lt;br /&gt;
#define MLTREEIMAGE_DEFAULT					1&lt;br /&gt;
#define MLTREEIMAGE_BRANCH					2   // calculates at the time 	&lt;br /&gt;
#define MLTREEIMAGE_BRANCH_EXPANDED			3&lt;br /&gt;
#define MLTREEIMAGE_BRANCH_COLLAPSED		4&lt;br /&gt;
#define MLTREEIMAGE_BRANCH_NOCHILD			5&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
	HINSTANCE				hinst;					// hInstance&lt;br /&gt;
	int				resourceId;				// resource id &lt;br /&gt;
	int				imageIndex;				// set image to specified index (specify -1 to get a new index back)&lt;br /&gt;
	BMPFILTERPROC	filterProc;				// pointer to the filter proc to use or one of the FILTER_*&lt;br /&gt;
	int				width;					// reserved&lt;br /&gt;
	int				height;					// reserved&lt;br /&gt;
} MLTREEIMAGE;   // basicly ml will read your reosurce when it will need to create your image&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_NEWPLAYLIST           0x107 // pass hwnd for dialog parent as param&lt;br /&gt;
#define ML_IPC_IMPORTPLAYLIST        0x108 // pass hwnd for dialog parent as param&lt;br /&gt;
#define ML_IPC_IMPORTCURRENTPLAYLIST 0x109&lt;br /&gt;
#define ML_IPC_GETPLAYLISTWND        0x10A&lt;br /&gt;
#define ML_IPC_SAVEPLAYLIST          0x10B // pass hwnd for dialog parent as param&lt;br /&gt;
#define ML_IPC_OPENPREFS             0x10C&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_PLAY_PLAYLIST 0x010D // plays the playlist pointed to by the tree item passed, returns 1 if found, 0 if not&lt;br /&gt;
#define ML_IPC_LOAD_PLAYLIST 0x010E // loads the playlist pointed to by the tree item passed into the playlist editor, returns 1 if found, 0 if not&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_REFRESH_PREFS 0x10F // this doesn't belong in here &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/** ------------------ &lt;br /&gt;
 ** ml_playlists &lt;br /&gt;
 ** ------------------ */&lt;br /&gt;
&lt;br /&gt;
#define PL_FLAG_SHOW 1&lt;br /&gt;
#define PL_FLAG_SWITCH 2&lt;br /&gt;
#define PL_FLAGS_IMPORT 4 // set to have ml_playlists make a copy (only valid for mlAddPlaylist)&lt;br /&gt;
#define PL_FLAG_FILL_FILENAME 8 // only valid for mlMakePlaylist&lt;br /&gt;
&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
  size_t size;  // size of this struct&lt;br /&gt;
	const wchar_t *playlistName; // set to NULL (or empty string) to prompt the user for a name&lt;br /&gt;
  const wchar_t *filename;&lt;br /&gt;
	int flags; // see PL_FLAG_* above&lt;br /&gt;
	// the following two items can be optionally filled in (set to -1 otherwise)&lt;br /&gt;
	// if they aren't set, the playlist file will have to be opened and parsed&lt;br /&gt;
	// so prepopulating is faster (assuming if you already know the data)&lt;br /&gt;
	int numItems; // set to -1 if you don't know. &lt;br /&gt;
	int length; // in seconds, set to -1 if you don't know&lt;br /&gt;
} mlAddPlaylist;&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_PLAYLIST_ADD 0x180 // call to add a new playlist file to the Playlists treeview.  pass an mlAddPlaylist *&lt;br /&gt;
&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
	size_t size;  // size of this struct&lt;br /&gt;
	const wchar_t *playlistName; // set to NULL (or empty string) to prompt the user for a name&lt;br /&gt;
  int type; //ML_TYPE_ITEMRECORDLIST, etc&lt;br /&gt;
  void *data; // object to load&lt;br /&gt;
	int flags; // see PL_FLAG_* above&lt;br /&gt;
	wchar_t filename[MAX_PATH]; // this will get populated if PL_FLAG_FILL_NAME is set&lt;br /&gt;
} mlMakePlaylistV2;&lt;br /&gt;
&lt;br /&gt;
// old structure, here to make it easy to do a sizeof() check&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
	size_t size;  // size of this struct&lt;br /&gt;
	const wchar_t *playlistName; // set to NULL (or empty string) to prompt the user for a name&lt;br /&gt;
  int type; //ML_TYPE_ITEMRECORDLIST, etc&lt;br /&gt;
  void *data; // object to load&lt;br /&gt;
	int flags; // see PL_FLAG_* above&lt;br /&gt;
} mlMakePlaylist;&lt;br /&gt;
&lt;br /&gt;
/* Call to add a new playlist to the Playlists treeview.  &lt;br /&gt;
   It will be automatically created based on the data you pass&lt;br /&gt;
	 type &amp;amp; data follow the same specifications as send-to, drag-and-drop, etc.&lt;br /&gt;
*/&lt;br /&gt;
#define ML_IPC_PLAYLIST_MAKE 0x181  // call to create a new playlist in the treeview based on passed information.  pass an mlMakePlaylist *&lt;br /&gt;
#define ML_IPC_PLAYLIST_COUNT 0x182&lt;br /&gt;
#define ML_IPC_PLAYLIST_INFO 0x183 // pass in the struct below. returns &amp;quot;1&amp;quot; on success and &amp;quot;0&amp;quot; on failure&lt;br /&gt;
&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	// you fill this in&lt;br /&gt;
	size_t size; // size of this struct&lt;br /&gt;
	size_t playlistNum; // number of the playlist you want to retrieve (0 index)&lt;br /&gt;
	// ml_playlists fills these in&lt;br /&gt;
	wchar_t playlistName[128];&lt;br /&gt;
	wchar_t filename[MAX_PATH];&lt;br /&gt;
	int numItems;&lt;br /&gt;
	int length; // in seconds&lt;br /&gt;
} mlPlaylistInfo;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/** ------------------ &lt;br /&gt;
 ** &lt;br /&gt;
 ** ------------------ */&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_GETFILEINFO 0x0200 // pass it a &amp;amp;itemRecord with a valid filename (and all other fields NULL), and it will try to fill in the rest&lt;br /&gt;
#define ML_IPC_FREEFILEINFO 0x0201 // pass it a &amp;amp;itemRecord tha twas filled by getfileinfo, it will free the strings it allocated&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_HANDLEDRAG 0x0300 // pass it a &amp;amp;mlDropItemStruct it will handle cursors etc (unless flags has the lowest bit set), and it will set result appropriately:&lt;br /&gt;
#define ML_IPC_HANDLEDROP 0x0301 // pass it a &amp;amp;mlDropItemStruct with data on drop:&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_SENDTOWINAMP 0x302 // send with a mlSendToWinampStruct:&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int type; //ML_TYPE_ITEMRECORDLIST, etc&lt;br /&gt;
  void *data; // object to play&lt;br /&gt;
&lt;br /&gt;
  int enqueue; // low bit set specifies enqueuing, and second bit NOT set specifies that &lt;br /&gt;
               // the media library should use its default behavior as the user configured it (if &lt;br /&gt;
               // enqueue is the default, the low bit will be flipped by the library)&lt;br /&gt;
} mlSendToWinampStruct;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  char *desc; // str&lt;br /&gt;
  intptr_t context; // context passed by ML_MSG_ONSENDTOBUILD&lt;br /&gt;
  intptr_t user32; // use some unique ptr in memory, you will get it back in ML_MSG_ONSENDTOSELECT...&lt;br /&gt;
} mlAddToSendToStruct;&lt;br /&gt;
#define ML_IPC_ADDTOSENDTO 0x0400&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  wchar_t *desc; // str&lt;br /&gt;
  intptr_t context; // context passed by ML_MSG_ONSENDTOBUILD&lt;br /&gt;
  intptr_t user32; // use some unique ptr in memory, you will get it back in ML_MSG_ONSENDTOSELECT...&lt;br /&gt;
} mlAddToSendToStructW;&lt;br /&gt;
#define ML_IPC_ADDTOSENDTOW 0x0401 // pass mlAddToSendToStructW&lt;br /&gt;
&lt;br /&gt;
// used to make a submenu in sendto&lt;br /&gt;
// pass mlAddToSendToStructW, set desc to 0 to start, set valid desc to end&lt;br /&gt;
// user32 is unused &lt;br /&gt;
#define ML_IPC_BRANCHSENDTO 0x0402 &lt;br /&gt;
&lt;br /&gt;
// follow same rules as ML_IPC_ADDTOSENDTOW, but adds to branch instead of main send-to menu&lt;br /&gt;
#define ML_IPC_ADDTOBRANCH 0x403  // pass mlAddToSendToStructW&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_HOOKTITLE 0x0440 // this is like winamp's IPC_HOOK_TITLES... :) param1 is waHookTitleStruct&lt;br /&gt;
#define ML_IPC_HOOKEXTINFO 0x441 // called on IPC_GET_EXTENDED_FILE_INFO_HOOKABLE, param1 is extendedFileInfoStruct&lt;br /&gt;
#define ML_IPC_HOOKEXTINFOW 0x442 // called on IPC_GET_EXTENDED_FILE_INFO_HOOKABLEW, param1 is extendedFileInfoStructW&lt;br /&gt;
#define ML_IPC_HOOKTITLEW 0x0443 // this is like winamp's IPC_HOOK_TITLESW... :) param1 is waHookTitleStructW&lt;br /&gt;
&lt;br /&gt;
#define ML_HANDLEDRAG_FLAG_NOCURSOR 1&lt;br /&gt;
#define ML_HANDLEDRAG_FLAG_NAME 2&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int type; //ML_TYPE_ITEMRECORDLIST, etc&lt;br /&gt;
  void *data; // NULL if just querying&lt;br /&gt;
&lt;br /&gt;
  int result; // filled in by client: -1 if dont allow, 0 if dont know, 1 if allow.&lt;br /&gt;
&lt;br /&gt;
  POINT p; // cursor pos in screen coordinates&lt;br /&gt;
  int flags; &lt;br /&gt;
&lt;br /&gt;
  char *name; // only valid if ML_HANDLEDRAG_FLAG_NAME&lt;br /&gt;
&lt;br /&gt;
} mlDropItemStruct;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_SKIN_LISTVIEW   0x0500 // pass the hwnd of your listview. returns a handle to use with ML_IPC_UNSKIN_LISTVIEW&lt;br /&gt;
#define ML_IPC_UNSKIN_LISTVIEW 0x0501 // pass the handle you got from ML_IPC_SKIN_LISTVIEW&lt;br /&gt;
#define ML_IPC_LISTVIEW_UPDATE 0x0502 // pass the handle you got from ML_IPC_SKIN_LISTVIEW&lt;br /&gt;
#define ML_IPC_LISTVIEW_DISABLEHSCROLL 0x0503 // pass the handle you got from ML_IPC_SKIN_LISTVIEW&lt;br /&gt;
#define ML_IPC_LISTVIEW_DISABLEVSCROLL 0x050A // pass the handle you got from ML_IPC_SKIN_LISTVIEW&lt;br /&gt;
#define ML_IPC_LISTVIEW_SHOWSORT		0x0504  // use LV_SKIN_SHOWSORT&lt;br /&gt;
#define ML_IPC_LISTVIEW_SORT			0x0505  // use LV_SKIN_SORT&lt;br /&gt;
&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
	INT_PTR listView;&lt;br /&gt;
	BOOL	showSort;&lt;br /&gt;
} LV_SKIN_SHOWSORT;&lt;br /&gt;
&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	INT_PTR listView;&lt;br /&gt;
	int		columnIndex;&lt;br /&gt;
	BOOL	ascending;&lt;br /&gt;
} LV_SKIN_SORT;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_SKIN_COMBOBOX   0x0508 // pass the hwnd of your combobox to skin, returns a ahndle to use with ML_IPC_UNSKIN_COMBOBOX&lt;br /&gt;
#define ML_IPC_UNSKIN_COMBOBOX 0x0509 // pass the handle from ML_IPC_SKIN_COMBOBOX&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_SKIN_WADLG_GETFUNC 0x0600 &lt;br /&gt;
    // 1: return int (*WADlg_getColor)(int idx); // pass this an index, returns a RGB value (passing 0 or &amp;gt; 3 returns NULL)&lt;br /&gt;
    // 2: return int (*WADlg_handleDialogMsgs)(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); &lt;br /&gt;
    // 3: return void (*WADlg_DrawChildWindowBorders)(HWND hwndDlg, int *tab, int tabsize); // each entry in tab would be the id | DCW_*&lt;br /&gt;
    // 32: return void (*childresize_init)(HWND hwndDlg, ChildWndResizeItem *list, int num);&lt;br /&gt;
    // 33: return void (*childresize_resize)(HWND hwndDlg, ChildWndResizeItem *list, int num);&lt;br /&gt;
    // 66: return (HFONT) font to use for dialog elements, if desired (0 otherwise)&lt;br /&gt;
   &lt;br /&gt;
// itemRecord type for use with ML_TYPE_ITEMRECORDLIST, as well as many other functions&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
  char *filename;&lt;br /&gt;
  char *title;&lt;br /&gt;
  char *album;&lt;br /&gt;
  char *artist;&lt;br /&gt;
  char *comment;&lt;br /&gt;
  char *genre;&lt;br /&gt;
  int year;&lt;br /&gt;
  int track;&lt;br /&gt;
  int length;&lt;br /&gt;
  char **extended_info;&lt;br /&gt;
  // currently defined extended columns (while they are stored internally as integers&lt;br /&gt;
  // they are passed using extended_info as strings):&lt;br /&gt;
  // use getRecordExtendedItem and setRecordExtendedItem to get/set.&lt;br /&gt;
  // for your own internal use, you can set other things, but the following values&lt;br /&gt;
  // are what we use at the moment. Note that setting other things will be ignored&lt;br /&gt;
  // by ML_IPC_DB*.&lt;br /&gt;
  // &lt;br /&gt;
  //&amp;quot;RATING&amp;quot; file rating. can be 1-5, or 0 or empty for undefined&lt;br /&gt;
  //&amp;quot;PLAYCOUNT&amp;quot; number of file plays.&lt;br /&gt;
  //&amp;quot;LASTPLAY&amp;quot; last time played, in standard time_t format&lt;br /&gt;
  //&amp;quot;LASTUPD&amp;quot; last time updated in library, in standard time_t format&lt;br /&gt;
  //&amp;quot;FILETIME&amp;quot; last known file time of file, in standard time_t format&lt;br /&gt;
  //&amp;quot;FILESIZE&amp;quot; last known file size, in kilobytes.&lt;br /&gt;
  //&amp;quot;BITRATE&amp;quot; file bitrate, in kbps&lt;br /&gt;
	//&amp;quot;TYPE&amp;quot; - &amp;quot;0&amp;quot; for audio, &amp;quot;1&amp;quot; for video&lt;br /&gt;
&lt;br /&gt;
} itemRecord;&lt;br /&gt;
&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
  itemRecord *Items;&lt;br /&gt;
  int Size;&lt;br /&gt;
  int Alloc;&lt;br /&gt;
} itemRecordList;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
  wchar_t *filename;&lt;br /&gt;
  wchar_t *title;&lt;br /&gt;
  wchar_t *album;&lt;br /&gt;
  wchar_t *artist;&lt;br /&gt;
  wchar_t *comment;&lt;br /&gt;
  wchar_t *genre;&lt;br /&gt;
	wchar_t *albumartist; &lt;br /&gt;
	wchar_t *replaygain_album_gain; // these are strings rather than float's to differentiate between '0 gain' and 'not defined'&lt;br /&gt;
	wchar_t *replaygain_track_gain; // these are strings rather than float's to differentiate between '0 gain' and 'not defined'&lt;br /&gt;
	wchar_t *publisher;&lt;br /&gt;
	wchar_t *composer;&lt;br /&gt;
  int year;&lt;br /&gt;
  int track;&lt;br /&gt;
	int tracks;&lt;br /&gt;
  int length;&lt;br /&gt;
	int rating; // file rating. can be 1-5, or 0 for undefined&lt;br /&gt;
	int playcount; // number of file plays.&lt;br /&gt;
	__time64_t lastplay; // last time played, in standard time_t format&lt;br /&gt;
	__time64_t lastupd; // last time updated in library, in standard time_t format&lt;br /&gt;
	__time64_t filetime; // last known file time of file, in standard time_t format&lt;br /&gt;
	int filesize; //last known file size, in kilobytes.&lt;br /&gt;
	int bitrate; // file bitrate, in kbps&lt;br /&gt;
	int type; // 0 for audio, 1 for video&lt;br /&gt;
	int disc; // disc number&lt;br /&gt;
	int discs; // number of discs&lt;br /&gt;
	int bpm;&lt;br /&gt;
  wchar_t **extended_info; &lt;br /&gt;
  // currently defined extended columns (while they are stored internally as integers&lt;br /&gt;
  // they are passed using extended_info as strings):&lt;br /&gt;
  // use getRecordExtendedItem and setRecordExtendedItem to get/set.&lt;br /&gt;
  // for your own internal use, you can set other things, but the following values&lt;br /&gt;
  // are what we use at the moment. Note that setting other things will be ignored&lt;br /&gt;
  // by ML_IPC_DB*.&lt;br /&gt;
  // &lt;br /&gt;
&lt;br /&gt;
} itemRecordW;&lt;br /&gt;
&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
  itemRecordW *Items;&lt;br /&gt;
  int Size;&lt;br /&gt;
  int Alloc;&lt;br /&gt;
} itemRecordListW;&lt;br /&gt;
&lt;br /&gt;
//&lt;br /&gt;
// all return 1 on success, -1 on error. or 0 if not supported, maybe?&lt;br /&gt;
&lt;br /&gt;
// pass these a mlQueryStruct&lt;br /&gt;
// results should be zeroed out before running a query, but if you wish you can run multiple queries and &lt;br /&gt;
// have it concatenate the results. tho it would be more efficient to just make one query that contains both,&lt;br /&gt;
// as running multiple queries might have duplicates etc.&lt;br /&gt;
// in general, though, if you need to treat &amp;quot;results&amp;quot; as if they are native, you should use&lt;br /&gt;
// copyRecordList to save a copy, then free the results using ML_IPC_DB_FREEQUERYRESULTS.&lt;br /&gt;
// if you need to keep an exact copy that you will only read (and will not modify), then you can&lt;br /&gt;
// use the one in the mlQueryStruct.&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_DB_RUNQUERY 0x0700 &lt;br /&gt;
#define ML_IPC_DB_RUNQUERY_SEARCH 0x0701 // &amp;quot;query&amp;quot; should be interpreted as keyword search instead of query string&lt;br /&gt;
#define ML_IPC_DB_RUNQUERY_FILENAME 0x0702 // searches for one exact filename match of &amp;quot;query&amp;quot;&lt;br /&gt;
#define ML_IPC_DB_RUNQUERY_INDEX 0x703 // retrieves item #(int)query&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_DB_FREEQUERYRESULTS 0x0705 // frees memory allocated by ML_IPC_RUNQUERY (empties results)&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
  char *query;&lt;br /&gt;
  int max_results;      // can be 0 for unlimited&lt;br /&gt;
  itemRecordList results;&lt;br /&gt;
} mlQueryStruct;&lt;br /&gt;
&lt;br /&gt;
/* Unicode versions of the above */&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_DB_RUNQUERYW 0x1700&lt;br /&gt;
#define ML_IPC_DB_RUNQUERY_SEARCHW 0x1701 // &amp;quot;query&amp;quot; should be interpreted as keyword search instead of query string&lt;br /&gt;
#define ML_IPC_DB_RUNQUERY_FILENAMEW 0x1702 // searches for one exact filename match of &amp;quot;query&amp;quot;&lt;br /&gt;
#define ML_IPC_DB_RUNQUERY_INDEXW 0x1703 // retrieves item #(int)query&lt;br /&gt;
#define ML_IPC_DB_FREEQUERYRESULTSW 0x1705 // frees memory allocated by ML_IPC_RUNQUERYW (empties results)&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
  wchar_t *query;&lt;br /&gt;
  int max_results;      // can be 0 for unlimited&lt;br /&gt;
  itemRecordListW results;&lt;br /&gt;
} mlQueryStructW;&lt;br /&gt;
&lt;br /&gt;
/* ----------------------------- */&lt;br /&gt;
&lt;br /&gt;
// pass these an (itemRecord *) to add/update.&lt;br /&gt;
// note that any NULL fields in the itemRecord won't be updated, &lt;br /&gt;
// and year, track, or length of -1 prevents updating as well.&lt;br /&gt;
#define ML_IPC_DB_UPDATEITEM 0x0706    // returns -2 if item not found in db&lt;br /&gt;
#define ML_IPC_DB_ADDORUPDATEITEM 0x0707&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_DB_REMOVEITEM 0x0708 // pass a char * to the filename to remove. returns -2 if file not found in db.&lt;br /&gt;
&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
  char*  fileName;   // file name to add&lt;br /&gt;
  int    meta_mode;  // metadata get mode (0 - don't use metadata, 1 - use metadata; -1 - read from user settings (ini file)&lt;br /&gt;
  int    gues_mode;  // metadata guessing mode (0 - smart, 1 - simple; 2 - no, -1 - read from user settings (ini file)&lt;br /&gt;
} LMDB_FILE_ADD_INFO;&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_DB_UPDATEFILE 0x0710         // Update File in the Local Media Data Base (return -2 if file record not found)&lt;br /&gt;
#define ML_IPC_DB_ADDORUPDATEFILE 0x0711      // Adds or Updates File in the Local Media Data Base.&lt;br /&gt;
&lt;br /&gt;
/* Unicode versions of the above */&lt;br /&gt;
&lt;br /&gt;
// pass these an (itemRecordW *) to add/update.&lt;br /&gt;
// note that any NULL fields in the itemRecordW won't be updated, &lt;br /&gt;
// and year, track, or length of -1 prevents updating as well.&lt;br /&gt;
#define ML_IPC_DB_UPDATEITEMW 0x1706    // returns -2 if item not found in db&lt;br /&gt;
#define ML_IPC_DB_ADDORUPDATEITEMW 0x1707&lt;br /&gt;
&lt;br /&gt;
typedef struct &lt;br /&gt;
{&lt;br /&gt;
  wchar_t*  fileName;   // file name to add&lt;br /&gt;
  int    meta_mode;  // metadata get mode (0 - don't use metadata, 1 - use metadata; -1 - read from user settings (ini file)&lt;br /&gt;
  int    gues_mode;  // metadata guessing mode (0 - smart, 1 - simple; 2 - no, -1 - read from user settings (ini file)&lt;br /&gt;
} LMDB_FILE_ADD_INFOW;&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_DB_UPDATEFILEW 0x1710         // Update File in the Local Media Data Base (return -2 if file record not found) NOTE that this call is broken on 5.33.  Only use on 5.34+&lt;br /&gt;
#define ML_IPC_DB_ADDORUPDATEFILEW 0x1711      // Adds or Updates File in the Local Media Data Base.&lt;br /&gt;
&lt;br /&gt;
/* ----------------------------- */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_DB_SYNCDB 0x0709 // sync db if dirty flags are set. good to do after a batch of updates.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these return 0 if unsupported, -1 if failed, 1 if succeeded&lt;br /&gt;
&lt;br /&gt;
// pass a winampMediaLibraryPlugin *. Will not call plugin's init() func. &lt;br /&gt;
// YOU MUST set winampMediaLibraryPlugin-&amp;gt;hDllInstance to NULL, and version to MLHDR_VER&lt;br /&gt;
// 5.25+:  You can set hDllInstance to valid value.  &lt;br /&gt;
//         This IPC will return -1 on failure, so a good check against old verions&lt;br /&gt;
//         is to try with hDllInstance set, if it returns -1, try again with hDllInstance=0&lt;br /&gt;
#define ML_IPC_ADD_PLUGIN 0x0750 &lt;br /&gt;
#define ML_IPC_REMOVE_PLUGIN 0x0751 // winampMediaLibraryPlugin * of plugin to remove. Will not call plugin's quit() func&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_SEND_PLUGIN_MESSAGE 0x0752 // sends message to plugins (wParam = 0, lParam = pointer to the pluginMessage struct)&lt;br /&gt;
// pluginMessage struct&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int messageType;&lt;br /&gt;
  INT_PTR param1;&lt;br /&gt;
  INT_PTR param2;&lt;br /&gt;
  INT_PTR param3;&lt;br /&gt;
} pluginMessage;&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_ENSURE_VISIBLE 0x753 // ensures that the media library is visible&lt;br /&gt;
#define ML_IPC_IS_VISIBLE 0x754 // queries the current visibility status&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_GET_PARENTAL_RATING 0x755 &lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_TOGGLE_VISIBLE 0x756&lt;br /&gt;
&lt;br /&gt;
// this gets sent to any child windows of the library windows, and then (if not&lt;br /&gt;
// handled) the library window itself&lt;br /&gt;
&lt;br /&gt;
#define WM_ML_CHILDIPC WM_APP+0x800 // avoids conflicts with any windows controls&lt;br /&gt;
#define ML_CHILDIPC_DROPITEM 0x100         // lParam = 100, wParam = &amp;amp;mlDropItemStruct&lt;br /&gt;
&lt;br /&gt;
// current item ratings&lt;br /&gt;
#define ML_IPC_SETRATING 0x0900 // lParam = 0 to 5, rates current track -- inserts it in the db if it's not in it yet &lt;br /&gt;
#define ML_IPC_GETRATING 0x0901 // return the current track's rating or 0 if not in db/no rating&lt;br /&gt;
&lt;br /&gt;
// playlist entry rating&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int plentry;&lt;br /&gt;
  int rating;&lt;br /&gt;
} pl_set_rating;&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_PL_SETRATING 0x0902 // lParam = pointer to pl_set_rating struct&lt;br /&gt;
#define ML_IPC_PL_GETRATING 0x0903 // lParam = playlist entry, returns the rating or 0 if not in db/no rating&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  HWND dialog_parent;              // Use this window as a parent for the query editor dialog&lt;br /&gt;
  const char *query;               // The query to edit, or &amp;quot;&amp;quot; / null for new query&lt;br /&gt;
} ml_editquery;                 &lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_EDITQUERY    0x904  // lParam = pointer to ml_editquery struct, returns 0 if edition was canceled and 1 on success&lt;br /&gt;
                                   // After returning, and if ok was clicked, the struct contains a pointer to the edited query. this pointer is static : &lt;br /&gt;
                                   // - do *not* free it&lt;br /&gt;
                                   // - if you need to keep it around, strdup it, as it may be changed later by other plugins calling ML_IPC_EDITQUERY.&lt;br /&gt;
&lt;br /&gt;
typedef struct {                &lt;br /&gt;
  HWND dialog_parent;              // Use this window as a parent for the view editor dialog&lt;br /&gt;
  const char *query;               // The query to edit, or &amp;quot;&amp;quot; / null for new views&lt;br /&gt;
  const char *name;                // Name of the view (ignored for new views)&lt;br /&gt;
  int mode;                        // View mode (0=simple view, 1=artist/album view, -1=hide mode radio boxes)&lt;br /&gt;
} ml_editview;                 &lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_EDITVIEW     0x905  // lParam = pointer to ml_editview struct, returns 0 if edition was canceled and 1 on success&lt;br /&gt;
                                   // After returning, and if ok was clicked, the struct contains the edited values. String pointers are static: &lt;br /&gt;
                                   // - do *not* free them &lt;br /&gt;
                                   // - if you need to keep them around, strdup them, as they may be changed later by other plugins calling ML_IPC_EDITQUERY.&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_SET_FILE_RATING 0x0906 // lParam = 0 to 5, rates current track -- inserts it in the db if it's not in it yet &lt;br /&gt;
#define ML_IPC_GET_FILE_RATING 0x0907 // return the current track's rating or 0 if not in db/no rating&lt;br /&gt;
&lt;br /&gt;
// playlist entry rating&lt;br /&gt;
typedef struct {&lt;br /&gt;
  const char* fileName;&lt;br /&gt;
  int newRating;&lt;br /&gt;
} file_set_rating;&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_SMARTVIEW_COUNT 0x0908	// returns the number of smartviews. no parameter required&lt;br /&gt;
#define ML_IPC_SMARTVIEW_INFO 0x0909	// pass a mlSmartViewInfo*. returns 1 on success and 0 on failure&lt;br /&gt;
#define ML_IPC_SMARTVIEW_ADD 0x0910	// pass a mlSmartViewInfo* with filled in size, name, query, mode, iconImgIndex. treeitemid gets filled in. returns 1 on success and 0 on failure&lt;br /&gt;
&lt;br /&gt;
typedef struct&lt;br /&gt;
{&lt;br /&gt;
	// you fill these in&lt;br /&gt;
	size_t size;  // set to sizeof(mlSmartViewInfo)&lt;br /&gt;
	size_t smartViewNum;&lt;br /&gt;
	// ml_local fills these in&lt;br /&gt;
	wchar_t smartViewName[128];&lt;br /&gt;
	wchar_t smartViewQuery[512];&lt;br /&gt;
	int mode;&lt;br /&gt;
	int iconImgIndex;&lt;br /&gt;
	int treeItemId;&lt;br /&gt;
} mlSmartViewInfo;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define ML_IPC_SET_FILE_RATINGW 0x0911 // lParam = 0 to 5, rates current track -- inserts it in the db if it's not in it yet &lt;br /&gt;
#define ML_IPC_GET_FILE_RATINGW 0x0912 // return the current track's rating or 0 if not in db/no rating&lt;br /&gt;
&lt;br /&gt;
// playlist entry rating&lt;br /&gt;
typedef struct {&lt;br /&gt;
  const wchar_t *fileName;&lt;br /&gt;
  int newRating;&lt;br /&gt;
} file_set_ratingW;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Language_API</id>
		<title>Language API</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Language_API"/>
				<updated>2008-09-25T13:04:58Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Language API&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Agave/Language/api_language.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Image_Loader_Service</id>
		<title>Image Loader Service</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Image_Loader_Service"/>
				<updated>2008-09-25T13:02:48Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Image Loader Service&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Include file: api/service/svcs/svc_imgload.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File_Reader_Service</id>
		<title>File Reader Service</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File_Reader_Service"/>
				<updated>2008-09-25T13:02:39Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;File Reader Service&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Include file: api/service/svcs/svc_fileread.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Creating_Custom_Cursors</id>
		<title>Creating Custom Cursors</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Creating_Custom_Cursors"/>
				<updated>2008-09-25T13:02:28Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Creating Custom Cursors&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Classic Skin:  [[The Base Skin]] --&amp;gt; [[Main|Paint the Main Window]] --&amp;gt; [[Equalizer|Paint the Equalizer Window]] --&amp;gt; [[Playlist|Paint the Playlist Window]] --&amp;gt; [[Mini-browser|Paint the Minibrowser Window]] --&amp;gt; [[AVS|Paint the AVS Window]] --&amp;gt; [[For_Winamp_2.9/5.x|Paint the Winamp 2.9/5.x Windows]] --&amp;gt; [[Creating Custom Cursors|Create Custom Cursors]] --&amp;gt; [[Editing the Configuration Files|Edit the Configuration Files]] --&amp;gt; [[WSZ Files|Compress to .WSZ format]] --&amp;gt; [[Submitting Your Skin to Winamp.com|Submit to Winamp.com]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A commonly overlooked skinning property is Winamp cursors. That is, the little arrow that you use to navigate through Winamp doesn't necessarily have to be an arrow. There are 27 different cursor states that Winamp can be in. Wouldn't it be cool if each one had specialized art that matched your skin? All you would need is an icon editing tool, and that idea becomes reality. &lt;br /&gt;
&lt;br /&gt;
==Cursor Filenames==&lt;br /&gt;
&lt;br /&gt;
The Base skin comes with the following cursors:&lt;br /&gt;
&lt;br /&gt;
*CLOSE.CUR: (Main Menu X)&lt;br /&gt;
*EQCLOSE.CUR: (EQ Close)&lt;br /&gt;
*EQNORMAL.CUR: (EQ Normal)&lt;br /&gt;
*EQSLID.CUR: (EQ Up and Down Slides)&lt;br /&gt;
*EQTITLE.CUR: (EQ Titlebar)&lt;br /&gt;
*MAINMENU.CUR: (Main Menu Menu Button-topleft)&lt;br /&gt;
*MIN.CUR: (Main Menu Minimize Button)&lt;br /&gt;
*NORMAL.CUR: (Main Menu Normal Arrow)&lt;br /&gt;
*PCLOSE.CUR: (Playlist Close)&lt;br /&gt;
*PNORMAL.CUR: (Playlist Normal)&lt;br /&gt;
*POSBAR.CUR: (Main Menu Song Position)&lt;br /&gt;
*PSIZE.CUR: (Playlist Expansion Mode)&lt;br /&gt;
*PTBAR.CUR: (Playlist Top Bar)&lt;br /&gt;
*PVSCROLL.CUR: (Playlist vertical button)&lt;br /&gt;
*PWINBUT.CUR: (Playlist Windowshade Mode)&lt;br /&gt;
*PWSNORM.CUR: (Playlist Windowshade Normal)&lt;br /&gt;
*PWSSIZE.CUR: (Playlist Windowshade Size Explainsion)&lt;br /&gt;
*SONGNAME.CUR: (Song Name Scroll)&lt;br /&gt;
*TITLEBAR.CUR: (Main Menu Name Bar)&lt;br /&gt;
*VOLBAL.CUR: (Main Menu Volume Balance)&lt;br /&gt;
*VOLBAR.CUR: (Main Menu Volume Switch)&lt;br /&gt;
*WINBUT.CUR: (Main Menu Windowshade Mode)&lt;br /&gt;
*WSCLOSE.CUR: (Windowshade Close)&lt;br /&gt;
*WSMIN.CUR: (WindowShade Main Minimize)&lt;br /&gt;
*WSNORMAL.CUR: (Windowshade Normal)&lt;br /&gt;
*WSPOSBAR.CUR: (Windowshade Song Position)&lt;br /&gt;
*WSWINBUT.CUR: (Windowshade Exit Windowshade Mode)&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/XML_Parser_Object</id>
		<title>XML Parser Object</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/XML_Parser_Object"/>
				<updated>2008-09-25T13:02:12Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;XML Parser Object&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;xml/obj_xml.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/WSZ_Files</id>
		<title>WSZ Files</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/WSZ_Files"/>
				<updated>2008-09-25T13:02:06Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;WSZ Files&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Classic Skin:  [[The Base Skin]] --&amp;gt; [[Main|Paint the Main Window]] --&amp;gt; [[Equalizer|Paint the Equalizer Window]] --&amp;gt; [[Playlist|Paint the Playlist Window]] --&amp;gt; [[Mini-browser|Paint the Minibrowser Window]] --&amp;gt; [[AVS|Paint the AVS Window]] --&amp;gt; [[For_Winamp_2.9/5.x|Paint the Winamp 2.9/5.x Windows]] --&amp;gt; [[Creating Custom Cursors|Create Custom Cursors]] --&amp;gt; [[Editing the Configuration Files|Edit the Configuration Files]] --&amp;gt; [[WSZ Files|Compress to .WSZ format]] --&amp;gt; [[Submitting Your Skin to Winamp.com|Submit to Winamp.com]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Winamp Skin Zip Files (WSZ)==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The last step you need to do before unleashing your Skin on the world is to convert it to the WSZ format. How do I do that, you ask? Just follow the following steps:&lt;br /&gt;
&lt;br /&gt;
#With your trusty zip compression tool of your choice, zip YOUR skin's folder (not the Winamp &amp;quot;Skins&amp;quot; folder) into a .zip file.&lt;br /&gt;
#Rename the new file's extension from .zip to .wsz.&lt;br /&gt;
#Test it by removing your skin folder, then placing your .WSZ into the Winamp &amp;quot;Skins&amp;quot; folder.&lt;br /&gt;
#Run Winamp, then press Alt-S to access the Skin browser. If you see your skin, then everything worked correctly.&lt;br /&gt;
#That's it! Pat yourself on the back, then take the next step and submit it to Winamp.com.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==WSZ History==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A Winamp skin is composed of 45 files. Most of the files that create a skin are .BMPs (a very common image file type) and a few text files. When skin support was originally implemented, an artist would have to create those skins and place them into a subdirectory of the Winamp Skins folder (Usually located in C:\Program Files\Winamp\Skins folder).&lt;br /&gt;
&lt;br /&gt;
This all started becoming a mess due to the fact that not all of the skin developers were creating subfolders when compressing their skins into a ZIP file for distribution. When an end-user uncompresses the files to the Winamp Skins folder, it would at times overwrite other skins. As a solution, we implemented the functionality into Winamp to read the .ZIP files directly. What would happen is an end-user would simply place the .ZIP file into their Winamp Skins folder and when using the Skin Browser in Winamp (ALT+S) the skin magically appeared and loaded if selected.&lt;br /&gt;
&lt;br /&gt;
This did clean up the mess, however, a new problem then surfaced. The .ZIP file format is a very widely used compression type and Winamp was just one of the many dozens of programs available to utilize it. We wanted users to be able to double click the Skin ZIP file and have Winamp automatically install and load the skin. How do we do that without associating Winamp as the default program for handling skins? Rename the file extension.&lt;br /&gt;
&lt;br /&gt;
We simply took all those compressed skins ending with the .ZIP and renamed them to end with .WSZ (Winamp Skin Zip). This allowed us to stay with the standard Winamp .ZIP files and not have to convert the thousands of skins available for download on the Internet. Any skins that are submitted to our site, ending with .ZIP or .WSZ, are automatically renamed to end with a .WSZ before published.&lt;br /&gt;
&lt;br /&gt;
Why do all this you ask? The answer is simple. We wanted to make it so that Winamp would automatically load the skin when a user clicked on a link to download a skin from Internet Explorer as well as Netscape Navigator. We also wanted to make it so that if a user actually had downloaded the .WSZ file, all they would have to do is double click it to install it.&lt;br /&gt;
&lt;br /&gt;
Exactly what happens at this point? Well, when a person installs a .WSZ file what happens is Winamp just copies the file to the Winamp Skins folder so that it can be handled correctly. You can also manually move the .WSZ file into your skin directory and Winamp will recognize it just as well.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Text_Feed_Service</id>
		<title>Text Feed Service</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Text_Feed_Service"/>
				<updated>2008-09-25T13:02:00Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Text Feed Service&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Include file: api/service/svcs/svc_textfeed.h&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Submitting_Your_Skin_to_Winamp.com</id>
		<title>Submitting Your Skin to Winamp.com</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Submitting_Your_Skin_to_Winamp.com"/>
				<updated>2008-09-25T13:01:53Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Submitting Your Skin to Winamp.com&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Creating a Classic Skin:  [[The Base Skin]] --&amp;gt; [[Main|Paint the Main Window]] --&amp;gt; [[Equalizer|Paint the Equalizer Window]] --&amp;gt; [[Playlist|Paint the Playlist Window]] --&amp;gt; [[Mini-browser|Paint the Minibrowser Window]] --&amp;gt; [[AVS|Paint the AVS Window]] --&amp;gt; [[For_Winamp_2.9/5.x|Paint the Winamp 2.9/5.x Windows]] --&amp;gt; [[Creating Custom Cursors|Create Custom Cursors]] --&amp;gt; [[Editing the Configuration Files|Edit the Configuration Files]] --&amp;gt; [[WSZ Files|Compress to .WSZ format]] --&amp;gt; [[Submitting Your Skin to Winamp.com|Submit to Winamp.com]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once you have an appropriate .WSZ file, the ultimate step is to share your masterpiece with the world. Your skin will join thousands of others on Winamp.com. This will allow people all over the world to enjoy the fruits of your labor. To do this, just follow these steps:&lt;br /&gt;
&lt;br /&gt;
#Have a classic skin ready in [[WSZ_Files|.WSZ]] format.&lt;br /&gt;
#Go to http://www.winamp.com/user/submit&lt;br /&gt;
#Select Classic Skins for Winamp 2.x compatible skins and click the &amp;quot;Submit a classic skin&amp;quot; button.&lt;br /&gt;
#Fill in the blanks:&lt;br /&gt;
## Name: The name of your skin.&lt;br /&gt;
## Comment: The short blurb that comes up when people browse the skins page.&lt;br /&gt;
## Description: The longer blurb that is displayed when people view the skin details page.&lt;br /&gt;
## Categories: Choose Primary and/or Secondary (optional) categories to properly sort your skin.&lt;br /&gt;
## Thumbnail: Click on the &amp;quot;Browse&amp;quot; button to find the .gif, .jpg, or .png file on your computer. Note: the image file dimensions should be no larger than 178px by 75px.&lt;br /&gt;
## Screenshot: (Full-sized screenshot of your skin.) Click on the &amp;quot;Browse&amp;quot; button to find the .gif, .jpg, or .png file on your computer. Note: the image file dimensions should be no larger than 275px by 600px.&lt;br /&gt;
## Skin File: Click on the &amp;quot;Browse&amp;quot; button to find the .WSZ (classic) or .WAL (modern) file on your computer.&lt;br /&gt;
#Click the &amp;quot;Submit&amp;quot; button, and...&lt;br /&gt;
#Voila! Your skin is on its way to being displayed (after being approved) before the world.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Skin Category Descriptions==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following descriptions are general guidelines. They are not intended to be taken too literally. In the end, it is up to you to decide which categories best fit your skin.&lt;br /&gt;
&lt;br /&gt;
* Animated: Inspired by cartoons, Japanese comics, or animated films.&lt;br /&gt;
* Compact/Utility: Minimalist/tiny/lightweight skins, or skins that server a special utility.&lt;br /&gt;
* Computer/OS: Inspired by an operating system's graphical user interface.&lt;br /&gt;
* Consumption: Skins inspired by food, beverages, or anything else consumed.&lt;br /&gt;
* Cool Devices: Skins made to look like... a cool... device.&lt;br /&gt;
* Games: Inspired by any segment of interactive entertainment software.&lt;br /&gt;
* Human: Skins based on humans. Aliens - down the hall to the &amp;quot;WTF&amp;quot; room.&lt;br /&gt;
* Movies/TV: Featuring screenshots, logos, or other paraphernalia connected to a feature film.&lt;br /&gt;
* Music: Inspired by a musical group, instrument or genre.&lt;br /&gt;
* Nature: Skins in tune with the natural habitat that surrounds woodland creatures, or the creatures themsevles.&lt;br /&gt;
* Retro: Conveys a sense of technologic, cultural or temporal nostalgia.&lt;br /&gt;
* Sports/University: Inspired by a sport, sports team, athlete, sporting event, or University.&lt;br /&gt;
* Stylish: Experimental skins built for aesthetics and new skinning ideas.&lt;br /&gt;
* Transportation: Skins based on cars, buses, trains, planes, camels, seagulls, etc.&lt;br /&gt;
* WTF: Skins that defy categorization. You know the type.&lt;br /&gt;
* Web Site: Inspired or sponsored by a web site.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Skin_API</id>
		<title>Skin API</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Skin_API"/>
				<updated>2008-09-25T13:01:47Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Skin API&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;api/skin/api_skin.h&lt;br /&gt;
&lt;br /&gt;
Modern Skin API.  Only present when gen_ff is loaded.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/SDK_Contents</id>
		<title>SDK Contents</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/SDK_Contents"/>
				<updated>2008-09-25T13:01:39Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;SDK Contents&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Agave - collection of [[Wasabi API|Wasabi]] objects unique to Winamp 5&lt;br /&gt;
&lt;br /&gt;
:Agave\AlbumArt - [[Album Art API]] interface definition files&lt;br /&gt;
&lt;br /&gt;
:Agave\Component - [[System Component Interface|W5S system component]]interface definition files&lt;br /&gt;
&lt;br /&gt;
:Agave\Config - [[Agave Config API|Winamp 5 configuration]].  Not be confused with the Winamp3 [[Wasabi Config API]]&lt;br /&gt;
&lt;br /&gt;
:Agave\Language - [[Language API]]&lt;br /&gt;
&lt;br /&gt;
:Agave\Metadata - [[Agave Metadata API]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
burner&lt;br /&gt;
&lt;br /&gt;
coverdirectory - Cover Directory sample plugin.  Demonstrates the [[Album Art API]], [[Service Factory|Service Factories]], and how to build a [[System Component Interface|System Component (W5S)]&lt;br /&gt;
&lt;br /&gt;
dsp_test - [[Audio Effects plugin|DSP Plugin]] example&lt;br /&gt;
&lt;br /&gt;
enc_flac - [[Audio Encoder Plugin]] example using the [http://flake-enc.sourceforge.net/ Flake] FLAC encoder.  Although the project name is enc_flac, the plugin compiles as enc_flake.dll to allow it to co-exist with the [http://flac.sourceforge.net/api/index.html libFLAC] based encoder that ships with Winamp.&lt;br /&gt;
&lt;br /&gt;
gen_classicart - Example [[General Purpose Plugin]] which demonstrates creating a Skinned window and the [[Album Art API]]&lt;br /&gt;
&lt;br /&gt;
gen_ml - Collection of header files that comprise the [[Media Library API]] and the struct definition for creating a [[Media Library Plugin]].  Most of the content is contained in ml.h&lt;br /&gt;
&lt;br /&gt;
gen_tray - Source code for the System Tray plugin which ships with Winamp.&lt;br /&gt;
&lt;br /&gt;
in_chain - Example plugin showing how to use another input plugin within your own input plugin&lt;br /&gt;
&lt;br /&gt;
in_raw - Example [[Input Plugin]]&lt;br /&gt;
&lt;br /&gt;
in_tone - Example [[Input Plugin]]&lt;br /&gt;
&lt;br /&gt;
irctell - Example [[System Component Interface|W5S]] plugin demonstrating [[System Callbacks API]] and the old Winamp3 [[Media Core API]] (only available in modern skins)&lt;br /&gt;
&lt;br /&gt;
maki - Tools and include files for compiling maki scripts for use in the Modern Skinning engine.  More information is available in the [[Skin Developer]] portion of this wiki.&lt;br /&gt;
&lt;br /&gt;
ml_http - Example [[Media Library Plugin]] demonstrating using embedded IE and the Javascript [[Javascript External Interface|window.external]] interface.&lt;br /&gt;
&lt;br /&gt;
ml_iso - Example [[Media Library Plugin]] demonstrating the send-to menu&lt;br /&gt;
&lt;br /&gt;
ml_local - Header files comprising the Local Media Database API&lt;br /&gt;
&lt;br /&gt;
ml_xmlex - Example [[Media Library Plugin]] demonstrating basic media libary UI concepts and the [[XML Parser object]]&lt;br /&gt;
&lt;br /&gt;
mlExplorer - Standalone executable demonstrating how to use the [[Nullsoft Database Engine|Nullsoft Database Engine (NDE)]] in your own application to read Winamp's media library contents.&lt;br /&gt;
&lt;br /&gt;
nde - [[Nullsoft Database Engine]] source code&lt;br /&gt;
&lt;br /&gt;
nsv&lt;br /&gt;
&lt;br /&gt;
nu&lt;br /&gt;
&lt;br /&gt;
playlist&lt;br /&gt;
&lt;br /&gt;
plLoadEx&lt;br /&gt;
&lt;br /&gt;
ReplayGainAnalysis&lt;br /&gt;
&lt;br /&gt;
Wasabi&lt;br /&gt;
&lt;br /&gt;
Winamp&lt;br /&gt;
&lt;br /&gt;
xml&lt;br /&gt;
&lt;br /&gt;
xspf&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Index.php/Winamp_Developer_Connect_Wiki_Terms_and_Conditions</id>
		<title>Index.php/Winamp Developer Connect Wiki Terms and Conditions</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Index.php/Winamp_Developer_Connect_Wiki_Terms_and_Conditions"/>
				<updated>2008-09-25T13:01:28Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Index.php/Winamp Developer Connect Wiki Terms and Conditions&amp;quot; [edit=sysop:move=sysop]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Winamp Developer Connect Wiki Terms and Conditions==&lt;br /&gt;
&lt;br /&gt;
Welcome!  The following terms govern your access, use and participate in Winamp’s Developer Connect Wiki (“Wiki Service”). &lt;br /&gt;
&lt;br /&gt;
BY REGISTERING OR BY USING THE WIKI SERVICE, YOU SIGNIFY ELECTRONICALLY YOUR AGREEMENT TO THE FOLLOWING TERMS. If you do not agree, you may not use the Wiki Service.&lt;br /&gt;
&lt;br /&gt;
==About the Developer Connect Wiki==&lt;br /&gt;
&lt;br /&gt;
The Wiki Service is a centralized resource that offers a consolidation of Winamp documentation, code samples, reference materials, and sample articles and gives the development community a place to share information. We offer the Wiki Service to help facilitate the development of Winamp skins, plugins, and visualization presets.  &lt;br /&gt;
&lt;br /&gt;
==About These Terms==&lt;br /&gt;
&lt;br /&gt;
The Wiki Service is provided by Nullsoft, Inc. and its affiliates (collectively, “we” or “us”). In order to use the Wiki Service, you must abide by Nullsoft Terms of Use for Winamp.com (http://www.winamp.com/legal/terms), the supplemental Wiki terms below, the Wiki Policy and Guidelines located at (http://qawinamptools.stream.aol.com/wiki/index.php/Policies_%26_Guidelines) and such other policies that we may post from time to time on the Wiki Service. These terms collectively make up your agreement with us regarding your access and use the Wiki Service (the “Terms”). We may change these Terms at any time. Your ongoing use of the Wiki Service after we post or notify you about changes to our terms signifies your agreement electronically to the updated terms.&lt;br /&gt;
&lt;br /&gt;
==Your requirements==&lt;br /&gt;
&lt;br /&gt;
In order to use the Wiki Service, you must register with us and provide complete, accurate and current information about yourself. You must keep this information up to date at all times. You must comply at all times with applicable laws and these Terms.&lt;br /&gt;
&lt;br /&gt;
==Use of Information==&lt;br /&gt;
&lt;br /&gt;
The Winamp Privacy Policy located at http://www.winamp.com/legal/privacy explains the practices that apply to your information when you use the Wiki Service. Your ongoing use of the Wiki Service signifies your consent to the information practices disclosed in our Privacy Policy.&lt;br /&gt;
&lt;br /&gt;
==Use of Wiki Service== &lt;br /&gt;
&lt;br /&gt;
You may not submit or transmit through the Wiki Service any material, or otherwise engage in any conduct that: &lt;br /&gt;
#violates or infringes the rights of others including, without limitation, patent, trademark, trade secret, copyright, publicity or other proprietary rights,&lt;br /&gt;
#is unlawful, threatening, abusive, harassing, defamatory, libelous, deceptive, fraudulent, invasive of another's privacy, tortious, or contains explicit or graphic descriptions, or accounts of, sexual acts,&lt;br /&gt;
#victimizes, harasses, degrades, or intimidates an individual or group of individuals on the basis of religion, gender, sexual orientation, race, ethnicity, age, or disability,&lt;br /&gt;
#impersonates any person, business or entity, &lt;br /&gt;
#contains viruses or any other malicious computer code, &lt;br /&gt;
#encourages conduct that would constitute a criminal offense, or that gives rise to civil liability,&lt;br /&gt;
#transmits, directly or indirectly, any unsolicited bulk communications (including e-mails, “spam” and instant messages),&lt;br /&gt;
#violates these Terms, including without limitation, the Nullsoft Terms of Use for Winamp.com, or&lt;br /&gt;
#interferes with the use of the Wiki Service or any other area on Winamp.com by others.&lt;br /&gt;
&lt;br /&gt;
==Ownership==&lt;br /&gt;
&lt;br /&gt;
The content on Wiki Service including, without limitation, images, graphics, audio, music, videos, texts, software, feedback, data, messages, answers, questions, comments, suggestions, ideas or any other materials (“Content”) are owned or licensed by us and protected under copyright and other intellectual property right laws. All trade names, trademarks and service marks appearing on the Content are protected by Nullsoft, Inc., its parent and affiliates or respective third party owners. Any rights not expressly granted herein are reserved. All Content is for your application development purposes and for your personal use only and may not be modified, reproduced, transmitted, published, exploited, sold, licensed or distributed to any third parties or in combination with any applications if the Content would constitute the primary value of the product being distributed.&lt;br /&gt;
 &lt;br /&gt;
==Submissions== &lt;br /&gt;
&lt;br /&gt;
The Wiki Service allows users to upload, download, edit, host, share and/or publish Content (“User Content”). We may, in our sole discretion, incorporate such User Content into any of our products or services. &lt;br /&gt;
&lt;br /&gt;
You are solely responsible for any submission of User Content. You may only submit User Content that you own or that you have acquired such consents, permissions or licenses needed to submit such Content. If your User Content contains content of a third party or open source material, you shall clearly notify us of such third-party material together with any license terms that deviate from those specified in these Terms, as well as be responsible for acquiring consent for such use the User Content. Any such third party content or open source material shall be subject to your obligation to indemnify us. Upon submission of any User Content to the Wiki Service, you will grant us and our parent a worldwide, perpetual, irrevocable, royalty-free, non-exclusive, assignable and sublicensable license to use, reproduce, modify, create derivative works, publicly perform and display such User Content in connection with any of our products or services, entirely without obligation, compensation or restriction of any kind. &lt;br /&gt;
 &lt;br /&gt;
==No Duty to Monitor==&lt;br /&gt;
&lt;br /&gt;
You agree that we are not liable for Content (including User Content) that is provided by others. We have no duty to pre-screen Content, but we have the right to refuse to post or to edit submitted Content. We reserve the right to remove Content for any reason, but we are not responsible for any failure or delay in removing such material. &lt;br /&gt;
&lt;br /&gt;
==Procedure for Making Claims of Copyright Infringement.== &lt;br /&gt;
&lt;br /&gt;
We respect the intellectual property of others. If you believe that your work has been copied and is accessible on the Wiki Service in a way that constitutes copyright infringement, please click here &amp;lt;http://about.aol.com/aolnetwork/copyright_infringement&amp;gt; for instructions on how to contact us to report possible copyright infringement.&lt;br /&gt;
&lt;br /&gt;
==No Warranties==&lt;br /&gt;
&lt;br /&gt;
We provide the Wiki Service &amp;quot;as is&amp;quot;, &amp;quot;with all faults&amp;quot; and &amp;quot;as available.&amp;quot; You use the Content and Wiki Service at your own risk. We and our suppliers and distributors make no express warranties or guarantees about the Wiki Service. TO THE EXTENT PERMITTED BY LAW, WE AND OUR SUPPLIERS DISCLAIM IMPLIED WARRANTIES THAT THE WIKI SERVICE ARE MERCHANTABLE, OF SATISFACTORY QUALITY, ACCURATE, TIMELY, FIT FOR A PARTICULAR PURPOSE OR NEED, OR NON-INFRINGING. WE DO NOT GUARANTEE THAT THE WIKI SERVICE WILL MEET YOUR REQUIREMENTS, IS ERROR-FREE, RELIABLE, WITHOUT INTERRUPTION OR AVAILABLE AT ALL TIMES. WE DO NOT GUARANTEE THAT THE RESULTS THAT MAY BE OBTAINED FROM THE WIKI SERVICE OR THAT YOU WILL BE ABLE TO ACCESS THE WIKI SERVICE AT ALL TIMES. You may have additional consumer rights under your local laws that this contract cannot change. &lt;br /&gt;
&lt;br /&gt;
==Limitation of Liability==&lt;br /&gt;
&lt;br /&gt;
YOUR SOLE AND EXCLUSIVE REMEDY FOR ANY DISPUTE WITH US IS TO DISCONTINUE YOUR USE OF THE WIKI SERVICE. WE, OUR PARENT, AND OUR SUPPLIERS SHALL NOT BE LIABLE FOR ANY INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES ARISING FROM YOUR USE OF, INABILITY TO USE, OR RELIANCE UPON AOL.COM. THESE EXCLUSIONS APPLY TO ANY CLAIMS FOR LOST PROFITS, LOST DATA, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF WE KNEW OR SHOULD HAVE KNOWN OF THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME STATES OR JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR THE LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, IN SUCH STATES OR JURISDICTIONS, OUR LIABILITY, AND THE LIABILITY OF OUR PARENT AND SUPPLIERS, SHALL BE LIMITED TO THE EXTENT PERMITTED BY LAW. &lt;br /&gt;
&lt;br /&gt;
==Indemnification==&lt;br /&gt;
&lt;br /&gt;
Upon a request by us, you agree to defend, indemnify, and hold harmless us and our parent and other affiliated companies, and our respective employees, contractors, officers, directors, and agents from all liabilities, claims, and expenses, including attorney's fees that arise from your use or misuse of the Wiki Service. We reserve the right, at our own expense, to assume the exclusive defense and control of any matter otherwise subject to indemnification by you, in which event you will cooperate with us in asserting any available defenses. &lt;br /&gt;
&lt;br /&gt;
==International Use==&lt;br /&gt;
&lt;br /&gt;
We make no representation that Content on the Wiki Service is appropriate or available for use in locations outside the United States, and accessing it from territories where the Content is illegal is prohibited. If you choose to access the Wiki Service from a location outside the U.S., you do so on your own initiative and you are responsible for compliance with local laws. &lt;br /&gt;
&lt;br /&gt;
==Software Restrictions==&lt;br /&gt;
&lt;br /&gt;
Any software offered through the Wiki Service is a &amp;quot;commercial item,&amp;quot; as that term is defined in 48 C.F.R. 2.101, consisting of &amp;quot;commercial computer software&amp;quot; and &amp;quot;commercial computer software documentation,&amp;quot; as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 27.405(b)(2) (June 1998) and 48 C.F.R. 227.7202, all U.S. Government end users acquire the software with only those rights as set forth herein. You agree to fully comply with all import and export laws, regulations, rules and orders of the United States, or any foreign government agency or authority, and that you will not directly or indirectly export, re-export, transfer and/or release the software, related technology, or any product thereof, for any proscribed end-use, or to any proscribed country, entity or person (wherever located), without proper authorization from the U.S. and/or foreign government. &lt;br /&gt;
&lt;br /&gt;
==Choice of Law==&lt;br /&gt;
&lt;br /&gt;
You agree that the laws of the Commonwealth of Virginia govern this contract and any claim or dispute that you may have against us, without regard to Virginia’s conflict of laws rules, and that the United Nations Convention on Contracts for the International Sale of Goods shall have no applicability. You further agree that any disputes or claims that you may have against us will be resolved by a court located in the Commonwealth of Virginia and you agree and submit to the exercise of personal jurisdiction of such courts for the purpose of litigating any such claim or action. PLEASE NOTE THAT BY AGREEING TO THESE TERMS OF USE, YOU ARE: (1) WAIVING CLAIMS THAT YOU MIGHT OTHERWISE HAVE AGAINST US BASED ON THE LAWS OF OTHER JURISDICTIONS, INCLUDING YOUR OWN; (2) IRREVOCABLY CONSENTING TO THE EXCLUSIVE JURISDICTION OF, AND VENUE IN, STATE OR FEDERAL COURTS IN THE COMMONWEALTH OF VIRGINIA OVER ANY DISPUTES OR CLAIMS YOU HAVE WITH US; AND (3) SUBMITTING YOURSELF TO THE PERSONAL JURISDICTION OF COURTS LOCATED IN THE COMMONWEALTH OF VIRGINIA FOR THE PURPOSE OF RESOLVING ANY SUCH DISPUTES OR CLAIMS.&lt;br /&gt;
&lt;br /&gt;
==Termination==&lt;br /&gt;
&lt;br /&gt;
Your right to use the Wiki Service automatically terminates if you violate these Terms or any rules or guidelines posted in connection with AOL.COM. We also reserve the right, in our sole discretion, to terminate your access to all or part of the Wiki Service, for any reason, with or without notice.&lt;br /&gt;
&lt;br /&gt;
==Electronic Notices==&lt;br /&gt;
&lt;br /&gt;
YOU AGREE TO TRANSACT WITH US ELECTRONICALLY. WE MAY PROVIDE NOTICES TO YOU ELECTRONICALLY (1) VIA E-MAIL IF YOU HAVE PROVIDED US WITH A VALID EMAIL ADDRESS OR (2) BY POSTING THE NOTICE ON A WEBSITE DESIGNATED BY US FOR THIS PURPOSE. The delivery of any Notice is effective when sent or posted by us, regardless of whether you read the Notice or actually receive delivery. You can withdraw your consent to receive Notices electronically by discontinuing your use of the Wiki Service. &lt;br /&gt;
&lt;br /&gt;
==General Terms==&lt;br /&gt;
&lt;br /&gt;
(a) This agreement constitutes the entire agreement between you and us concerning the subject matter of these Terms, which may only be modified by us. (b) This Agreement shall not be governed by the United Nations Convention on Contracts for the International Sale of Goods. (c) If any part of these Terms is held invalid or unenforceable, that part shall be construed to reflect the parties' original intent as nearly as practicable, and the remaining portions remain in full force and effect, or we may at its option instead terminate this Agreement. (d) English is the controlling language of these Terms. If you have received a translation into another language, it has been provided for your convenience only. (e) A waiver by either party of any term or condition of this Agreement or any breach thereof, in any one instance, shall not waive such term or condition or any subsequent breach thereof. (f) You may not assign or otherwise transfer by operation of law or otherwise this Agreement or any rights or obligations herein. We may assign these Terms to any entity, including to any of our affiliates or parent at our sole discretion. (g) These Terms shall be binding upon and shall inure to the benefit of the parties, their successors and permitted assigns.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Plugin_Terminology</id>
		<title>Plugin Terminology</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Plugin_Terminology"/>
				<updated>2008-09-25T13:00:16Z</updated>
		
		<summary type="html">&lt;p&gt;Tarik: Protected &amp;quot;Plugin Terminology&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== winamp plugin filename conventions ==&lt;br /&gt;
Most plugin types are identified by Winamp by the filename&lt;br /&gt;
* in_*.dll - input plugins&lt;br /&gt;
* out_*.dll - output plugins&lt;br /&gt;
* gen_*.dll - general purpose plugins&lt;br /&gt;
* vis_*.dll - visualizer plugins&lt;br /&gt;
* dsp_*.dll - audio effects plugins&lt;br /&gt;
* ml_*.dll - media library plugins (loaded by gen_ml.dll)&lt;br /&gt;
* pmp_*.dll - portable media player plugins (loaded by ml_pmp.dll... a plugin type loaded by a plugin of a plugin. hah!)&lt;br /&gt;
* nsvdec_*.dll - NSV decoder plugins&lt;br /&gt;
* enc_*.dll - audio encoder plugins&lt;br /&gt;
* W5S (Winamp 5 System) plugins located in c:\program files\winamp\system do not have to follow any special filename convention except for the .w5s file extension&lt;br /&gt;
* WAC (Winamp Component) plugins located in c:\program files\winamp\plugins\freeform\wacs do not have to follow any special filename conventions, either, except for the .wac file extension.  WAC files are loaded by gen_ff.dll&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== code naming conventions ==&lt;br /&gt;
* IPC: Inter-Plugin Communications.  The constants which define the old SendMessage API are prefixed with IPC_&lt;br /&gt;
* Wasabi: Winamp Service Architecture Binary Interface.  A system to allow sharing of C++ objects between different plugins and components.  Think of it as a very lightweight version of COM.&lt;br /&gt;
* Agave: project codename for Winamp 5.12 (when the Wasabi service manager was merged into Winamp 5.  It may or may not have involved a lot of tequila).  The name &amp;quot;Agave&amp;quot; is used in the SDK to refer to Wasabi components that are unique to Winamp's media platform.  For example: the Wasabi Language API could be used in other (non-Winamp) Wasabi applications, but the Agave Playlist Manager makes very little sense outside of a media application.&lt;br /&gt;
&lt;br /&gt;
Wasabi interfaces are all built using the Dispatchable base class.  A naming convention has been established to help developers understand the intent of the interface.&lt;br /&gt;
* ifc: interface.  Wasabi interfaces not associated with the service manager are prefixed with this, e.g. ifc_window&lt;br /&gt;
* api: Wasabi interfaces which expose a singleton object meant to be used as a global API.  e.g. api_application&lt;br /&gt;
* svc: service.  Wasabi interfaces which define a service are prefixed with this, e.g. svc_playlisthandler&lt;br /&gt;
* obj: object.  Wasabi interfaces which define an object created by the service manager are prefixed with this.  e.g. obj_xml for an instance of an XML parser.&lt;/div&gt;</summary>
		<author><name>Tarik</name></author>	</entry>

	</feed>