Initial community commit

This commit is contained in:
Jef 2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit fc06254474
16440 changed files with 4239995 additions and 2 deletions

View 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

View 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);
}

View 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

View 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;
}

View 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"

View 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

View 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

View 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>

View 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>

View 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

View 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

View 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);
}

View 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;
}

View 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);
};