Click here to Skip to main content
15,892,517 members
Articles / Desktop Programming / WTL

Multidevice ASIO output plugin for WinAMP

Rate me:
Please Sign up or sign in to vote.
4.80/5 (9 votes)
13 Feb 2009CDDL27 min read 48.2K   728   23  
A tiny WinAMP output DLL that uses a C++ replacement of the official ASIO SDK that supports multiple ASIO devices.
#pragma once

#include "WinAMP.hpp"


namespace WinAMP
{

namespace OutModule
{

extern "C"
{

////////////////////////////////////////////////////////////////////////////////
//
//  Out_Module
//  ----------
//
//  A workaround copy-paste redefinition of the Out_Module struct from the out.h
// WA SDK header that only adds the __cdecl specifiers to enable compiling with
// a default global calling convention different from cdecl.
//
// (todo) try to think of something better.
//
////////////////////////////////////////////////////////////////////////////////
//#include "WA SDK/Winamp/OUT.H"

#define OUT_VER 0x10

struct Out_Module
{
	int version;				// module version (OUT_VER)
	char *description;			// description of module, with version string
	intptr_t id;						// module id. each input module gets its own. non-nullsoft modules should
								// be >= 65536. 

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

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

	void (__cdecl *Init)();				// called when loaded
	void (__cdecl *Quit)();				// called when unloaded

	int (__cdecl *Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms); 
					// returns >=0 on success, <0 on failure

					// NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins. 
					//    ... so don't expect the max latency returned to be what you asked for.
					// returns max latency in ms (0 for diskwriters, etc)
					// bufferlenms and prebufferms must be in ms. 0 to use defaults. 
					// prebufferms must be <= bufferlenms
					// pass bufferlenms==-666 to tell the output plugin that it's clock is going to be used to sync video
					//   out_ds turns off silence-eating when -666 is passed

	void (__cdecl *Close)();	// close the ol' output device.

	int (__cdecl *Write)(char *buf, int len);	
					// 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data. 
					// 1 returns not able to write (yet). Non-blocking, always.

	int (__cdecl *CanWrite)();	// returns number of bytes possible to write at a given time. 
						// Never will decrease unless you call Write (or Close, heh)

	int (__cdecl *IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be
						// written (i.e. closing while IsPlaying() returns 1 would truncate the song

	int (__cdecl *Pause)(int pause); // returns previous pause state

	void (__cdecl *SetVolume)(int volume); // volume is 0-255
	void (__cdecl *SetPan)(int pan); // pan is -128 to 128

	void (__cdecl *Flush)(int t);	// flushes buffers and restarts output at time t (in ms) 
							// (used for seeking)

	int (__cdecl *GetOutputTime)(); // returns played time in MS
	int (__cdecl *GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff)

};

//  Forward declarations of WinAMP output module callbacks. Implementations must
// be provided by the concrete output plugin module.
void __cdecl Init        ();
void __cdecl Quit        ();

int  __cdecl Open        ( int sampleRate, int numChannels, int BPS, int bufferLen_ms, int prebuffer_ms );
void __cdecl Close       ();

int  __cdecl IsPlaying   ();
int  __cdecl Pause       ( int pause  );

int  __cdecl CanWrite    ();
int  __cdecl Write       ( char * buf, int len );

void __cdecl SetVolume   ( int volume  );
void __cdecl SetPan      ( int pan     );
void __cdecl Flush       ( int time_ms );

int  __cdecl GetWrittenTime();
int  __cdecl GetOutputTime ();

void __cdecl ConfigDialog( HWND hwnd );
void __cdecl About       ( HWND hwnd );

}


//  Functions for automatic filling of the WinAMP output module Out_Module
// structure. Must be implemented by the concrete output module plugin.
char const * WAOutModuleDescription();
intptr_t     WAOutModuleID();


// Compile time configuration.
static size_t const maxWAInputChunk = 8192; // As specified by an out.h comment.


////////////////////////////////////////////////////////////////////////////////
//
//  WAOutModule
//  -----------
//
//  A wrapper around the Out_Module struct that fills it automatically and
// provides methods to change/configure some of the callbacks at runtime as well
// as some default implementations for those same callbacks.
//
////////////////////////////////////////////////////////////////////////////////

class WAOutModule : private Out_Module
{
public:
    static WAOutModule & singleton();

    Out_Module & getWAOutModule() { return *this; }

    HWND      WinAMPWindow() const { assert( hMainWindow  && "WinAMP didn't fill in it's window handle!"      ); return hMainWindow ; }
    HINSTANCE DLLInstance () const { assert( hDllInstance && "WinAMP didn't fill in the DLL instance handle!" ); return hDllInstance; }

    // Configurable callbacks.
    typedef int  (__cdecl *WriteCallback    )( char * buf, int len );
    typedef void (__cdecl *SetVolumeCallback)( int volume          );
    typedef void (__cdecl *SetPanCallback   )( int pan             );

    void setWriteCallback    ( WriteCallback     writeCallback     ) { Write     = writeCallback    ; }
    void setSetVolumeCallback( SetVolumeCallback setVolumeCallback ) { SetVolume = setVolumeCallback; }
    void setSetPanCallback   ( SetPanCallback    setPanCallback    ) { SetPan    = setPanCallback   ; }

    // Default callback implementations.
    static void __cdecl SetVolumeMixer  ( int volume );
    static void __cdecl SetVolumeWaveOut( int volume );
    static void __cdecl SetVolumeVoid   ( int        ) {}

    static void __cdecl SetPanWaveOut( int pan );
    static void __cdecl SetPanMixer  ( int pan );
    static void __cdecl SetPanVoid   ( int     ) {}

private:
    WAOutModule();

    static WAOutModule WinAMPOutModule;
};

}   // namespace OutModule

}   // namespace WinAMP

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 Common Development and Distribution License (CDDL)


Written By
Software Developer Little Endian Ltd.
Croatia Croatia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions