Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
16
Src/Plugins/Output/out_wave/api.h
Normal file
16
Src/Plugins/Output/out_wave/api.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef NULLSOFT_API_H
|
||||
#define NULLSOFT_API_H
|
||||
|
||||
#include <api/service/api_service.h>
|
||||
extern api_service *serviceManager;
|
||||
#define WASABI_API_SVC serviceManager
|
||||
|
||||
#include <api/service/waServiceFactory.h>
|
||||
|
||||
#include "../Agave/Language/api_language.h"
|
||||
|
||||
#include <api/application/api_application.h>
|
||||
extern api_application *applicationApi;
|
||||
#define WASABI_API_APP applicationApi
|
||||
|
||||
#endif
|
248
Src/Plugins/Output/out_wave/cnv_pcmwaveout.cpp
Normal file
248
Src/Plugins/Output/out_wave/cnv_pcmwaveout.cpp
Normal file
|
@ -0,0 +1,248 @@
|
|||
#include "cnv_pcmwaveout.h"
|
||||
#include <mmsystem.h>
|
||||
#include "waveout.h"
|
||||
#include "../studio/services/svc_textfeed.h"
|
||||
|
||||
#define FEEDID_DEVICELIST "waveOut:DEVICES"
|
||||
|
||||
static String * devlist;
|
||||
static UINT n_devs;
|
||||
|
||||
#define DEVICE_DEFAULT "(default device)" //trick: use this string for default wave mapper, without querying device names and shit
|
||||
|
||||
_string cfg_dev("Device",DEVICE_DEFAULT);
|
||||
|
||||
|
||||
static void devlist_init()
|
||||
{
|
||||
if (devlist) return;
|
||||
n_devs=waveOutGetNumDevs()+1;
|
||||
UINT n;
|
||||
WAVEOUTCAPS caps;
|
||||
devlist=new String[n_devs];
|
||||
for(n=0;n<n_devs;n++)
|
||||
{
|
||||
if (waveOutGetDevCaps(n-1,&caps,sizeof(caps))==MMSYSERR_NOERROR)
|
||||
{
|
||||
devlist[n]=caps.szPname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TextFeed : public svc_textFeedI {
|
||||
public:
|
||||
TextFeed() {
|
||||
registerFeed(FEEDID_DEVICELIST); // we output shit in <List> objects whose feed param is "DirectSound::DEVICES"
|
||||
}
|
||||
static const char *getServiceName() { return "waveOut TextFeed Service"; }
|
||||
|
||||
protected:
|
||||
virtual void registerCallback(const char *feedid, TextFeedCallback *cb)
|
||||
{
|
||||
if (!STRICMP(feedid,FEEDID_DEVICELIST))
|
||||
{//HACK: nice delayed init - don't query device list before we really need to, for really short loading time
|
||||
static bool inited;
|
||||
if (!inited)
|
||||
{
|
||||
inited=1;
|
||||
|
||||
devlist_init();
|
||||
|
||||
String feed_devlist="";
|
||||
UINT n;
|
||||
for(n=0;n<n_devs;n++)
|
||||
{
|
||||
if (!feed_devlist.isempty()) feed_devlist += ";";
|
||||
feed_devlist+=devlist[n];
|
||||
}
|
||||
sendFeed(FEEDID_DEVICELIST, feed_devlist);
|
||||
if (!strcmp(cfg_dev,DEVICE_DEFAULT)) cfg_dev=devlist[0];
|
||||
}
|
||||
}
|
||||
svc_textFeedI::registerCallback(feedid,cb);
|
||||
}
|
||||
};
|
||||
|
||||
static waServiceTSingle<svc_textFeed, TextFeed> g_feed;
|
||||
|
||||
|
||||
_int cfg_buf_ms("Buffer length (ms)",2000);
|
||||
_int cfg_prebuf("Prebuffer (ms)",0);
|
||||
_bool cfg_vol_enabled("Volume control enabled",1);
|
||||
_bool cfg_vol_alt("Alt volume control method",0);
|
||||
_bool cfg_vol_reset("Reset volume on stop",0);
|
||||
|
||||
class cnv_pcmwaveout: public svc_mediaConverterI {
|
||||
private:
|
||||
WaveOut * pWO;
|
||||
int fmt_sr,fmt_bps,fmt_nch;
|
||||
public:
|
||||
cnv_pcmwaveout()
|
||||
{
|
||||
pWO = 0;
|
||||
fmt_sr = 0;
|
||||
fmt_bps = 0;
|
||||
fmt_nch = 0;
|
||||
}
|
||||
~cnv_pcmwaveout()
|
||||
{
|
||||
if (pWO) delete pWO;
|
||||
}
|
||||
|
||||
static const char *getServiceName() { return "WaveOut Output"; }
|
||||
|
||||
virtual int canConvertFrom(svc_fileReader *reader, const char *name, const char *chunktype) {
|
||||
if(chunktype && !STRICMP(chunktype,"pcm")) return 1;
|
||||
return 0;
|
||||
}
|
||||
virtual const char *getConverterTo() { return "OUTPUT:waveOut"; }
|
||||
|
||||
virtual int getInfos(MediaInfo *infos) {return 0;}
|
||||
|
||||
virtual int processData(MediaInfo *infos, ChunkList *chunk_list, bool *killswitch)
|
||||
{
|
||||
Chunk * c=chunk_list->getChunk("PCM");
|
||||
if (!c) return 0;
|
||||
char * data=(char*)c->getData();
|
||||
int size=c->getSize();
|
||||
if (size<=0) {
|
||||
if (pWO && infos->getData("audio_need_canwrite")) infos->setDataInt("audio_canwrite",pWO->CanWrite(),FALSE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sr,bps,nch;
|
||||
sr=c->getInfo("srate");
|
||||
bps=c->getInfo("bps");
|
||||
nch=c->getInfo("nch");
|
||||
|
||||
if (pWO && (fmt_sr!=sr || fmt_bps!=bps || fmt_nch!=nch))
|
||||
{
|
||||
while(!*killswitch && pWO->GetLatency()>0) Sleep(1);
|
||||
delete pWO;
|
||||
pWO=0;
|
||||
}
|
||||
|
||||
if (*killswitch) return 0;
|
||||
|
||||
|
||||
if (!pWO)
|
||||
{
|
||||
fmt_sr=sr;
|
||||
fmt_bps=bps;
|
||||
fmt_nch=nch;
|
||||
WaveOutConfig cfg;
|
||||
cfg.SetPCM(sr,nch,bps);
|
||||
cfg.SetBuffer(cfg_buf_ms,cfg_prebuf);
|
||||
const char * devname=cfg_dev;
|
||||
if (_stricmp(devname,DEVICE_DEFAULT))
|
||||
{
|
||||
devlist_init();
|
||||
for(UINT n=0;n<n_devs;n++)
|
||||
{
|
||||
if (!_stricmp(devname,devlist[n]))
|
||||
{
|
||||
cfg.SetDevice(n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cfg.SetVolumeSetup(cfg_vol_enabled,cfg_vol_alt,cfg_vol_reset);
|
||||
pWO=WaveOut::Create(&cfg);
|
||||
if (!pWO)
|
||||
{
|
||||
//todo: cfg.GetError() yadda yadda
|
||||
return 0;
|
||||
}
|
||||
pWO->SetVolume(api->core_getVolume(m_coretoken));
|
||||
pWO->SetPan(api->core_getPan(m_coretoken));
|
||||
}
|
||||
|
||||
while(!*killswitch)
|
||||
{
|
||||
int d=pWO->WriteData(data,size);
|
||||
if (d>0)
|
||||
{
|
||||
size-=d;
|
||||
if (size<=0) break;
|
||||
data+=d;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual int getLatency(void) {return pWO ? pWO->GetLatency() : 0;}
|
||||
|
||||
virtual int corecb_onSeeked(int newpos) {if (pWO) pWO->Flush();return 0;}
|
||||
|
||||
|
||||
virtual int corecb_onVolumeChange(int v) {pWO->SetVolume(v);return 0;}
|
||||
virtual int corecb_onPanChange(int v) {pWO->SetPan(v);return 0;}
|
||||
|
||||
virtual int corecb_onAbortCurrentSong() {if (pWO) pWO->Flush();return 0;}
|
||||
virtual int corecb_onPaused() {if (pWO) pWO->Pause(1);return 0;}
|
||||
virtual int corecb_onUnpaused() {if (pWO) pWO->Pause(0);return 0;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static WACNAME wac;
|
||||
WAComponentClient *the = &wac;
|
||||
|
||||
#include "../studio/services/servicei.h"
|
||||
static waServiceT<svc_mediaConverter, cnv_pcmwaveout> waveout;
|
||||
|
||||
// {E91551F2-E1CE-4484-B331-B3BE2B754B52}
|
||||
static const GUID guid =
|
||||
{ 0xe91551f2, 0xe1ce, 0x4484, { 0xb3, 0x31, 0xb3, 0xbe, 0x2b, 0x75, 0x4b, 0x52 } };
|
||||
|
||||
WACNAME::WACNAME() {
|
||||
#ifdef FORTIFY
|
||||
FortifySetName("cnv_pcmwaveout.wac");
|
||||
FortifyEnterScope();
|
||||
#endif
|
||||
registerService(&g_feed);//autoderegistered on shutdown
|
||||
registerService(&waveout);
|
||||
registerSkinFile("Wacs/xml/waveout/waveout-prefs.xml");
|
||||
}
|
||||
|
||||
WACNAME::~WACNAME() {
|
||||
#ifdef FORTIFY
|
||||
FortifyLeaveScope();
|
||||
#endif
|
||||
if (devlist)
|
||||
{
|
||||
delete[] devlist;
|
||||
devlist=0;
|
||||
}
|
||||
n_devs=0;
|
||||
}
|
||||
|
||||
GUID WACNAME::getGUID() {
|
||||
return guid;
|
||||
}
|
||||
|
||||
void WACNAME::onDestroy() {
|
||||
|
||||
}
|
||||
|
||||
void WACNAME::onCreate()
|
||||
{
|
||||
// {EDAA0599-3E43-4eb5-A65D-C0A0484240E7}
|
||||
static const GUID cfg_audio_guid =
|
||||
{ 0xedaa0599, 0x3e43, 0x4eb5, { 0xa6, 0x5d, 0xc0, 0xa0, 0x48, 0x42, 0x40, 0xe7 } };
|
||||
|
||||
api->preferences_registerGroup("waveout", "waveOut", guid, cfg_audio_guid);
|
||||
|
||||
|
||||
|
||||
registerAttribute(&cfg_dev);
|
||||
registerAttribute(&cfg_buf_ms);
|
||||
registerAttribute(&cfg_prebuf);
|
||||
|
||||
registerAttribute(&cfg_vol_enabled);
|
||||
registerAttribute(&cfg_vol_alt);
|
||||
registerAttribute(&cfg_vol_reset);
|
||||
|
||||
|
||||
}
|
37
Src/Plugins/Output/out_wave/cnv_pcmwaveout.h
Normal file
37
Src/Plugins/Output/out_wave/cnv_pcmwaveout.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef _CNV_DS2_H
|
||||
#define _CNV_DS2_H
|
||||
|
||||
#include "../studio/wac.h"
|
||||
#include "../common/rootcomp.h"
|
||||
#include "../attribs/cfgitemi.h"
|
||||
#include "../attribs/attrint.h"
|
||||
#include "../attribs/attrbool.h"
|
||||
#include "../attribs/attrstr.h"
|
||||
|
||||
|
||||
#include "../studio/services/svc_mediaconverter.h"
|
||||
#include "../studio/services/servicei.h"
|
||||
#include "../studio/corecb.h"
|
||||
#include "../studio/wac.h"
|
||||
|
||||
|
||||
#define WACNAME WACcnv_waveout
|
||||
|
||||
class WACNAME : public WAComponentClient {
|
||||
public:
|
||||
WACNAME();
|
||||
virtual ~WACNAME();
|
||||
|
||||
virtual const char *getName() { return "WaveOut Output"; };
|
||||
virtual GUID getGUID();
|
||||
|
||||
virtual void onDestroy();
|
||||
virtual void onCreate();
|
||||
|
||||
virtual int getDisplayComponent() { return FALSE; };
|
||||
|
||||
virtual CfgItem *getCfgInterface(int n) { return this; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
576
Src/Plugins/Output/out_wave/out_wave.cpp
Normal file
576
Src/Plugins/Output/out_wave/out_wave.cpp
Normal file
|
@ -0,0 +1,576 @@
|
|||
#include "out_wave.h"
|
||||
#include "api.h"
|
||||
#include "resource.h"
|
||||
#include "waveout.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
|
||||
#ifdef HAVE_SSRC
|
||||
#include "ssrc\ssrc.h"
|
||||
static Resampler_base * pSSRC;
|
||||
#endif
|
||||
|
||||
static bool gapless_stop;
|
||||
static WaveOut * pWO;
|
||||
static __int64 total_written;
|
||||
static int pos_delta;
|
||||
static UINT canwrite_hack;
|
||||
|
||||
// wasabi based services for localisation support
|
||||
api_service *WASABI_API_SVC = 0;
|
||||
api_language *WASABI_API_LNG = 0;
|
||||
api_application *WASABI_API_APP = 0;
|
||||
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
|
||||
|
||||
void _init();
|
||||
|
||||
//cfg_prebuf now in ms !
|
||||
UINT cfg_dev = 0, cfg_buf_ms = 2000, cfg_prebuf = 200, cfg_trackhack = 200;
|
||||
bool cfg_volume = 1, cfg_altvol = 0, cfg_resetvol = 0;
|
||||
static int fmt_sr, fmt_bps, fmt_nch;
|
||||
|
||||
static int volume = 255, pan = 0;
|
||||
|
||||
|
||||
#ifdef HAVE_SSRC
|
||||
UINT cfg_dither = 1, cfg_resample_freq = 48000, cfg_resample_bps = 1;
|
||||
bool cfg_fast = 1;
|
||||
UINT cfg_pdf = 1;
|
||||
UINT bps_tab[3] = {8, 16, 24};
|
||||
static bool finished, use_finish;
|
||||
|
||||
static UINT resample_freq;
|
||||
static UINT resample_bps;
|
||||
|
||||
static void do_ssrc_create()
|
||||
{
|
||||
pSSRC = SSRC_create(fmt_sr, resample_freq, fmt_bps, resample_bps, fmt_nch, cfg_dither, cfg_pdf, cfg_fast, 0);
|
||||
finished = 0;
|
||||
use_finish = cfg_trackhack == 0 ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void do_cfg(bool s);
|
||||
|
||||
static CRITICAL_SECTION sync; //various funky time consuming stuff going on, better protect ourselves with a critical section here, resampler doesnt have its own one
|
||||
#define SYNC_IN EnterCriticalSection(&sync);
|
||||
#define SYNC_OUT LeaveCriticalSection(&sync);
|
||||
|
||||
|
||||
void Config(HWND);
|
||||
|
||||
int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
|
||||
{
|
||||
MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0};
|
||||
msgbx.lpszText = message;
|
||||
msgbx.lpszCaption = title;
|
||||
msgbx.lpszIcon = MAKEINTRESOURCEW(102);
|
||||
msgbx.hInstance = GetModuleHandle(0);
|
||||
msgbx.dwStyle = MB_USERICON;
|
||||
msgbx.hwndOwner = parent;
|
||||
return MessageBoxIndirectW(&msgbx);
|
||||
}
|
||||
|
||||
void About(HWND hwndParent)
|
||||
{
|
||||
wchar_t message[1024] = {0}, text[1024] = {0};
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_WAVEOUT_OLD,text,1024);
|
||||
wsprintfW(message, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
|
||||
mod.description, __DATE__);
|
||||
DoAboutMessageBox(hwndParent,text,message);
|
||||
}
|
||||
|
||||
static void Init()
|
||||
{
|
||||
if (!IsWindow(mod.hMainWindow))
|
||||
return;
|
||||
|
||||
// loader so that we can get the localisation service api for use
|
||||
WASABI_API_SVC = (api_service*)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
|
||||
if (WASABI_API_SVC == (api_service*)1) WASABI_API_SVC = NULL;
|
||||
if (!WASABI_API_SVC || WASABI_API_SVC == (api_service *)1)
|
||||
return;
|
||||
|
||||
waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID);
|
||||
if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
|
||||
|
||||
sf = WASABI_API_SVC->service_getServiceByGuid(applicationApiServiceGuid);
|
||||
if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface());
|
||||
|
||||
// need to have this initialised before we try to do anything with localisation features
|
||||
WASABI_API_START_LANG(mod.hDllInstance,OutWaveLangGUID);
|
||||
|
||||
static wchar_t szDescription[256];
|
||||
swprintf(szDescription,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_WAVEOUT),OUT_WAVE_VER);
|
||||
mod.description = (char*)szDescription;
|
||||
}
|
||||
|
||||
static int inited;
|
||||
|
||||
static void Quit()
|
||||
{
|
||||
if (inited)
|
||||
{
|
||||
if (pWO)
|
||||
{
|
||||
delete pWO;
|
||||
pWO = 0;
|
||||
}
|
||||
#ifdef HAVE_SSRC
|
||||
if (pSSRC)
|
||||
{
|
||||
delete pSSRC;
|
||||
pSSRC = 0;
|
||||
}
|
||||
#endif
|
||||
do_cfg(1);
|
||||
inited = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_stuff()
|
||||
{
|
||||
canwrite_hack = 0;
|
||||
pos_delta = 0;
|
||||
total_written = 0;
|
||||
gapless_stop = 0;
|
||||
}
|
||||
|
||||
|
||||
void _init()
|
||||
{
|
||||
if (!inited)
|
||||
{
|
||||
inited = 1;
|
||||
do_cfg(0);
|
||||
if (cfg_dev > waveOutGetNumDevs()) cfg_dev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void _write(char * data, int size);
|
||||
|
||||
int Open(int sr, int nch, int bps, int bufferlenms, int prebufferms)
|
||||
{
|
||||
_init();
|
||||
SYNC_IN;
|
||||
|
||||
if (pWO) //"gapless" track change (or someone forgot to close output)
|
||||
{
|
||||
pWO->SetCloseOnStop(0); //turn off self-destruct on out-of-PCM-data
|
||||
if (!pWO->IsClosed()) //has it run out of PCM data or not ? if yes, we can only delete and create new one
|
||||
{
|
||||
if (sr != fmt_sr || nch != fmt_nch || bps != fmt_bps) //tough shit, new pcm format
|
||||
{ //wait-then-close, dont cut previous track
|
||||
#ifdef HAVE_SSRC
|
||||
if (!pSSRC && !finished)
|
||||
{
|
||||
use_finish = 1;
|
||||
_write(0, 0);
|
||||
}
|
||||
#endif
|
||||
while (pWO->GetLatency() > 0) Sleep(1);
|
||||
}
|
||||
else
|
||||
{ //successful gapless track change. yay.
|
||||
reset_stuff();
|
||||
#ifdef HAVE_SSRC
|
||||
if (pSSRC)
|
||||
{
|
||||
if (finished)
|
||||
{
|
||||
delete pSSRC;
|
||||
do_ssrc_create();
|
||||
}
|
||||
else use_finish = cfg_trackhack == 0 ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
int r = pWO->GetMaxLatency();
|
||||
SYNC_OUT;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_SSRC
|
||||
if (pSSRC)
|
||||
{
|
||||
delete pSSRC;
|
||||
pSSRC = 0;
|
||||
}
|
||||
#endif
|
||||
delete pWO;
|
||||
}
|
||||
|
||||
WaveOutConfig * cfg = new WaveOutConfig; //avoid crazy crt references with creating cfg on stack, keep TINY_DLL config happy
|
||||
cfg->SetBuffer(cfg_buf_ms, cfg_prebuf);
|
||||
cfg->SetDevice(cfg_dev);
|
||||
cfg->SetVolumeSetup(cfg_volume, cfg_altvol, cfg_resetvol);
|
||||
|
||||
fmt_sr = sr;
|
||||
fmt_nch = nch;
|
||||
fmt_bps = bps;
|
||||
|
||||
#ifdef HAVE_SSRC
|
||||
resample_freq = cfg_resample_freq;
|
||||
if (resample_freq < 6000) resample_freq = 6000;
|
||||
else if (resample_freq > 192000) resample_freq = 192000;
|
||||
resample_bps = bps_tab[cfg_resample_bps];
|
||||
|
||||
if (fmt_sr == (int)resample_freq && fmt_bps == (int)resample_bps)
|
||||
{
|
||||
cfg->SetPCM(fmt_sr, fmt_nch, fmt_bps);
|
||||
}
|
||||
else
|
||||
{
|
||||
do_ssrc_create();
|
||||
}
|
||||
|
||||
|
||||
if (!pSSRC) cfg->SetPCM(sr, nch, bps);
|
||||
else cfg->SetPCM(resample_freq, nch, resample_bps);
|
||||
|
||||
#else//!HAVE_SSRC
|
||||
cfg->SetPCM(sr, nch, bps);
|
||||
#endif
|
||||
|
||||
pWO = WaveOut::Create(cfg);
|
||||
if (!pWO)
|
||||
{
|
||||
const WCHAR *error = cfg->GetError();
|
||||
if (error)
|
||||
{
|
||||
WCHAR err[128] = {0}, temp[128] = {0};
|
||||
swprintf(err,128,WASABI_API_LNGSTRINGW(IDS_ERROR),WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_WAVEOUT_OLD,temp,128));
|
||||
MessageBoxW(mod.hMainWindow, error, err, MB_ICONERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reset_stuff();
|
||||
}
|
||||
|
||||
delete cfg;
|
||||
if (pWO)
|
||||
{
|
||||
int r = pWO->GetMaxLatency();
|
||||
SYNC_OUT;
|
||||
return r;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_SSRC
|
||||
if (pSSRC)
|
||||
{
|
||||
delete pSSRC;
|
||||
pSSRC = 0;
|
||||
}
|
||||
#endif
|
||||
SYNC_OUT;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSRC
|
||||
static UINT ssrc_extra_latency;
|
||||
|
||||
static void _write(char * data, int size)
|
||||
{
|
||||
if (pWO)
|
||||
{
|
||||
if (pSSRC)
|
||||
{
|
||||
if (!finished)
|
||||
{
|
||||
UINT nsiz;
|
||||
if (data > 0) pSSRC->Write(data, (UINT)size);
|
||||
else if (use_finish)
|
||||
{
|
||||
finished = 1;
|
||||
pSSRC->Finish();
|
||||
}
|
||||
data = (char*)pSSRC->GetBuffer(&nsiz);
|
||||
UINT nsiz1 = nsiz;
|
||||
while (nsiz) //ugly
|
||||
{
|
||||
int wr = pWO->WriteData(data, nsiz);
|
||||
if (wr > 0)
|
||||
{
|
||||
data += wr;
|
||||
nsiz -= wr;
|
||||
if (!nsiz) break;
|
||||
}
|
||||
ssrc_extra_latency = MulDiv(nsiz, 1000, resample_freq * fmt_nch * (resample_bps >> 3));
|
||||
SYNC_OUT;
|
||||
Sleep(1); //shouldnt happen anymore since canwrite works correctly
|
||||
SYNC_IN;
|
||||
}
|
||||
pSSRC->Read(nsiz1);
|
||||
ssrc_extra_latency = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pWO->WriteData(data, size);
|
||||
}
|
||||
total_written += size / ((fmt_bps >> 3) * fmt_nch);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int Write(char *data, int size)
|
||||
{
|
||||
SYNC_IN;
|
||||
gapless_stop = 0;
|
||||
canwrite_hack = 0;
|
||||
// decrypt, if necessary
|
||||
|
||||
#ifdef HAVE_SSRC
|
||||
_write(data, size);
|
||||
#else
|
||||
if (pWO)
|
||||
{
|
||||
pWO->WriteData(data, size);
|
||||
total_written += size / ((fmt_bps >> 3) * fmt_nch);
|
||||
}
|
||||
#endif
|
||||
SYNC_OUT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
SYNC_IN;
|
||||
if (pWO)
|
||||
{
|
||||
if (gapless_stop) //end-of-song stop, dont close yet, use gapless hacks
|
||||
{
|
||||
pWO->SetCloseOnStop(1); //will self-destruct when out of PCM data to play, has no more than 200ms in buffer
|
||||
}
|
||||
else //regular stop (user action)
|
||||
{
|
||||
delete pWO;
|
||||
pWO = 0;
|
||||
#ifdef HAVE_SSRC
|
||||
if (pSSRC)
|
||||
{
|
||||
delete pSSRC;
|
||||
pSSRC = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
SYNC_OUT;
|
||||
}
|
||||
|
||||
int CanWrite()
|
||||
{
|
||||
int r;
|
||||
SYNC_IN;
|
||||
if (pWO)
|
||||
{
|
||||
#ifdef HAVE_SSRC
|
||||
if (pSSRC)
|
||||
{
|
||||
r = MulDiv(pWO->CanWrite() - (resample_bps >> 3) * fmt_nch, fmt_bps * fmt_sr, resample_freq * resample_bps) - pSSRC->GetDataInInbuf();
|
||||
if (r < 0) r = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
r = pWO->CanWrite();
|
||||
|
||||
if (++canwrite_hack > 2) pWO->ForcePlay(); //avoid constant-small-canwrite-while-still-prebuffering snafu
|
||||
}
|
||||
else r = 0;
|
||||
SYNC_OUT;
|
||||
return r;
|
||||
}
|
||||
|
||||
int IsPlaying()
|
||||
{ //this is called only when decoding is done unless some input plugin dev is really nuts about making useless calls
|
||||
SYNC_IN;
|
||||
if (pWO)
|
||||
{
|
||||
#ifdef HAVE_SSRC
|
||||
_write(0, 0);
|
||||
#endif
|
||||
pWO->ForcePlay(); //evil short files: make sure that output has started
|
||||
if ((UINT)pWO->GetLatency() > cfg_trackhack) //cfg_trackhack used to be 200ms constant
|
||||
{ //just for the case some input plugin dev is actually nuts about making useless calls or user presses stop/prev/next when decoding is finished, we don't activate gapless_stop here
|
||||
gapless_stop = 0;
|
||||
SYNC_OUT;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{ //ok so looks like we're really near the end-of-track, time to do gapless track switch mumbo-jumbo
|
||||
gapless_stop = 1;
|
||||
SYNC_OUT;
|
||||
return 0; //hack: make the input plugin think that we're done with current track
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SYNC_OUT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Pause(int new_state)
|
||||
{
|
||||
int rv;
|
||||
SYNC_IN;
|
||||
if (pWO)
|
||||
{
|
||||
rv = pWO->IsPaused();
|
||||
pWO->Pause(new_state);
|
||||
}
|
||||
else rv = 0;
|
||||
SYNC_OUT;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
void Flush(int pos)
|
||||
{
|
||||
SYNC_IN;
|
||||
if (pWO) pWO->Flush();
|
||||
#ifdef HAVE_SSRC
|
||||
if (pSSRC)
|
||||
{
|
||||
delete pSSRC;
|
||||
do_ssrc_create();
|
||||
}
|
||||
#endif
|
||||
reset_stuff();
|
||||
pos_delta = pos;
|
||||
SYNC_OUT;
|
||||
}
|
||||
|
||||
void SetVolume(int v)
|
||||
{
|
||||
SYNC_IN;
|
||||
if (v != -666)
|
||||
{
|
||||
volume = v;
|
||||
}
|
||||
if (pWO) pWO->SetVolume(volume);
|
||||
SYNC_OUT;
|
||||
}
|
||||
|
||||
void SetPan(int p)
|
||||
{
|
||||
SYNC_IN;
|
||||
pan = p;
|
||||
if (pWO) pWO->SetPan(pan);
|
||||
SYNC_OUT;
|
||||
}
|
||||
|
||||
int get_written_time() //this ignores high 32bits of total_written
|
||||
{
|
||||
return MulDiv((int)total_written, 1000, fmt_sr);
|
||||
}
|
||||
|
||||
int GetWrittenTime()
|
||||
{
|
||||
int r;
|
||||
SYNC_IN;
|
||||
r = pWO ? pos_delta + get_written_time() : 0;
|
||||
SYNC_OUT;
|
||||
return r;
|
||||
}
|
||||
|
||||
int GetOutputTime()
|
||||
{
|
||||
int r;
|
||||
SYNC_IN;
|
||||
r = pWO ? (pos_delta + get_written_time()) - pWO->GetLatency() : 0;
|
||||
#ifdef HAVE_SSRC
|
||||
if (pSSRC)
|
||||
r -= ssrc_extra_latency ? ssrc_extra_latency : pSSRC->GetLatency();
|
||||
#endif
|
||||
SYNC_OUT;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int Validate(int dummy1, int dummy2, short key, char dummy4);
|
||||
static int NewWrite(int len, char *buf);
|
||||
|
||||
Out_Module mod =
|
||||
{
|
||||
OUT_VER_U,
|
||||
#ifdef HAVE_SSRC
|
||||
NAME" SSRC",
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
1471482036, //could put different one for SSRC config but i'm too lazy and this shit doesnt seem used anymore anyway
|
||||
0, 0,
|
||||
Config,
|
||||
About,
|
||||
|
||||
Init,
|
||||
Quit,
|
||||
Open,
|
||||
|
||||
Close,
|
||||
|
||||
Write,
|
||||
|
||||
CanWrite,
|
||||
|
||||
IsPlaying,
|
||||
|
||||
Pause,
|
||||
|
||||
SetVolume,
|
||||
SetPan,
|
||||
|
||||
Flush,
|
||||
|
||||
GetOutputTime,
|
||||
GetWrittenTime,
|
||||
};
|
||||
|
||||
HMODULE thisMod=0;
|
||||
Out_Module *(*waveGetter)(HINSTANCE) = 0;
|
||||
HMODULE inWMDLL = 0;
|
||||
BOOL APIENTRY DllMain(HANDLE hMod, DWORD r, void*)
|
||||
{
|
||||
if (r == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
thisMod=(HMODULE)hMod;
|
||||
DisableThreadLibraryCalls((HMODULE)hMod);
|
||||
InitializeCriticalSection(&sync);
|
||||
}
|
||||
else if (r == DLL_PROCESS_DETACH)
|
||||
{
|
||||
DeleteCriticalSection(&sync);
|
||||
|
||||
if (inWMDLL)
|
||||
{
|
||||
FreeLibrary(inWMDLL); // potentially unsafe, we'll see ...
|
||||
inWMDLL = 0;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
__declspec( dllexport ) Out_Module * winampGetOutModule()
|
||||
{
|
||||
inWMDLL = GetModuleHandleW(L"in_wm.dll");
|
||||
if (inWMDLL)
|
||||
{
|
||||
waveGetter = (Out_Module * (*)(HINSTANCE))GetProcAddress(inWMDLL, "GetWave");
|
||||
if (waveGetter)
|
||||
return waveGetter(thisMod);
|
||||
}
|
||||
|
||||
return &mod;
|
||||
}
|
||||
}
|
||||
|
||||
bool get_waveout_state(char * z)
|
||||
{
|
||||
if (pWO) return pWO->PrintState(z);
|
||||
else return 0;
|
||||
}
|
7
Src/Plugins/Output/out_wave/out_wave.h
Normal file
7
Src/Plugins/Output/out_wave/out_wave.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#define STRICT
|
||||
#include <windows.h>
|
||||
#include "../Winamp/out.h"
|
||||
|
||||
extern Out_Module mod;
|
||||
|
||||
#define OUT_WAVE_VER L"2.22"
|
158
Src/Plugins/Output/out_wave/out_wave.rc
Normal file
158
Src/Plugins/Output/out_wave/out_wave.rc
Normal file
|
@ -0,0 +1,158 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""version.rc2""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_WAVE_CONFIG DIALOGEX 0, 0, 311, 169
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x0
|
||||
BEGIN
|
||||
LTEXT "Device:",IDC_STATIC,4,8,26,8
|
||||
COMBOBOX IDC_DEV,34,6,160,82,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
GROUPBOX "Buffering",IDC_STATIC,4,24,190,76
|
||||
LTEXT "Buffer length:",IDC_STATIC,20,34,46,8
|
||||
CONTROL "Slider1",IDC_BUFFER,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,66,33,120,12
|
||||
CTEXT "z",IDC_BUF_DISP,70,44,112,8
|
||||
LTEXT "Prebuffer:",IDC_STATIC,34,56,32,8
|
||||
CONTROL "Slider1",IDC_PREBUFFER_1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,66,55,120,12
|
||||
CTEXT "z",IDC_PREBUF_DISP_1,70,66,112,8
|
||||
LTEXT "Buffer-ahead\non track change:",IDC_STATIC,12,76,56,18
|
||||
CONTROL "Slider1",IDC_PREBUFFER_2,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,66,78,120,12
|
||||
CTEXT "z",IDC_PREBUF_DISP_2,70,88,112,8
|
||||
GROUPBOX "Volume Control",IDC_STATIC,4,104,190,46
|
||||
CONTROL "Enable",IDC_VOL_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,118,38,10
|
||||
CONTROL "Alt. setting method (slow)",IDC_ALT_VOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,92,118,94,10
|
||||
CONTROL "Reset to original value on stop",IDC_VOL_RESET,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,134,111,10
|
||||
GROUPBOX "Status Display",IDC_STATIC,198,4,108,121
|
||||
LTEXT "",IDC_STATE,204,15,96,105
|
||||
LTEXT "Note: Most settings take full effect after restarting playback",IDC_BLAH,4,155,194,8,WS_DISABLED
|
||||
PUSHBUTTON "Reset to defaults",IDC_RESET,199,131,108,13
|
||||
DEFPUSHBUTTON "OK",IDOK,199,150,52,13
|
||||
PUSHBUTTON "Cancel",IDCANCEL,255,150,52,13
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_WAVE_CONFIG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 307
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 163
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_NULLSOFT_WAVEOUT "Nullsoft WaveOut Output v%s"
|
||||
65535 "{004A91D9-CCD6-44e5-973A-4B7045C4662B}"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_NULLSOFT_WAVEOUT_OLD "Nullsoft WaveOut Output"
|
||||
IDS_NOT_ACTIVE "not active"
|
||||
IDS_UNKNOWN_MMSYSTEM_ERROR "Unknown MMSYSTEM error."
|
||||
IDS_UNSUPPORTED_PCM_FORMAT
|
||||
"Unsupported PCM format (%u Hz, %u bits per sample, %u channels). Please change format settings in input plug-in configuration or change output device in waveOut plug-in configuration."
|
||||
IDS_ANOTHER_PROGRAM_IS_USING_THE_SOUNDCARD
|
||||
"Another program is using your soundcard. Please change output device (in waveOut plug-in configuration), switch to DirectSound output (in Winamp preferences / plug-ins / output) or get a soundcard which can play multiple streams."
|
||||
IDS_NO_SOUND_DEVICES_FOUND
|
||||
"No sound devices found. Please buy a soundcard first (or install proper drivers if you think that you have one)."
|
||||
IDS_INTERNAL_DRIVER_ERROR
|
||||
"Internal driver error; please reboot your computer."
|
||||
IDS_REINSTALL_SOUNDCARD_DRIVERS "Please reinstall soundcard drivers."
|
||||
IDS_ERROR_CODE_WINDOWS_ERROR_MESSAGE
|
||||
"%s\n\nError code: %u\nWindows error message: \n""%s"""
|
||||
IDS_ERROR_CODE "%s\nError code: %u"
|
||||
IDS_DATA_FORMAT "Data format: \n %u Hz\n %u bits per sample\n %u channel(s)\n"
|
||||
IDS_BUFFER_STATUS "Buffer status:\n %u bytes allocated\n %u blocks queued\n"
|
||||
IDS_LATENCY "Latency: %u ms\n"
|
||||
IDS_PREFS_TITLE "%s Settings"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_ERROR "%s Error"
|
||||
IDS_WAVE_U_MS "%u ms"
|
||||
IDS_ABOUT_TEXT "%s\n© 2005-2023 Winamp SA\n© 2001-2002 Peter Pawlowski\t\nBuild date: %hs"
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
#include "version.rc2"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
30
Src/Plugins/Output/out_wave/out_wave.sln
Normal file
30
Src/Plugins/Output/out_wave/out_wave.sln
Normal file
|
@ -0,0 +1,30 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29424.173
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "out_wave", "out_wave.vcxproj", "{D63584C4-6233-4469-AD94-4B9E0BDD15B7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D63584C4-6233-4469-AD94-4B9E0BDD15B7}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D63584C4-6233-4469-AD94-4B9E0BDD15B7}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D63584C4-6233-4469-AD94-4B9E0BDD15B7}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D63584C4-6233-4469-AD94-4B9E0BDD15B7}.Release|Win32.Build.0 = Release|Win32
|
||||
{D63584C4-6233-4469-AD94-4B9E0BDD15B7}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D63584C4-6233-4469-AD94-4B9E0BDD15B7}.Debug|x64.Build.0 = Debug|x64
|
||||
{D63584C4-6233-4469-AD94-4B9E0BDD15B7}.Release|x64.ActiveCfg = Release|x64
|
||||
{D63584C4-6233-4469-AD94-4B9E0BDD15B7}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E2F57101-9F64-4677-A8F2-3F76DCA10FD4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
284
Src/Plugins/Output/out_wave/out_wave.vcxproj
Normal file
284
Src/Plugins/Output/out_wave/out_wave.vcxproj
Normal file
|
@ -0,0 +1,284 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{D63584C4-6233-4469-AD94-4B9E0BDD15B7}</ProjectGuid>
|
||||
<RootNamespace>out_wave</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnableManifest>false</VcpkgEnableManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OUT_wave_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>odbc32.lib;odbccp32.lib;dsound.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;OUT_wave_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>odbc32.lib;odbccp32.lib;dsound.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OUT_wave_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>odbc32.lib;odbccp32.lib;dsound.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<DelayLoadDLLs>winmm.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;OUT_wave_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0409</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>odbc32.lib;odbccp32.lib;dsound.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<DelayLoadDLLs>winmm.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api.h" />
|
||||
<ClInclude Include="out_wave.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="waveout.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="out_wave.cpp" />
|
||||
<ClCompile Include="wa2_config.cpp" />
|
||||
<ClCompile Include="waveout.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="out_wave.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
|
||||
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
44
Src/Plugins/Output/out_wave/out_wave.vcxproj.filters
Normal file
44
Src/Plugins/Output/out_wave/out_wave.vcxproj.filters
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="out_wave.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="wa2_config.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="waveout.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="waveout.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="out_wave.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{864917ef-d719-4565-9427-bd2c884cedff}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ressource Files">
|
||||
<UniqueIdentifier>{784d9708-92ec-4f11-b552-29c92528bf31}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{c5280fb1-feed-44f9-8a38-2ba42a13bb94}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="out_wave.rc">
|
||||
<Filter>Ressource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
60
Src/Plugins/Output/out_wave/resource.h
Normal file
60
Src/Plugins/Output/out_wave/resource.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by out_wave.rc
|
||||
//
|
||||
#define IDS_NULLSOFT_WAVEOUT_OLD 0
|
||||
#define IDS_NOT_ACTIVE 1
|
||||
#define IDS_UNKNOWN_MMSYSTEM_ERROR 2
|
||||
#define IDC_RESET 3
|
||||
#define IDS_UNSUPPORTED_PCM_FORMAT 3
|
||||
#define IDS_ANOTHER_PROGRAM_IS_USING_THE_SOUNDCARD 4
|
||||
#define IDS_NO_SOUND_DEVICES_FOUND 5
|
||||
#define IDS_INTERNAL_DRIVER_ERROR 6
|
||||
#define IDS_REINSTALL_SOUNDCARD_DRIVERS 7
|
||||
#define IDS_ERROR_CODE_WINDOWS_ERROR_MESSAGE 8
|
||||
#define IDS_ERROR_CODE 9
|
||||
#define IDS_DATA_FORMAT 10
|
||||
#define IDS_BUFFER_STATUS 11
|
||||
#define IDS_LATENCY 12
|
||||
#define IDS_ABOUT 13
|
||||
#define IDS_PREFS_TITLE 15
|
||||
#define IDS_ERROR 16
|
||||
#define IDS_WAVE_U_MS 17
|
||||
#define IDS_ABOUT_STRING 18
|
||||
#define IDS_ABOUT_TEXT 18
|
||||
#define IDD_CONFIG 300
|
||||
#define IDD_WAVE_CONFIG 300
|
||||
#define IDC_GAPLESS 1000
|
||||
#define IDC_BUF_SIZE 1001
|
||||
#define IDC_SPIN1 1002
|
||||
#define IDC_PRIMARY 1003
|
||||
#define IDC_PREBUF_SIZE 1003
|
||||
#define IDC_DEV 1004
|
||||
#define IDC_HACK 1005
|
||||
#define IDC_EXCLUSIVE 1006
|
||||
#define IDC_PREBUFFER 1007
|
||||
#define IDC_SPIN2 1008
|
||||
#define IDC_VOL_ENABLE 1009
|
||||
#define IDC_ALT_VOL 1010
|
||||
#define IDC_VOL_RESET 1011
|
||||
#define IDC_PREB_TEXT 1012
|
||||
#define IDC_STATE 1013
|
||||
#define IDC_PREBUFFER_1 1014
|
||||
#define IDC_PREBUFFER_2 1015
|
||||
#define IDC_PREBUF_DISP_1 1016
|
||||
#define IDC_PREBUF_DISP_2 1017
|
||||
#define IDC_BLAH 1018
|
||||
#define IDC_BUFFER 1020
|
||||
#define IDC_BUF_DISP 1021
|
||||
#define IDS_NULLSOFT_WAVEOUT 65534
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 301
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1019
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
39
Src/Plugins/Output/out_wave/version.rc2
Normal file
39
Src/Plugins/Output/out_wave/version.rc2
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
#include "../../../Winamp/buildType.h"
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,22,0,0
|
||||
PRODUCTVERSION WINAMP_PRODUCTVER
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Winamp SA"
|
||||
VALUE "FileDescription", "Winamp Output Plug-in"
|
||||
VALUE "FileVersion", "2,22,0,0"
|
||||
VALUE "InternalName", "Nullsoft Wave Output"
|
||||
VALUE "LegalCopyright", "Copyright © 2005-2023 Winamp SA"
|
||||
VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
|
||||
VALUE "OriginalFilename", "out_wave.dll"
|
||||
VALUE "ProductName", "Winamp"
|
||||
VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
267
Src/Plugins/Output/out_wave/wa2_config.cpp
Normal file
267
Src/Plugins/Output/out_wave/wa2_config.cpp
Normal file
|
@ -0,0 +1,267 @@
|
|||
#include "out_wave.h"
|
||||
#include "api.h"
|
||||
#include <commctrl.h>
|
||||
#include "resource.h"
|
||||
#include <math.h>
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#pragma intrinsic(log)
|
||||
|
||||
#ifndef _WIN64
|
||||
//__inline long int lrint (double flt)
|
||||
//{
|
||||
// int intgr;
|
||||
//
|
||||
// _asm
|
||||
// {
|
||||
// fld flt
|
||||
// fistp intgr
|
||||
// }
|
||||
//
|
||||
// return intgr;
|
||||
//}
|
||||
#else
|
||||
//__inline long int lrint (double flt)
|
||||
//{
|
||||
// return (int)flt;
|
||||
//}
|
||||
#endif
|
||||
|
||||
|
||||
#pragma warning(disable:4800)
|
||||
|
||||
extern Out_Module mod;
|
||||
extern UINT cfg_buf_ms,cfg_dev,cfg_prebuf;
|
||||
extern bool cfg_volume,cfg_altvol,cfg_resetvol;
|
||||
extern UINT cfg_trackhack;
|
||||
|
||||
bool get_waveout_state(char * z) throw();
|
||||
|
||||
void _init();
|
||||
|
||||
#define BUFFER_SCALE 4000.0
|
||||
|
||||
static UINT cur_buffer;
|
||||
|
||||
static UINT get_buffer(HWND wnd)
|
||||
{
|
||||
if (cur_buffer) return cur_buffer;
|
||||
|
||||
//0-BUFFER_SCALE => 200-20000
|
||||
LRESULT z=SendDlgItemMessage(wnd,IDC_BUFFER,TBM_GETPOS,0,0);
|
||||
//return cur_buffer=lrint( 0.5 + 200.0*pow(100.0,((double)z)/BUFFER_SCALE) );
|
||||
|
||||
}
|
||||
|
||||
#define LOG100 4.6051701859880913680359829093687
|
||||
static void set_buffer(HWND wnd,UINT b)
|
||||
{
|
||||
cur_buffer=b;
|
||||
SendDlgItemMessage(wnd,IDC_BUFFER,TBM_SETPOS,1,lrint( 0.5 + BUFFER_SCALE * log( (double)b/200.0 ) / LOG100 /* / log( 100.0 )*/ ));
|
||||
}
|
||||
|
||||
static void update_prebuf_1(HWND wnd)
|
||||
{
|
||||
WCHAR zz[128] = { 0 };
|
||||
wsprintf(zz, WASABI_API_LNGSTRINGW(IDS_WAVE_U_MS), SendDlgItemMessage(wnd, IDC_PREBUFFER_1, TBM_GETPOS, 0, 0));
|
||||
SetDlgItemText(wnd,IDC_PREBUF_DISP_1,zz);
|
||||
}
|
||||
|
||||
static void update_prebuf_2(HWND wnd)
|
||||
{
|
||||
WCHAR zz[128] = { 0 };
|
||||
wsprintf(zz, WASABI_API_LNGSTRINGW(IDS_WAVE_U_MS), SendDlgItemMessage(wnd, IDC_PREBUFFER_2, TBM_GETPOS, 0, 0));
|
||||
SetDlgItemText(wnd,IDC_PREBUF_DISP_2,zz);
|
||||
}
|
||||
|
||||
static void update_prebuf_range(HWND wnd)
|
||||
{
|
||||
UINT max=get_buffer(wnd);
|
||||
if (max>0x7FFF) max=0x7FFF;
|
||||
SendDlgItemMessage(wnd,IDC_PREBUFFER_1,TBM_SETRANGE,1,MAKELONG(0,max));
|
||||
SendDlgItemMessage(wnd,IDC_PREBUFFER_2,TBM_SETRANGE,1,MAKELONG(0,max));
|
||||
}
|
||||
|
||||
static void update_buf(HWND wnd)
|
||||
{
|
||||
WCHAR zz[128] = { 0 };
|
||||
wsprintf(zz, WASABI_API_LNGSTRINGW(IDS_WAVE_U_MS), get_buffer(wnd));
|
||||
SetDlgItemText(wnd,IDC_BUF_DISP,zz);
|
||||
}
|
||||
|
||||
static INT_PTR WINAPI CfgProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
|
||||
{
|
||||
switch(msg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
wchar_t title[128] = {0}, temp[128] = {0};
|
||||
swprintf(title,128,WASABI_API_LNGSTRINGW(IDS_PREFS_TITLE),WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_WAVEOUT_OLD,temp,128));
|
||||
SetWindowTextW(wnd,title);
|
||||
|
||||
SendDlgItemMessage(wnd,IDC_VOL_ENABLE,BM_SETCHECK,(long)cfg_volume,0);
|
||||
SendDlgItemMessage(wnd,IDC_ALT_VOL,BM_SETCHECK,(long)cfg_altvol,0);
|
||||
SendDlgItemMessage(wnd,IDC_VOL_RESET,BM_SETCHECK,(long)cfg_resetvol,0);
|
||||
|
||||
{
|
||||
int dev;
|
||||
HWND w=GetDlgItem(wnd,IDC_DEV);
|
||||
UINT max=waveOutGetNumDevs();
|
||||
WAVEOUTCAPS caps;
|
||||
for(dev=-1;dev<(int)max;dev++)
|
||||
{
|
||||
if (waveOutGetDevCaps((UINT)dev,&caps,sizeof(caps)) == MMSYSERR_NOERROR)
|
||||
SendMessage(w,CB_ADDSTRING,0,(LPARAM)caps.szPname);
|
||||
}
|
||||
SendMessage(w,CB_SETCURSEL,cfg_dev,0);
|
||||
}
|
||||
|
||||
SendDlgItemMessage(wnd,IDC_BUFFER,TBM_SETRANGE,0,MAKELONG(0,(int)BUFFER_SCALE));
|
||||
set_buffer(wnd,cfg_buf_ms);
|
||||
update_prebuf_range(wnd);
|
||||
SendDlgItemMessage(wnd,IDC_PREBUFFER_1,TBM_SETPOS,1,cfg_prebuf);
|
||||
SendDlgItemMessage(wnd,IDC_PREBUFFER_2,TBM_SETPOS,1,cfg_trackhack);
|
||||
update_prebuf_1(wnd);
|
||||
update_prebuf_2(wnd);
|
||||
update_buf(wnd);
|
||||
|
||||
SetTimer(wnd,1,500,0);
|
||||
CfgProc(wnd,WM_TIMER,0,0);
|
||||
}
|
||||
return 1;
|
||||
case WM_COMMAND:
|
||||
switch(wp)
|
||||
{
|
||||
case IDC_RESET:
|
||||
SendDlgItemMessage(wnd,IDC_VOL_ENABLE,BM_SETCHECK,1,0);
|
||||
SendDlgItemMessage(wnd,IDC_ALT_VOL,BM_SETCHECK,0,0);
|
||||
SendDlgItemMessage(wnd,IDC_VOL_RESET,BM_SETCHECK,0,0);
|
||||
|
||||
SendDlgItemMessage(wnd,IDC_DEV,CB_SETCURSEL,0,0);
|
||||
|
||||
set_buffer(wnd,2000);
|
||||
update_prebuf_range(wnd);
|
||||
SendDlgItemMessage(wnd,IDC_PREBUFFER_1,TBM_SETPOS,1,200);
|
||||
SendDlgItemMessage(wnd,IDC_PREBUFFER_2,TBM_SETPOS,1,200);
|
||||
update_prebuf_1(wnd);
|
||||
update_prebuf_2(wnd);
|
||||
update_buf(wnd);
|
||||
break;
|
||||
case IDOK:
|
||||
KillTimer(wnd,1);
|
||||
cfg_dev=(UINT)SendDlgItemMessage(wnd,IDC_DEV,CB_GETCURSEL,0,0);
|
||||
cfg_buf_ms=get_buffer(wnd);
|
||||
cfg_prebuf= (UINT)SendDlgItemMessage(wnd,IDC_PREBUFFER_1,TBM_GETPOS,0,0);
|
||||
cfg_trackhack=(UINT)SendDlgItemMessage(wnd,IDC_PREBUFFER_2,TBM_GETPOS,0,0);
|
||||
cfg_volume=(bool)SendDlgItemMessage(wnd,IDC_VOL_ENABLE,BM_GETCHECK,0,0);
|
||||
cfg_altvol=(bool)SendDlgItemMessage(wnd,IDC_ALT_VOL,BM_GETCHECK,0,0);
|
||||
cfg_resetvol=(bool)SendDlgItemMessage(wnd,IDC_VOL_RESET,BM_GETCHECK,0,0);
|
||||
EndDialog(wnd,1);
|
||||
break;
|
||||
case IDCANCEL:
|
||||
KillTimer(wnd,1);
|
||||
EndDialog(wnd,0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WM_HSCROLL:
|
||||
switch(GetWindowLong((HWND)lp,GWL_ID))
|
||||
{
|
||||
case IDC_BUFFER:
|
||||
cur_buffer=0;
|
||||
update_buf(wnd);
|
||||
update_prebuf_range(wnd);
|
||||
update_prebuf_1(wnd);
|
||||
update_prebuf_2(wnd);
|
||||
break;
|
||||
case IDC_PREBUFFER_1:
|
||||
update_prebuf_1(wnd);
|
||||
break;
|
||||
case IDC_PREBUFFER_2:
|
||||
update_prebuf_2(wnd);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WM_TIMER:
|
||||
{
|
||||
char poo[512] = {0};
|
||||
bool z=get_waveout_state(poo);
|
||||
SetDlgItemTextA(wnd,IDC_STATE,z ? poo : WASABI_API_LNGSTRING(IDS_NOT_ACTIVE));
|
||||
EnableWindow(GetDlgItem(wnd,IDC_BLAH),z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
const int controls[] =
|
||||
{
|
||||
IDC_BUFFER,
|
||||
IDC_PREBUFFER_1,
|
||||
IDC_PREBUFFER_2,
|
||||
};
|
||||
if (FALSE != WASABI_API_APP->DirectMouseWheel_ProcessDialogMessage(wnd, msg, wp, lp, controls, ARRAYSIZE(controls)))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Config(HWND w)
|
||||
{
|
||||
_init();
|
||||
WASABI_API_DIALOGBOXW(IDD_CONFIG,w,CfgProc);
|
||||
}
|
||||
|
||||
static char _dllfile[MAX_PATH];
|
||||
static char * dllfile;
|
||||
char *inifile=0;
|
||||
|
||||
static UINT atoui(char* s)
|
||||
{
|
||||
int ret=0;
|
||||
while(s && *s>='0' && *s<='9') {ret=10*ret+(*s-'0');s++;}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _do_var(unsigned int v,char* n,bool s)
|
||||
{
|
||||
if (s)
|
||||
{
|
||||
char tmp[2*sizeof(unsigned int) + 1] = {0}; // max 32 bit unsigned int == 4 294 967 296 == 10 digits, 11 if signed
|
||||
wsprintfA(tmp,"%u",v);
|
||||
WritePrivateProfileStringA(dllfile,n,tmp,inifile);
|
||||
return v;
|
||||
}
|
||||
else
|
||||
{
|
||||
char tmp[64],tmp_s[2*sizeof(unsigned int) + 1] = {0};
|
||||
wsprintfA(tmp_s,"%u",v);
|
||||
GetPrivateProfileStringA(dllfile,n,tmp_s,tmp,64,inifile);
|
||||
return atoui(tmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define do_var(V) {V=_do_var(V,#V,s);}
|
||||
|
||||
void do_cfg(bool s)
|
||||
{
|
||||
if (!inifile)
|
||||
inifile =(char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE);
|
||||
|
||||
if (!dllfile)
|
||||
{
|
||||
GetModuleFileNameA(mod.hDllInstance,_dllfile,sizeof(_dllfile));
|
||||
dllfile=strrchr(_dllfile,'\\');
|
||||
if (!dllfile) dllfile=_dllfile;
|
||||
else dllfile++;
|
||||
char * p=strchr(dllfile,'.');
|
||||
if (p) *p=0;
|
||||
}
|
||||
|
||||
do_var(cfg_buf_ms);
|
||||
do_var(cfg_dev);
|
||||
do_var(cfg_volume);
|
||||
do_var(cfg_altvol);
|
||||
do_var(cfg_resetvol);
|
||||
do_var(cfg_prebuf);
|
||||
do_var(cfg_trackhack);
|
||||
}
|
617
Src/Plugins/Output/out_wave/waveout.cpp
Normal file
617
Src/Plugins/Output/out_wave/waveout.cpp
Normal file
|
@ -0,0 +1,617 @@
|
|||
#define STRICT
|
||||
#include <windows.h>
|
||||
#include "out_wave.h"
|
||||
#include "api.h"
|
||||
#include "waveout.h"
|
||||
#include "resource.h"
|
||||
#include <mmreg.h>
|
||||
#pragma intrinsic(memset, memcpy)
|
||||
#define SYNC_IN EnterCriticalSection(&sync);
|
||||
#define SYNC_OUT LeaveCriticalSection(&sync);
|
||||
|
||||
#define GET_TIME timeGetTime()
|
||||
|
||||
static const int kMaxChannelsToMask = 8;
|
||||
static const unsigned int kChannelsToMask[kMaxChannelsToMask + 1] = {
|
||||
0,
|
||||
// 1 = Mono
|
||||
SPEAKER_FRONT_CENTER,
|
||||
// 2 = Stereo
|
||||
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
|
||||
// 3 = Stereo + Center
|
||||
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER,
|
||||
// 4 = Quad
|
||||
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
|
||||
SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT,
|
||||
// 5 = 5.0
|
||||
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER |
|
||||
SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT,
|
||||
// 6 = 5.1
|
||||
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
|
||||
SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY |
|
||||
SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT,
|
||||
// 7 = 6.1
|
||||
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
|
||||
SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY |
|
||||
SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT |
|
||||
SPEAKER_BACK_CENTER,
|
||||
// 8 = 7.1
|
||||
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
|
||||
SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY |
|
||||
SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT |
|
||||
SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT
|
||||
// TODO(fbarchard): Add additional masks for 7.2 and beyond.
|
||||
};
|
||||
|
||||
WaveOut::~WaveOut()
|
||||
{
|
||||
if (hThread)
|
||||
{
|
||||
SYNC_IN
|
||||
die=1;
|
||||
|
||||
SYNC_OUT;
|
||||
SetEvent(hEvent);
|
||||
WaitForSingleObject(hThread,INFINITE);
|
||||
}
|
||||
if (hEvent) CloseHandle(hEvent);
|
||||
DeleteCriticalSection(&sync);
|
||||
killwaveout();
|
||||
if (buffer) LocalFree(buffer);
|
||||
hdr_free_list(hdrs);
|
||||
hdr_free_list(hdrs_free);
|
||||
}
|
||||
|
||||
DWORD WINAPI WaveOut::ThreadProc(WaveOut * p)
|
||||
{
|
||||
p->thread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WaveOut::thread()
|
||||
{
|
||||
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);
|
||||
while(hWo)
|
||||
{
|
||||
WaitForSingleObject(hEvent,INFINITE);
|
||||
SYNC_IN;
|
||||
if (die) {SYNC_OUT; break;}
|
||||
|
||||
|
||||
for(HEADER * h=hdrs;h;)
|
||||
{
|
||||
if (h->hdr.dwFlags&WHDR_DONE)
|
||||
{
|
||||
n_playing--;
|
||||
buf_size_used-=h->hdr.dwBufferLength;
|
||||
last_time=GET_TIME;
|
||||
waveOutUnprepareHeader(hWo,&h->hdr,sizeof(WAVEHDR));
|
||||
HEADER* f=h;
|
||||
h=h->next;
|
||||
hdr_free(f);
|
||||
}
|
||||
else h=h->next;
|
||||
}
|
||||
|
||||
|
||||
/* if (needflush)
|
||||
{
|
||||
flush();
|
||||
if (!paused) waveOutRestart(hWo);
|
||||
needflush=0;
|
||||
}*/
|
||||
|
||||
if (!paused && newpause)
|
||||
{
|
||||
paused=1;
|
||||
if (hWo) waveOutPause(hWo);
|
||||
p_time=GET_TIME-last_time;
|
||||
}
|
||||
|
||||
if (paused && !newpause)
|
||||
{
|
||||
paused=0;
|
||||
if (hWo) waveOutRestart(hWo);
|
||||
last_time = GET_TIME-p_time;
|
||||
}
|
||||
|
||||
|
||||
UINT limit;
|
||||
if (needplay) limit=0;
|
||||
else if (!n_playing)
|
||||
{
|
||||
limit=prebuf;
|
||||
if (limit<avgblock) limit=avgblock;
|
||||
}
|
||||
else if (buf_size_used<(buf_size>>1) || n_playing<3) limit=minblock;//skipping warning, blow whatever we have
|
||||
else limit=avgblock;//just a block
|
||||
|
||||
while(data_written>limit)
|
||||
{
|
||||
UINT d=(data_written > maxblock) ? maxblock : data_written;
|
||||
d-=d%fmt_align;
|
||||
if (!d) break;
|
||||
data_written-=d;
|
||||
buf_size_used+=d;
|
||||
|
||||
HEADER * h=hdr_alloc();
|
||||
h->hdr.dwBytesRecorded=h->hdr.dwBufferLength=d;
|
||||
h->hdr.lpData=buffer+write_ptr;
|
||||
write_ptr+=d;
|
||||
if (write_ptr>buf_size)
|
||||
{
|
||||
write_ptr-=buf_size;
|
||||
memcpy(buffer+buf_size,buffer,write_ptr);
|
||||
}
|
||||
|
||||
n_playing++;
|
||||
if (use_altvol) do_altvol(h->hdr.lpData,d);
|
||||
waveOutPrepareHeader(hWo,&h->hdr,sizeof(WAVEHDR));
|
||||
waveOutWrite(hWo,&h->hdr,sizeof(WAVEHDR));//important: make all waveOutWrite calls from *our* thread to keep win2k/xp happy
|
||||
if (n_playing==1) last_time=GET_TIME;
|
||||
#if 0
|
||||
{
|
||||
char t[128] = {0};
|
||||
wsprintf(t,"block size: %u, limit used %u\n", d,limit);
|
||||
OutputDebugString(t);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
needplay=0;
|
||||
|
||||
if (!data_written && !n_playing && closeonstop) killwaveout();
|
||||
|
||||
SYNC_OUT;
|
||||
}
|
||||
killwaveout();
|
||||
}
|
||||
|
||||
int WaveOut::WriteData(const void * _data,UINT size)
|
||||
{
|
||||
|
||||
SYNC_IN;
|
||||
if (paused) //$!#@!
|
||||
{
|
||||
SYNC_OUT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char * data=(const char*)_data;
|
||||
|
||||
{
|
||||
UINT cw=CanWrite();
|
||||
if (size>cw)
|
||||
{
|
||||
size=cw;
|
||||
}
|
||||
}
|
||||
|
||||
UINT written=0;
|
||||
while(size>0)
|
||||
{
|
||||
UINT ptr=(data_written + write_ptr)%buf_size;
|
||||
UINT delta=size;
|
||||
if (ptr+delta>buf_size) delta=buf_size-ptr;
|
||||
memcpy(buffer+ptr,data,delta);
|
||||
data+=delta;
|
||||
size-=delta;
|
||||
written+=delta;
|
||||
data_written+=delta;
|
||||
}
|
||||
SYNC_OUT; // sync out first to prevent a ping-pong condition
|
||||
if (written) SetEvent(hEvent);//new shit, time to update
|
||||
return (int)written;
|
||||
}
|
||||
|
||||
void WaveOut::flush()//in sync
|
||||
{
|
||||
waveOutReset(hWo);
|
||||
|
||||
while(hdrs)
|
||||
{
|
||||
if (hdrs->hdr.dwFlags & WHDR_PREPARED)
|
||||
{
|
||||
waveOutUnprepareHeader(hWo,&hdrs->hdr,sizeof(WAVEHDR));
|
||||
}
|
||||
hdr_free(hdrs);
|
||||
}
|
||||
reset_shit();
|
||||
}
|
||||
|
||||
void WaveOut::Flush()
|
||||
{
|
||||
/* SYNC_IN;
|
||||
needflush=1;
|
||||
SetEvent(hEvent);
|
||||
SYNC_OUT;
|
||||
while(needflush) Sleep(1);*/
|
||||
SYNC_IN;//no need to sync this to our thread
|
||||
flush();
|
||||
if (!paused) waveOutRestart(hWo);
|
||||
SYNC_OUT;
|
||||
}
|
||||
|
||||
|
||||
void WaveOut::ForcePlay()
|
||||
{
|
||||
SYNC_IN;//needs to be done in our thread
|
||||
if (!paused) {needplay=1;SetEvent(hEvent);}
|
||||
SYNC_OUT;
|
||||
// while(needplay) Sleep(1);
|
||||
}
|
||||
|
||||
WaveOut::WaveOut()
|
||||
{
|
||||
#ifndef TINY_DLL //TINY_DLL has its own new operator with zeroinit
|
||||
memset(&hWo,0,sizeof(*this)-((char*)&hWo-(char*)this));
|
||||
#endif
|
||||
myvol=-666;
|
||||
mypan=-666;
|
||||
InitializeCriticalSection(&sync);
|
||||
}
|
||||
|
||||
int WaveOut::open(WaveOutConfig * cfg)
|
||||
{
|
||||
fmt_sr = cfg->sr;
|
||||
fmt_bps = cfg->bps;
|
||||
fmt_nch = cfg->nch;
|
||||
fmt_align = ( fmt_bps >> 3 ) * fmt_nch;
|
||||
fmt_mul = fmt_align * fmt_sr;
|
||||
|
||||
use_volume=cfg->use_volume;
|
||||
use_altvol=cfg->use_altvol;
|
||||
use_resetvol=cfg->resetvol;
|
||||
|
||||
if (!use_volume)
|
||||
use_altvol=use_resetvol=0;
|
||||
else if (use_altvol)
|
||||
{
|
||||
use_resetvol=0;
|
||||
use_volume=0;
|
||||
}
|
||||
|
||||
WAVEFORMATEX wfx=
|
||||
{
|
||||
WAVE_FORMAT_PCM,
|
||||
(WORD)fmt_nch,
|
||||
fmt_sr,
|
||||
fmt_mul,
|
||||
(WORD)fmt_align,
|
||||
(WORD)fmt_bps,
|
||||
0
|
||||
};
|
||||
|
||||
if (!hEvent) hEvent=CreateEvent(0,0,0,0);
|
||||
|
||||
WAVEFORMATEXTENSIBLE wfxe = { 0 };
|
||||
wfxe.Format = wfx;
|
||||
wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
wfxe.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
|
||||
wfxe.Format.nChannels = fmt_nch;
|
||||
wfxe.Format.nBlockAlign = (wfxe.Format.nChannels *
|
||||
wfxe.Format.wBitsPerSample) / 8;
|
||||
wfxe.Format.nAvgBytesPerSec = wfxe.Format.nBlockAlign *
|
||||
wfxe.Format.nSamplesPerSec;
|
||||
wfxe.Samples.wReserved = 0;
|
||||
if (fmt_nch > kMaxChannelsToMask) {
|
||||
wfxe.dwChannelMask = kChannelsToMask[kMaxChannelsToMask];
|
||||
}
|
||||
else {
|
||||
wfxe.dwChannelMask = kChannelsToMask[fmt_nch];
|
||||
}
|
||||
wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
wfxe.Samples.wValidBitsPerSample = wfxe.Format.wBitsPerSample;
|
||||
MMRESULT mr = waveOutOpen(&hWo, (UINT)(cfg->dev-1), reinterpret_cast<LPCWAVEFORMATEX>(&wfxe), (DWORD_PTR)hEvent, 0, CALLBACK_EVENT);
|
||||
|
||||
|
||||
if (mr)
|
||||
{
|
||||
WCHAR full_error[1024], * _fe = full_error;
|
||||
WCHAR poo[MAXERRORLENGTH] = { 0 };
|
||||
WCHAR* e = poo;
|
||||
|
||||
if (waveOutGetErrorTextW(mr,poo,MAXERRORLENGTH)!=MMSYSERR_NOERROR)
|
||||
{
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN_MMSYSTEM_ERROR, poo, MAXERRORLENGTH);
|
||||
}
|
||||
char * e2=0, e2Buf[1024] = {0};
|
||||
switch(mr)
|
||||
{
|
||||
case 32:
|
||||
wsprintfW(_fe, WASABI_API_LNGSTRINGW(IDS_UNSUPPORTED_PCM_FORMAT), fmt_sr, fmt_bps, fmt_nch);
|
||||
//fixme: some broken drivers blow mmsystem032 for no reason, with "standard" 44khz/16bps/stereo, need better error message when pcm format isnt weird
|
||||
while(_fe && *_fe) _fe++;
|
||||
e2="";
|
||||
break;
|
||||
case 4:
|
||||
e2=WASABI_API_LNGSTRING_BUF(IDS_ANOTHER_PROGRAM_IS_USING_THE_SOUNDCARD,e2Buf,1024);
|
||||
break;
|
||||
case 2:
|
||||
e2=WASABI_API_LNGSTRING_BUF(IDS_NO_SOUND_DEVICES_FOUND,e2Buf,1024);
|
||||
break;
|
||||
case 20:
|
||||
e2=WASABI_API_LNGSTRING_BUF(IDS_INTERNAL_DRIVER_ERROR,e2Buf,1024);
|
||||
break;
|
||||
case 7:
|
||||
e2=WASABI_API_LNGSTRING_BUF(IDS_REINSTALL_SOUNDCARD_DRIVERS,e2Buf,1024);
|
||||
break;
|
||||
//case 8: fixme
|
||||
}
|
||||
if (e2)
|
||||
{
|
||||
wsprintfW(_fe, WASABI_API_LNGSTRINGW(IDS_ERROR_CODE_WINDOWS_ERROR_MESSAGE), e2, mr, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsprintfW(_fe, WASABI_API_LNGSTRINGW(IDS_ERROR_CODE), e, mr);
|
||||
}
|
||||
cfg->SetError(full_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
buf_size=MulDiv(cfg->buf_ms,fmt_mul,1000);
|
||||
|
||||
maxblock = 0x10000;
|
||||
minblock = 0x100;
|
||||
avgblock = buf_size>>4;
|
||||
if (maxblock>buf_size>>2) maxblock=buf_size>>2;
|
||||
if (avgblock>maxblock) avgblock=maxblock;
|
||||
if (maxblock<minblock) maxblock=minblock;
|
||||
if (avgblock<minblock) avgblock=minblock;
|
||||
|
||||
|
||||
buffer = (char*)LocalAlloc(LPTR,buf_size+maxblock);//extra space at the end of the buffer
|
||||
|
||||
prebuf = MulDiv(cfg->prebuf,fmt_mul,1000);
|
||||
if (prebuf>buf_size) prebuf=buf_size;
|
||||
|
||||
n_playing=0;
|
||||
|
||||
waveOutRestart(hWo);
|
||||
reset_shit();
|
||||
|
||||
|
||||
if (use_resetvol) waveOutGetVolume(hWo,&orgvol);
|
||||
|
||||
if (myvol!=-666 || mypan!=-666) update_vol();
|
||||
|
||||
|
||||
{
|
||||
DWORD dw;
|
||||
hThread=CreateThread(0,0,(LPTHREAD_START_ROUTINE)ThreadProc,this,0,&dw);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WaveOut::GetLatency(void)
|
||||
{
|
||||
SYNC_IN;
|
||||
int r=0;
|
||||
if (hWo)
|
||||
{
|
||||
r=MulDiv(buf_size_used+data_written,1000,(fmt_bps>>3)*fmt_nch*fmt_sr);
|
||||
if (paused) r-=p_time;
|
||||
else if (n_playing) r-=GET_TIME-last_time;
|
||||
if (r<0) r=0;
|
||||
}
|
||||
SYNC_OUT;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void WaveOut::SetVolume(int v)
|
||||
{
|
||||
SYNC_IN;
|
||||
myvol=v;
|
||||
update_vol();
|
||||
SYNC_OUT;
|
||||
}
|
||||
|
||||
void WaveOut::SetPan(int p)
|
||||
{
|
||||
SYNC_IN;
|
||||
mypan=p;
|
||||
update_vol();
|
||||
SYNC_OUT;
|
||||
}
|
||||
|
||||
void WaveOut::update_vol()
|
||||
{
|
||||
if (hWo && use_volume)
|
||||
{
|
||||
if (myvol==-666) myvol=255;
|
||||
if (mypan==-666) mypan=0;
|
||||
DWORD left,right;
|
||||
left=right=myvol|(myvol<<8);
|
||||
if (mypan<0) right=(right*(128+mypan))>>7;
|
||||
else if (mypan>0) left=(left*(128-mypan))>>7;
|
||||
waveOutSetVolume(hWo,left|(right<<16));
|
||||
}
|
||||
}
|
||||
|
||||
void WaveOut::reset_shit()
|
||||
{
|
||||
n_playing=0;
|
||||
data_written=0;
|
||||
buf_size_used=0;
|
||||
last_time=0;
|
||||
//last_time=GET_TIME;
|
||||
}
|
||||
|
||||
void WaveOut::Pause(int s)
|
||||
{
|
||||
SYNC_IN;
|
||||
newpause=s?1:0;//needs to be done in our thread to keep stupid win2k/xp happy
|
||||
|
||||
SYNC_OUT;
|
||||
SetEvent(hEvent);
|
||||
while(paused!=newpause) Sleep(1);
|
||||
}
|
||||
|
||||
void WaveOut::killwaveout()
|
||||
{
|
||||
if (hWo)
|
||||
{
|
||||
flush();
|
||||
if (use_resetvol) waveOutSetVolume(hWo,orgvol);
|
||||
waveOutClose(hWo);
|
||||
hWo=0;
|
||||
}
|
||||
}
|
||||
|
||||
int WaveOut::CanWrite()
|
||||
{
|
||||
SYNC_IN;
|
||||
int rv=paused ? 0 : buf_size-buf_size_used-data_written;
|
||||
SYNC_OUT;
|
||||
return rv;
|
||||
}
|
||||
|
||||
WaveOut * WaveOut::Create(WaveOutConfig * cfg)
|
||||
{
|
||||
WaveOut * w=new WaveOut;
|
||||
if (w->open(cfg)<=0)
|
||||
{
|
||||
delete w;
|
||||
w=0;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
WaveOut::HEADER * WaveOut::hdr_alloc()
|
||||
{
|
||||
HEADER * r;
|
||||
if (hdrs_free)
|
||||
{
|
||||
r=hdrs_free;
|
||||
hdrs_free=hdrs_free->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
r=new HEADER;
|
||||
}
|
||||
r->next=hdrs;
|
||||
hdrs=r;
|
||||
memset(&r->hdr,0,sizeof(WAVEHDR));
|
||||
return r;
|
||||
}
|
||||
|
||||
void WaveOut::hdr_free(HEADER * h)
|
||||
{
|
||||
HEADER ** p=&hdrs;
|
||||
while(p && *p)
|
||||
{
|
||||
if (*p==h)
|
||||
{
|
||||
*p = (*p)->next;
|
||||
break;
|
||||
}
|
||||
else p=&(*p)->next;
|
||||
}
|
||||
|
||||
h->next=hdrs_free;
|
||||
hdrs_free=h;
|
||||
}
|
||||
|
||||
void WaveOut::hdr_free_list(HEADER * h)
|
||||
{
|
||||
while(h)
|
||||
{
|
||||
HEADER * t=h->next;
|
||||
delete h;
|
||||
h=t;
|
||||
}
|
||||
}
|
||||
|
||||
bool WaveOut::PrintState(char * z)
|
||||
{
|
||||
bool rv;
|
||||
SYNC_IN;
|
||||
if (!hWo) rv=0;
|
||||
else
|
||||
{
|
||||
rv=1;
|
||||
wsprintfA(z,WASABI_API_LNGSTRING(IDS_DATA_FORMAT),fmt_sr,fmt_bps,fmt_nch);
|
||||
while(z && *z) z++;
|
||||
wsprintfA(z,WASABI_API_LNGSTRING(IDS_BUFFER_STATUS),buf_size,n_playing);
|
||||
while(z && *z) z++;
|
||||
wsprintfA(z,WASABI_API_LNGSTRING(IDS_LATENCY),GetLatency());
|
||||
// while(z && *z) z++;
|
||||
// wsprintf(z,"Data written: %u KB",MulDiv((int)total_written,(fmt_bps>>3)*fmt_nch,1024));
|
||||
}
|
||||
SYNC_OUT;
|
||||
return rv;
|
||||
}
|
||||
|
||||
void WaveOutConfig::SetError(const WCHAR * x)
|
||||
{
|
||||
error=(WCHAR*)LocalAlloc(LPTR,lstrlenW(x+1));
|
||||
lstrcpyW(error,x);
|
||||
}
|
||||
|
||||
void WaveOut::do_altvol_i(char * ptr,UINT max,UINT start,UINT d,int vol)
|
||||
{
|
||||
UINT p=start*(fmt_bps>>3);
|
||||
while(p<max)
|
||||
{
|
||||
void * z=ptr+p;
|
||||
switch(fmt_bps)
|
||||
{
|
||||
case 8:
|
||||
*(BYTE*)z=0x80^(BYTE)MulDiv(0x80^*(BYTE*)z,vol,255);
|
||||
break;
|
||||
case 16:
|
||||
*(short*)z=(short)MulDiv(*(short*)z,vol,255);
|
||||
break;
|
||||
case 24:
|
||||
{
|
||||
long l=0;
|
||||
memcpy(&l,z,3);
|
||||
if (l&0x800000) l|=0xFF000000;
|
||||
l=MulDiv(l,vol,255);
|
||||
memcpy(z,&l,3);
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
*(long*)z=MulDiv(*(long*)z,vol,255);
|
||||
break;
|
||||
}
|
||||
p+=d*(fmt_bps>>3);
|
||||
}
|
||||
}
|
||||
|
||||
void WaveOut::do_altvol(char * ptr,UINT s)
|
||||
{
|
||||
int mixvol=(myvol==-666) ? 255 : myvol;
|
||||
int mixpan=(mypan==-666) ? 0 : mypan;
|
||||
if (mixvol==255 && (fmt_nch!=2 || mixpan==0)) return;
|
||||
if (fmt_nch==2)
|
||||
{
|
||||
int rv=mixvol,lv=mixvol;
|
||||
if (mixpan<0)
|
||||
{//-128..0
|
||||
rv=MulDiv(rv,mixpan+128,128);
|
||||
}
|
||||
else if (mixpan>0)
|
||||
{
|
||||
lv=MulDiv(rv,128-mixpan,128);
|
||||
}
|
||||
do_altvol_i(ptr,s,0,2,lv);
|
||||
do_altvol_i(ptr,s,1,2,rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
do_altvol_i(ptr,s,0,1,mixvol);
|
||||
}
|
||||
}
|
||||
|
||||
bool WaveOut::IsClosed()
|
||||
{
|
||||
SYNC_IN;
|
||||
bool rv=hWo ? 0 : 1;
|
||||
SYNC_OUT;
|
||||
return rv;
|
||||
}
|
125
Src/Plugins/Output/out_wave/waveout.h
Normal file
125
Src/Plugins/Output/out_wave/waveout.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
simple waveout class.
|
||||
usage:
|
||||
create the object
|
||||
write PCM data using WriteData(); WriteData() returns number of bytes successfully written; CanWrite() returns amout of bytes you can write at given point of time
|
||||
ForcePlay after writing last data block to ensure that all your PCM data gets queued to waveout
|
||||
wait for GetLatency() to become 0 to ensure that playback is finished
|
||||
delete the object
|
||||
*/
|
||||
|
||||
|
||||
class WaveOutConfig
|
||||
{
|
||||
friend class WaveOut;
|
||||
private:
|
||||
UINT sr,nch,bps,buf_ms,dev,prebuf;
|
||||
WCHAR* error;
|
||||
void SetError(const WCHAR* x);
|
||||
bool use_volume,use_altvol,resetvol;
|
||||
public:
|
||||
WaveOutConfig()
|
||||
{
|
||||
error=0;
|
||||
sr=44100;
|
||||
nch=2;
|
||||
bps=16;
|
||||
buf_ms=2000;
|
||||
dev=0;
|
||||
prebuf=200;
|
||||
use_volume=1;
|
||||
use_altvol=0;
|
||||
resetvol=0;
|
||||
}
|
||||
void SetPCM(UINT _sr,UINT _nch,UINT _bps) {sr=_sr;nch=_nch;bps=_bps;}
|
||||
void SetBuffer(UINT _buf,UINT _prebuf) {buf_ms=_buf;prebuf=_prebuf;}
|
||||
void SetDevice(UINT d) {dev=d;}
|
||||
void SetVolumeSetup(bool enabled,bool alt,bool _reset) {use_volume = enabled;use_altvol=alt;resetvol=_reset;}
|
||||
~WaveOutConfig()
|
||||
{
|
||||
if (error) LocalFree(error);
|
||||
}
|
||||
|
||||
//call these after attempting to create WaveOut
|
||||
const WCHAR* GetError() {return error;}
|
||||
|
||||
};
|
||||
|
||||
class WaveOut{
|
||||
public:
|
||||
static WaveOut * Create(WaveOutConfig * cfg);
|
||||
|
||||
~WaveOut();
|
||||
|
||||
int WriteData(const void * ptr,UINT siz);
|
||||
|
||||
int GetLatency(void);
|
||||
|
||||
void Flush();
|
||||
|
||||
|
||||
void SetVolume(int v);
|
||||
void SetPan(int p);
|
||||
void Pause(int s);
|
||||
void ForcePlay();
|
||||
int CanWrite();
|
||||
int IsPaused() {return paused?1:0;}
|
||||
UINT GetMaxLatency() {return MulDiv(buf_size,1000,fmt_mul);}
|
||||
bool PrintState(char * z);
|
||||
|
||||
//for gapless mode
|
||||
void SetCloseOnStop(bool b) {closeonstop=b;}
|
||||
bool IsClosed();
|
||||
|
||||
private:
|
||||
WaveOut();
|
||||
|
||||
typedef struct tagHEADER
|
||||
{
|
||||
tagHEADER * next;
|
||||
WAVEHDR hdr;
|
||||
} HEADER;
|
||||
HEADER * hdr_alloc();
|
||||
void hdr_free(HEADER * h);
|
||||
static void hdr_free_list(HEADER * h);
|
||||
|
||||
HWAVEOUT hWo;
|
||||
HANDLE hThread;
|
||||
HANDLE hEvent;
|
||||
CRITICAL_SECTION sync;
|
||||
HEADER *hdrs,*hdrs_free;
|
||||
UINT fmt_bps,fmt_nch,fmt_sr,fmt_mul,fmt_align;//,fmt_chan;
|
||||
char * buffer;
|
||||
UINT buf_size,buf_size_used;
|
||||
UINT data_written,write_ptr;
|
||||
UINT minblock,maxblock,avgblock;
|
||||
DWORD last_time;
|
||||
DWORD p_time;
|
||||
UINT prebuf;
|
||||
|
||||
UINT n_playing;
|
||||
UINT cur_block;
|
||||
bool paused,needplay;
|
||||
bool die;
|
||||
bool use_volume,use_altvol,use_resetvol;
|
||||
bool newpause;//,needflush;
|
||||
bool closeonstop;
|
||||
int myvol,mypan;
|
||||
DWORD orgvol;
|
||||
|
||||
|
||||
|
||||
|
||||
void killwaveout();
|
||||
void flush();
|
||||
void update_vol();
|
||||
void advance_block();
|
||||
|
||||
void reset_shit();
|
||||
void thread();
|
||||
void init();
|
||||
int open(WaveOutConfig * cfg);
|
||||
void do_altvol(char * ptr,UINT s);
|
||||
void do_altvol_i(char * ptr,UINT max,UINT start,UINT d,int vol);
|
||||
static DWORD WINAPI ThreadProc(WaveOut * p);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue