Winamp General Purpose Plug-ins (Track Title Spool to File)
Winamp Track Title Monitor lets you output formatted data about the currently playing track to a text-file and supports multiple instances of Winamp on the same machine.
Downloads for the software described here are available on the downloads page.
UPDATE 2nd February 2008: There is a bug in the 3rd party LRTimer code which prevents more than one timer being created on the machine. This is because it created a named timer “LRTimer” – when an existing timer with the same name already exists, the handle to the existing timer is returned. To fix this, change
"LRTimer" on line 61 of lrtimer.cpp to
NULL before compiling. This creates an un-named timer instead. I have updated the DLL download and source files to fix the bug.
UPDATE 18th July 2006: There is a bug in the 3rd party LRTimer code which causes the timer thread (and therefore Winamp) to consume 100% CPU time. To correct this, change
SleepEx(0, TRUE); on line 77 of lrtimer.cpp to
SleepEx(INFINITE, TRUE); before compiling. I have updated the DLL download to fix the bug.
At Deviant Audio, we have two separate radio stations with separate content at the time of writing (July 2006). Until recently, these two stations had their content sourced on different servers, however they have recently been merged onto the same machine. This means that the uplink server (a Windows Server 2003 box) runs two copies of Winamp with two separate playlists, streaming silently to two separate SHOUTcast distribution servers.
A while ago I coded a little toy for our chat room called DChat. DChat allows users to type a command like “!dchat Hello World” into the chat room, and the message is appended to the current track title and output in the stream metadata. This allows listeners to leave messages “on the stream” that all other listeners can see in their player window.
DChat works as follows:
- A general purpose Winamp plug-in extracts the currently playing song title and writes it in a text file to a network share on our LAN
- The DChat code polls the file periodically, merges it with the DChat message and writes the combined text, eg. “Song Title ]#[ DChat Message” to another file.
- Our audio encoder DSP (Oddcast 3) picks up the contents of this file periodically and outputs it as the song title metadata on the stream.
This worked fine until I introduced the second instance of Winamp onto the machine. Winamp 5.11 and later offers the ability to store multiple configurations for winamp.ini and plugin ini files in separate locations, which can be utilised separately by each instance. This allows each plugin on each instance to have a unique configuration. This is important in the running of Deviant Audio so that for example, Oddcast can be configured to stream to a different server for each running instance. You can invoke multiple configuration instancing thus:
Winamp.exe /INIDIR=path/to/configuration /M3UDIR=path/to/default/playlist
/INIDIR changes the path for all configuration files including winamp.ini and any plugins. /M3UDIR changes the playlist loaded when Winamp starts up if no other files are specified. More about these options can be found in this Winamp forum post.
The problem: the song title plugin we were using unfortunately does not respect the specified plugin directory, instead hardcoding its configuration in %Winamp%\Plugins. With two instances of Winamp, this means the song title on our station using DChat gets overwritten when the track changes in either copy of Winamp (causing song titles from the other station to be replicated on the DChat-using station).
I tried a total of seven song title plugins, all of which failed to meet the criteria:
- Store configuration in specified configuration directory per instance
- Refresh the song title file when playing an http stream in Winamp. This is important because we use relays to broadcast live shows with live track titles from other DJs, and some plugins only update the song title file when the actual track is changed, rather than when the song title is changed.
For reference, these are the plugins tried:
- What’s Playing 1.1 – doesn’t output http stream title data
- Now Playing 2.0.2 – doesn’t output http stream title data
- WinampThingy – doesn’t output song title as text file (script calling only)
- Currently Playing 2 Textfile (cp2txt) – doesn’t use specified plugin configuration directory [this is the plugin we have been using so far]
- Toaster – doesn’t output song title as text file (visual display and AIM, MSN, IRC-type IPC integration only)
- Winamp History 1.12 – crashes on our Winamp installs
- Currently Hearing 2.0 – doesn’t use specified plugin configuration directory
These plugins were of course probably not tested for multi-instancing since it is a relatively new feature of Winamp. One solution would be to clone the entire Winamp folder, however I wanted a more elegant solution to reduce administration overhead, so I decided to code my own plugin to do the job.
The plugin was coded in Visual Studio 2005 as a C++ DLL using the Winamp 5.04 custom SDK, which you can obtain from winamp.com. I also made use of LRTimer, the free Low Resolution Timer API for C++.
In general, it wasn’t too difficult once all the messy boilerplate code was sorted out, however I want to point out one major pitfall to other would-be multi-instance plugin developers, that wasted considerable time:
char *ini_file = (char *) SendMessage(plugin.hwndParent, WM_WA_IPC, 0, IPC_GETINIFILE);
This code is meant to retrieve the instance-specific path to winamp.ini, which you can then store your configuration settings in (if you want to use your own configuration file, you can replace IPC_GETINIFILE with IPC_GETINIDIRECTORY which returns an instance-specific plugin configuration directory you can write files to).
plugin.hwndParent contains Winamp’s main window handle, which receives most IPC calls from plugins and external applications. However, during general plugin initialisation, the window has not been created yet, therefore the window handle is invalid and IPC_GETINIFILE does not return a valid result.
The solution to this is to wait until Winamp calls your plugin’s initialisation routine. Do not execute routines or create objects at DLL load-time which make IPC calls to Winamp, as they will fail. When the initialisation routine is called, the window handle will have been created and the IPC calls will work.
This seems pretty obvious now, but it took me several hours to solve 🙂
The Track Monitor plugin I created meets the two criteria mentioned, with a dialog-configurable target path, refresh interval and optional enable/disable toggle. I hope you find it useful. I have made a point of commenting the source code well for new plugin coders as the Winamp API examples are rather undocumented.
Please send feedback via the contact page or leave a comment below.