Click here to Skip to main content
15,894,460 members
Articles / Programming Languages / C#

Using Winamp input plugins for tagging audio files

Rate me:
Please Sign up or sign in to vote.
4.74/5 (9 votes)
21 Jun 2007CPOL5 min read 68.9K   456   30  
C# Interop with dynamic loaded plug-ins and function pointers
using System;
using System.Runtime.InteropServices;
using System.Text;

// RightToCopy & PublishAndPerish: OrlandoCurioso 2007
// Ansi/Unicode SDK 5.32

namespace OC.Winamp
{
    internal abstract partial class Constants
    {
        public const int IN_VER = 0x100;
        public const int IN_VER_UNI = 0x0f000100;
        public const int IN_UNICODE = 0x0F000000;
        public const int GETFILEINFO_TITLE_LENGTH = 2048;
    }

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    internal delegate IntPtr GetInModulePtr();        //typedef In_Module*	(*WINAMPGETINMODULE2)( void );

    internal abstract partial class AnsiDelegates
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet= CharSet.Ansi)]
        public delegate int IntString(string fn);
        [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public delegate void GetFileInfo(string file, StringBuilder title, out int length_in_ms);
        [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public delegate int InfoBox(string file, IntPtr hwndParent);
    }

    internal abstract partial class UnicodeDelegates
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public delegate int IntString(string fn);
        [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public delegate void GetFileInfo(string file, StringBuilder title, out int length_in_ms);
        [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public delegate int InfoBox(string file, IntPtr hwndParent);
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 152)]
    internal class In_Module
    {
        public int version;				// module type (IN_VER or IN_VER_UNI)
        [MarshalAs(UnmanagedType.LPStr)]
        public string description;		// always ANSI
        public IntPtr hMainWindow;		// winamp's main window (filled in by winamp)
        public IntPtr hDllInstance;		// DLL instance handle  (filled in by winamp)
        [MarshalAs(UnmanagedType.LPStr)]
        public string FileExtensions;	// always ANSI
        public int is_seekable;
        public int UsesOutputPlug;

        public delegate void VoidIntPtrdelegate(IntPtr hwndParent);
        public delegate void VoidVoiddelegate();
        public delegate int IntVoiddelegate();
        public delegate void VoidIntdelegate(int value);
        public delegate int IntIntdelegate(int value);
        public delegate void EQSetdelegate(int on, [MarshalAs(UnmanagedType.LPArray, SizeConst = 10)] byte[] data, int preamp);

        [MarshalAs(UnmanagedType.FunctionPtr)]
        public VoidIntPtrdelegate Config;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public VoidIntPtrdelegate About;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public VoidVoiddelegate Init;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public VoidVoiddelegate Quit;
        public IntPtr GetFileInfo;              // GetFileInfodelegate
        public IntPtr InfoBox;                  // InfoBoxdelegate
        public IntPtr IsOurFile;                // IntStringdelegate
        public IntPtr Play;                     // IntStringdelegate
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public VoidVoiddelegate Pause;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public VoidVoiddelegate UnPause;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public IntVoiddelegate IsPaused;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public VoidVoiddelegate Stop;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public IntVoiddelegate GetLength;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public IntVoiddelegate GetOutputTime;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public IntIntdelegate SetOutputTime;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public VoidIntdelegate SetVolume;
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public VoidIntdelegate SetPan;

        public IntPtr SAVSAInit;                 // all filled in by winamp, except EQSet
        public IntPtr SAVSADeInit;
        public IntPtr SAAddPCMData;
        public IntPtr SAGetMode;
        public IntPtr SAAdd;

        public IntPtr VSAAddPCMData;
        public IntPtr VSAGetMode;
        public IntPtr VSAAdd;
        public IntPtr VSASetInfo;

        public IntPtr dsp_isactive;
        public IntPtr dsp_dosamples;

        [MarshalAs(UnmanagedType.FunctionPtr)]
        public EQSetdelegate EQSet;

        public IntPtr SetInfo;
        public IntPtr outMod;
    }
}


#region in2.h / SDK 5.32

#if false

//#ifndef NULLSOFT_WINAMP_IN2H
//#define NULLSOFT_WINAMP_IN2H
//#include "out.h"

//// note: exported symbol is now winampGetInModule2.

//#define IN_UNICODE 0x0F000000

//#ifdef UNICODE_INPUT_PLUGIN
//#define in_char wchar_t
//#define IN_VER (IN_UNICODE | 0x100)
//#else
//#define in_char char
//#define IN_VER 0x100
//#endif

typedef struct 
{
	int version;				// module type (IN_VER)
	char *description;			// description of module, with version string

	HWND hMainWindow;			// winamp's main window (filled in by winamp)
	HINSTANCE hDllInstance;		// DLL instance handle (Also filled in by winamp)

	char *FileExtensions;		// "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
								// May be altered from Config, so the user can select what they want
	
	int is_seekable;			// is this stream seekable? 
	int UsesOutputPlug;			// does this plug-in use the output plug-ins? (musn't ever change, ever :)

	void (*Config)(HWND hwndParent); // configuration dialog
	void (*About)(HWND hwndParent);  // about dialog

	void (*Init)();				// called at program init
	void (*Quit)();				// called at program quit

//#define GETFILEINFO_TITLE_LENGTH 2048 
	void (*GetFileInfo)(const in_char *file, in_char *title, int *length_in_ms); // if file == NULL, current playing is used
	int (*InfoBox)(const in_char *file, HWND hwndParent);
	
	int (*IsOurFile)(const in_char *fn);	// called before extension checks, to allow detection of mms://, etc
	// playback stuff
	int (*Play)(const in_char *fn);		// return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error
	void (*Pause)();			// pause stream
	void (*UnPause)();			// unpause stream
	int (*IsPaused)();			// ispaused? return 1 if paused, 0 if not
	void (*Stop)();				// stop (unload) stream

	// time stuff
	int (*GetLength)();			// get length in ms
	int (*GetOutputTime)();		// returns current output time in ms. (usually returns outMod->GetOutputTime()
	void (*SetOutputTime)(int time_in_ms);	// seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush()..

	// volume stuff
	void (*SetVolume)(int volume);	// from 0 to 255.. usually just call outMod->SetVolume
	void (*SetPan)(int pan);	// from -127 to 127.. usually just call outMod->SetPan
	
	// in-window builtin vis stuff

	void (*SAVSAInit)(int maxlatency_in_ms, int srate);		// call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
	// call after opening audio device with max latency in ms and samplerate
	void (*SAVSADeInit)();	// call in Stop()


	// simple vis supplying mode
	void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); 
											// sets the spec data directly from PCM data
											// quick and easy way to get vis working :)
											// needs at least 576 samples :)

	// advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
	int (*SAGetMode)();		// gets csa (the current type (4=ws,2=osc,1=spec))
							// use when calling SAAdd()
	int (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp


	// vis stuff (plug-in)
	// simple vis supplying mode
	void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
											// quick and easy way to get vis working :)
											// needs at least 576 samples :)

	// advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
	int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd
	int (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in


	// call this in Play() to tell the vis plug-ins the current output params. 
	void (*VSASetInfo)(int srate, int nch); // <-- Correct (benski, dec 2005).. old declaration had the params backwards


	// dsp plug-in processing: 
	// (filled in by winamp, calld by input plug)

	// returns 1 if active (which means that the number of samples returned by dsp_dosamples
	// could be greater than went in.. Use it to estimate if you'll have enough room in the
	// output buffer
	int (*dsp_isactive)(); 

	// returns number of samples to output. This can be as much as twice numsamples. 
	// be sure to allocate enough buffer for samples, then.
	int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate);


	// eq stuff
	void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.

	// info setting (filled in by winamp)
	void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)

	Out_Module *outMod; // filled in by winamp, optionally used :)
} In_Module;

//#endif

#endif

#endregion

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions