|
#pragma once
#include "WAOutModule.hpp"
#include "ASIODevice.hpp"
#include "buffers.hpp"
#include "resource.h"
#include <list>
#include <map>
#include <vector>
namespace WinAMP
{
namespace OutModule
{
class Writer;
// The maximum number of supported channels is a compile time parameter to
// avoid the extra dereferencing related to run-time allocated arrays/containers
// /buffers and the space overhead for any practical value is negligible.
// It is specified through a compile time constant (instead as a template
// parameter) to avoid template parameter pollution/ugliness of every
// out-of-line declaration/definition.
size_t const maxSupportedChannels = 2;
////////////////////////////////////////////////////////////////////////////////
//
// WAASIOOut
// ---------
//
// A singleton class modeling the main logic of the Wasiona plugin.
//
////////////////////////////////////////////////////////////////////////////////
class WAASIOOut
{
public:
class Config;
////////////////////////////////////////////////////////////////////////////
//
// WAASIOOut::Device
// -----------------
//
// Extends the ASIODevice class with the functionality needed by a WinAMP
// output plugin.
//
////////////////////////////////////////////////////////////////////////////
class Device : public ASIODevice<0, maxSupportedChannels>
{
typedef ASIODevice<0, maxSupportedChannels> Base;
public:
Device( ASIODriver const &, TCHAR const * driverModulePath );
static Device & getThreadInstance() { return static_cast<Device &>( Base::getThreadInstance() ); }
size_t outputBufferSizeInBytesPerChannel() const { return outputBufferSizeInBytesPerChannel_; }
void cacheOutputBufferSize( size_t outputBytesPerSample, size_t outputBufferSizeInSamplesPerChannel );
bool start() { return supportsCallbackSwitching_ ? Base::startUsingCallbackSwitching() : Base::start(); }
MultiChannelBuffer::Reader & reader() { return bufferReader_; }
MultiChannelBuffer::Reader const & reader() const { return const_cast<Device &>( *this ).reader(); }
private:
MultiChannelBuffer::Reader bufferReader_;
size_t outputBufferSizeInBytesPerChannel_;
bool const supportsCallbackSwitching_;
};
typedef MultiChannelBuffer Buffer;
//typedef std::vector<Writer *> Writers; // ...trading speed for space
typedef std::list<Writer *> Writers; // with std::list over
//typedef std::vector<Device> Devices; // std::vector...
typedef std::list<Device> Devices;
public:
static WAASIOOut & singleton() { return singleton_; }
Devices & devices() { return devices_; }
Writers & activeWriters() { return inWriters_; }
Writers const & activeWriters() const { return const_cast<WAASIOOut &>( *this ).inWriters_; }
static Config & config ();
unsigned & inputSampleRate () { return sampleRate_; }
unsigned & inputBytesPerSample() { return inputBytesPerSample_; }
unsigned & numberOfInChannels ();
long & gain() { return gain_; }
bool checkAndSaveNewIOParameters( int sampleRate, int numChannels, int BPS );
bool initialized() const;
bool initialize();
bool updateDevicesAndWritersWithNewIOParameters();
long getMaxLatency();
void pauseDevices();
void startDevices();
void stopDevices ();
BOOL pause ( int newPauseState );
BOOL paused() const { return pause_; }
void resetTrackVariables();
void setCurrentDeviceTime( ASIOTime const *, size_t underflowBytes, Device const & );
unsigned long trackOutputTime() const { return timeAlreadyPlayedBeforeLastUnpause_ + lastASIOOutputTime_; }
void resetWriters();
void clear() { devices_.clear(); inWriters_.clear(); }
bool comInitialized() const { return comInitialized_; }
bool initializeCOM();
void uninitializeCOM() { ::CoUninitialize(); comInitialized_ = false; }
bool shouldReinitialize() const { return shouldReinitialize_; }
void setShouldReinitialize() { shouldReinitialize_ = true; }
static int WAOutModuleID() { return 76647; }
static char const * WAOutModuleDescription() { return "wasiona: experimental multi-device ASIO output plug-in"; }
static char const * IniSection() { return "wasiona"; }
static void __cdecl SetVolumeLazy( int volume );
static void __cdecl SetVolumeASIO( int volume );
static void __cdecl SetPanASIO ( int pan );
static void setVolumeAndPanningCallbacks();
private:
WAASIOOut();
bool loadDevices();
private: // ASIO callbacks
static void __cdecl BufferSwitch ( long doubleBufferIndex, ASIOBool directProcess );
static ASIOTime * __cdecl BufferSwitchTimeInfo( ASIOTime *, long doubleBufferIndex, ASIOBool directProcess );
static void __cdecl SampleRateDidChange ( ASIOSampleRate );
static long __cdecl ASIOMessage ( long selector, long value, void * message, double * opt );
private:
Devices devices_ ;
Writers inWriters_;
unsigned int numberOfInputChannels_ ;
unsigned int inputBytesPerSample_ ;
unsigned int sampleRate_ ;
unsigned int lastASIOOutputTime_ ;
unsigned int underflowSamples_ ;
unsigned int timeAlreadyPlayedBeforeLastUnpause_;
BOOL pause_ ;
long gain_ ;
bool comInitialized_ ;
bool shouldReinitialize_;
static WAASIOOut singleton_;
};
////////////////////////////////////////////////////////////////////////////////
//
// WAASIOOut::Config
// -----------------
//
// Wraps the configuration code and the interaction with WA's plugin.ini.
//
// (todo) To be cleaned up, documented and improved, probably the least mature
// part of the code.
//
////////////////////////////////////////////////////////////////////////////////
class WAASIOOut::Config
{
public:
enum VolumeControler
{
Void = ID_DISABLED,
waveOUT = ID_WAVEOUT ,
mixerAPI = ID_MIXERAPI,
ASIO = ID_ASIO
};
typedef BYTE DeviceIndices[ 10 ];
static BYTE const terminator = static_cast<BYTE>( LB_ERR );
public:
Config()
{
if ( !ReadConfig( *this, WAASIOOut::IniSection() ) || ( structVersion_ != currentConfigVersion ) )
setDefault();
}
~Config()
{
VERIFY( SaveConfig( *this, WAASIOOut::IniSection() ) );
}
void setDefault()
{
::ZeroMemory( this, sizeof( *this ) );
structVersion_ = currentConfigVersion;
volumeControler_ = mixerAPI;
deviceIndices_[ 1 ] = terminator;
}
VolumeControler & volumeControler() { return volumeControler_; }
DeviceIndices & deviceIndices () { return deviceIndices_ ; }
BYTE const * indicesBegin() const { return &deviceIndices_[ 0 ]; }
BYTE const * indicesEnd () const;
private:
BYTE structVersion_;
VolumeControler volumeControler_;
DeviceIndices deviceIndices_;
static BYTE const currentConfigVersion = 1;
#if 0 // Disabled until implemented.
DWORD priority_;
unsigned outputSamplingRate_;
BYTE latency_;
BYTE minimumOutputChannels_; // for example for mono to stereo expansion
BYTE maximumOutputChannels_; // for downmix forcing
bool gapless_;
bool directInputMonitor_;
BYTE channelMappings_[ maxSupportedChannels ];
#endif // Disabled until implemented.
};
} // 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.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.