winamp/Src/Plugins/Output/out_ds/ds2.h

237 lines
5.9 KiB
C++

#ifndef _DS2_H
#define _DS2_H
#ifndef STRICT
#define STRICT
#endif
#include <windows.h>
#include <mmsystem.h>
#include <dsound.h>
#include "ds_main.h"
#include "Config.h"
#include "SoundBlockList.h"
#include "DevEnum.h"
#include "VolCtrl.h"
class CriticalSection : public CRITICAL_SECTION
{
public:
inline void Enter() {EnterCriticalSection(this);}
inline void Leave() {LeaveCriticalSection(this);}
CriticalSection() {InitializeCriticalSection(this);}
~CriticalSection() {DeleteCriticalSection(this);}
//BOOL TryEnter() {return TryEnterCriticalSection(this);}
};
typedef struct
{
UINT sr,bps,nch;
UINT buf_size_bytes,buf_size_ms;
UINT pos_play,pos_write,latency,latency_ms;
UINT lock_count;
UINT underruns;
size_t bytes_async;
__int64 bytes_written,bytes_played;
double vol_left,vol_right;
GUID current_device;
bool have_primary_buffer;
bool paused;
DWORD dscaps_flags;
DWORD dscaps_flags_primary;
} DS2_REALTIME_STAT;
class DS2
{
private:
DS2(DS2config * cfg);
SoundBlockList BlockList;
UINT LockCount;
UINT Underruns;
bool DoLock();
public:
~DS2();
int WriteData(void * data,UINT size,bool *killswitch);//returns 1 on success and 0 on failure
int WriteDataNow(void * data,UINT size);//sleep-less version, writes CanWrite() of bytes immediately, returns amount of data written
int ForceWriteData(void * data,UINT size);//sleep-less force-write all the data w/o sleep/canwrite (async buffer has no size limit), use with caution
/*
how to use writedata shit
a) just WriteData(), will sleep until its done
b) WriteDataNow() until we're done (writes as much data as possible at the moment, without sleep)
c) ForceWriteData() (evil!), then sleep while CanWrite()<0
*/
void StartNewStream();
UINT GetLatency();
void _inline Release() {delete this;}//obsolete
void Pause(int new_state);
void SetVolume(double);
inline void SetVolume_Int(int i) {SetVolume((double)i/255.0);}
void SetPan(double);
inline void SetPan_Int(int i) {SetPan((double)i/128.0);}
void Flush();//causes problems with some um.. drivers
int CanWrite();//can be negative !!!!!!! (eg. after ForceWriteData)
inline UINT BufferStatusPercent() {return MulDiv(data_buffered+(UINT)BlockList.DataSize(),buf_size,100);}
void ForcePlay();
void KillEndGap();
#ifdef DS2_HAVE_FADES
void FadePause(UINT time);
void FadeAndForget(UINT time);
void Fade(UINT time,double destvol);
inline void Fade_Int(UINT time,int destvol) {Fade(time,(double)destvol/255.0);}
void FadeX(UINT time,double destvol);//actual fade time depends on volume difference
inline void FadeX_Int(UINT time,int destvol) {FadeX(time,(double)destvol/255.0);}
#endif
void WaitFor(DS2 * prev,UINT fadeout=0);
//gapless mode stuff
void SetCloseOnStop(bool b);
bool IsClosed();
private:
#ifdef _DEBUG
DWORD serial;
UINT sync_n;
#endif
int Open(DS2config * cfg);
DS2 * next;
DS2 * wait;
UINT prebuf;
DWORD flags;
enum
{
FLAG_UPDATED=1,
FLAG_WAITED=1<<1,
FLAG_NEED_PLAY_NOW=1<<2,
FLAG_DIE_ON_STOP=1<<3,
FLAG_CLOSE_ON_STOP=1<<4,
FLAG_PAUSED=1<<5,
FLAG_PLAYING=1<<6,
// FLAG_UNDERRUNNING=1<<7,
FLAG_USE_CPU_MNGMNT=1<<8,
FLAG_FADEPAUSE=1<<9,
FLAG_FADEPAUSING=1<<10,
FLAG_STARTSIL=1<<11,
FLAG_SWMIXED=1<<12,
};
IDirectSoundBuffer * pDSB;
IDirectSound * myDS;
UINT fmt_nch,fmt_bps,fmt_sr,fmt_mul;
UINT buf_size,clear_size;
__int64 last_nonsil,pos_delta,pos_delta2;
inline __int64 GetCurPos() {return data_written-data_buffered;}
__int64 GetSafeWrite();
__int64 data_written;
UINT data_buffered;
UINT silence_buffered;
UINT bytes2ms(UINT bytes);
UINT ms2bytes(UINT ms);
#ifdef DS2_HAVE_FADES
DsVolCtrl VolCtrl;
double fadepause_orgvol;
UINT fadepause_time;
UINT waitfade;
#else
class DsVolCtrl
{
private:
double CurVol,CurPan;
public:
DsVolCtrl() {CurVol=1;CurPan=0;}
inline void SetTime(__int64) {}
inline void SetFade(__int64,double) {}
inline void SetFadeVol(__int64,double,double) {}
inline void SetFadePan(__int64,double,double) {}
inline void SetVolume(double v) {CurVol=v;}
inline void SetPan(double p) {CurPan=p;}
// inline __int64 RelFade(__int64 max,double destvol) {return 0;}
void Apply(IDirectSoundBuffer * pDSB);
inline bool Fading() {return 0;}
// inline double GetCurVol() {return CurVol;}
// inline double GetDestVol() {return CurVol;}
inline void Reset() {}
};
DsVolCtrl VolCtrl;
#endif
void SetVolumeI(double);
void SetPanI(int _pan);
void _setvol();
void _setpan();
void update_pos();
void ds_stop();
void ds_kill();
bool Update();
void reset_vars();
void do_reset_vars();
int silence_delta;
void test_silence(char * buf,int len,int * first,int* last);
static DWORD WINAPI ThreadFunc(void*);
UINT _inline _align() {return (fmt_bps>>3)*fmt_nch;}
UINT _inline _align_var(UINT var) {return var-(var%_align());}
static void SYNC_IN();
static void SYNC_OUT();
typedef HRESULT (WINAPI *tDirectSoundCreate)( const GUID * lpGuid, LPDIRECTSOUND * ppDS, IUnknown FAR * pUnkOuter );
static tDirectSoundCreate pDirectSoundCreate;
static IDirectSound * pDS;
public:
static void Init();//init is OBSOLETE
static void Quit(bool wait=0);//must be called on exit, NOT from DllMain, its ok to call it if init never happened
static DS2 * Create(DS2config * cfg);
static bool InitDLL();//used internally
static HRESULT myDirectSoundCreate(const GUID * g,IDirectSound ** out);
static void SetTotalTime(__int64);
static __int64 GetTotalTime();
static UINT InstanceCount();
void GetRealtimeStat(DS2_REALTIME_STAT * stat);
static bool GetRealtimeStatStatic(DS2_REALTIME_STAT * stat);
__int64 GetOutputTime();
#ifdef DS2_HAVE_DEVICES
static bool TryGetDevCaps(const GUID *g,LPDSCAPS pCaps,DWORD * speakercfg=0);//for current device
typedef HRESULT (WINAPI *tDirectSoundEnumerate)(LPDSENUMCALLBACK lpDSEnumCallback,LPVOID lpContext);
static tDirectSoundEnumerate pDirectSoundEnumerate;
static GUID GetCurDev();
#endif
#ifdef DS2_HAVE_PITCH
void SetPitch(double p);
#endif
};
#endif