mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
612 lines
No EOL
13 KiB
C++
612 lines
No EOL
13 KiB
C++
#include "../Agave/Language/api_language.h"
|
|
#include "main.h"
|
|
#include <math.h>
|
|
#include "resource.h"
|
|
#include "../Winamp/in2.h"
|
|
#include "../Winamp/wa_ipc.h"
|
|
|
|
extern In_Module mod;
|
|
void get_temp_file(char* fn)
|
|
{
|
|
static char tmp_path[MAX_PATH];
|
|
if (!tmp_path[0]) GetTempPathA(MAX_PATH,tmp_path);
|
|
static DWORD num;
|
|
if (num==0) num=GetTickCount();
|
|
wsprintfA(fn,"%sasdf%x.tmp",tmp_path,num++);
|
|
}
|
|
|
|
void file2title(const char* f,string& t)
|
|
{
|
|
const char* p1=strrchr(f,'\\'),*p2=strrchr(f,':'),*p3=strrchr(f,'/');
|
|
if (p2>p1) p1=p2;
|
|
if (p3>p1) p1=p3;
|
|
if (p1) p1++;
|
|
else p1=(char*)f;
|
|
t=p1;
|
|
p1=strrchr(t,'.');
|
|
if (p1) t.truncate(p1-(const char*)t);
|
|
}
|
|
|
|
static char* exts[]={"MID","MIDI","RMI","KAR","HMP","HMI","XMI","MSS","MUS","CMF","GMD","MIDS","MIZ","HMZ"};
|
|
#define N_EXTS tabsize(exts)
|
|
static char is_def[N_EXTS]={1,1,1,1,0,0,0,0,0,0,0,0,1,0};
|
|
|
|
static int get_def_exts()
|
|
{
|
|
int ret=0;
|
|
int n;
|
|
for(n=0;n<N_EXTS;n++)
|
|
{
|
|
if (is_def[n]) ret|=1<<n;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
cfg_int cfg_ext_mask("ext_mask",get_def_exts());
|
|
|
|
static char d_smf[128];
|
|
static char d_clo[128];
|
|
static char d_cmp[128];
|
|
|
|
int ext_descs[N_EXTS]={STRING_FILES_SMF,STRING_FILES_SMF,STRING_FILES_SMF,STRING_FILES_SMF,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_COMPRESSED,STRING_FILES_COMPRESSED};
|
|
|
|
int MIDI_core::FileTypes_GetNum() {return N_EXTS;}
|
|
const char * MIDI_core::FileTypes_GetExtension(int n) {return exts[n];}
|
|
char * MIDI_core::FileTypes_GetDescription(int n) {
|
|
char* s = d_smf;
|
|
if(ext_descs[n] == STRING_FILES_SMF) {
|
|
if(!d_smf[0]) {
|
|
WASABI_API_LNGSTRING_BUF(ext_descs[n],d_smf,128);
|
|
}
|
|
s = d_smf;
|
|
}
|
|
else if(ext_descs[n] == STRING_FILES_CLONE) {
|
|
if(!d_clo[0]) {
|
|
WASABI_API_LNGSTRING_BUF(ext_descs[n],d_clo,128);
|
|
}
|
|
s = d_clo;
|
|
}
|
|
else if(ext_descs[n] == STRING_FILES_COMPRESSED) {
|
|
if(!d_cmp[0]) {
|
|
WASABI_API_LNGSTRING_BUF(ext_descs[n],d_cmp,128);
|
|
}
|
|
s = d_cmp;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
static int isourext(const char* ext)
|
|
{
|
|
UINT n;
|
|
for(n=0;n<N_EXTS;n++)
|
|
{
|
|
if ((cfg_ext_mask&(1<<n)) && !_stricmp(ext,exts[n])) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int MIDI_core::IsOurFile(const char *fn)
|
|
{
|
|
const char* p=strrchr(fn,'.');
|
|
if (p)
|
|
{
|
|
if (isourext(p+1)) return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
extern UINT volmode_detect();
|
|
|
|
static BOOL CALLBACK KarProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp);
|
|
|
|
int MIDI_core::Init()
|
|
{
|
|
theFile=0;
|
|
data_src=0;
|
|
plr=0;
|
|
eof=0;
|
|
mix_dev=0;mix_idx=0;
|
|
kwnd=0;
|
|
kmap=0;
|
|
kmap_size=0;kmap_ptr=0;
|
|
kmap_data=0;
|
|
format_srate=0;format_nch=0;format_bps=0;
|
|
|
|
device=MIDI_driver::find_device(cfg_driver,cfg_device);
|
|
if (!device) return 0;
|
|
use_out=device->has_output() || (cfg_smp && cfg_sampout);
|
|
use_smp=cfg_smp && !device->has_output();
|
|
|
|
if (cfg_volmode>2) volmod=cfg_volmode-1;
|
|
else if (cfg_volmode==2) volmod = device->volctrl_happy() ? 1 : volmode_detect()+2;
|
|
else volmod=cfg_volmode;
|
|
|
|
if (volmod>1)
|
|
{
|
|
UINT idx=volmod-2;
|
|
UINT id=0;
|
|
UINT n_devz=mixerGetNumDevs();
|
|
UINT dev=0;
|
|
BOOL found=0;
|
|
MIXERLINE ml;
|
|
while(dev<n_devz)
|
|
{
|
|
mixerGetID((HMIXEROBJ)dev,&id,MIXER_OBJECTF_MIXER);
|
|
|
|
ZeroMemory(&ml,sizeof(ml));
|
|
ml.cbStruct=sizeof(ml);
|
|
ml.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
|
|
|
|
mixerGetLineInfo((HMIXEROBJ)id,&ml,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER);
|
|
|
|
if (idx<ml.cConnections)
|
|
{
|
|
found=1;
|
|
break;
|
|
}
|
|
idx-=ml.cConnections;
|
|
dev++;
|
|
}
|
|
if (found)
|
|
{
|
|
mix_dev=id;
|
|
mix_idx=idx;
|
|
}
|
|
else
|
|
{
|
|
volmod=0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
CStream * sampling_create(int srate,int nch,int bps);
|
|
|
|
cfg_int cfg_lyrics("lyrics",1);
|
|
|
|
int MIDI_core::OpenFile(MIDI_file * file)
|
|
{
|
|
|
|
#ifdef USE_LOG
|
|
log_write("MIDI_core::Open()");
|
|
#endif
|
|
|
|
if (!file) return 0;
|
|
|
|
format_srate=device->has_freq() ? cfg_freq : 44100;
|
|
format_bps=16;
|
|
format_nch=2;
|
|
|
|
|
|
|
|
theFile=file->AddRef();
|
|
#ifdef USE_LOG
|
|
log_write("file loaded");
|
|
#endif
|
|
plr=0;
|
|
|
|
|
|
if (use_smp)
|
|
{
|
|
#ifdef USE_LOG
|
|
log_write("starting sampling");
|
|
#endif
|
|
format_srate=cfg_wavein_sr;
|
|
format_bps=cfg_wavein_bps;
|
|
format_nch=cfg_wavein_ch;
|
|
data_src=sampling_create(format_srate,format_nch,format_bps);
|
|
}
|
|
|
|
plr=device->create();
|
|
|
|
if (plr)
|
|
{
|
|
#ifdef USE_LOG
|
|
if (data_src) log_write("got PCM data source");
|
|
|
|
log_write("playback started");
|
|
#endif
|
|
|
|
if (cfg_lyrics)
|
|
{
|
|
kmap=kmap_create(theFile,1,&kmap_size,&kmap_data);
|
|
if (kmap)
|
|
{
|
|
kwnd=WASABI_API_CREATEDIALOGPARAMW(IDD_LYRICS,MIDI_callback::GetMainWindow(),KarProc,0);
|
|
free(kmap_data); kmap_data=0;//not needed anymore, used only on initdialog to setdlgitemtext
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if (data_src) {delete data_src;data_src=0;}
|
|
|
|
theFile->Free();
|
|
theFile=0;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int MIDI_core::GetSamples(void *sample_buffer, int bytes, char *killswitch)
|
|
{
|
|
#ifdef USE_LOG
|
|
log_write("GetSamples");
|
|
#endif
|
|
if (data_src)
|
|
{
|
|
return data_src->ReadData(sample_buffer,bytes,(bool*)killswitch);
|
|
}
|
|
else return 0;
|
|
}
|
|
|
|
void MIDI_core::update_vol()
|
|
{
|
|
MIXERLINE ml;
|
|
ZeroMemory(&ml,sizeof(ml));
|
|
ml.cbStruct=sizeof(ml);
|
|
ml.dwSource=mix_idx;
|
|
mixerGetLineInfo((HMIXEROBJ)mix_dev,&ml,MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_MIXER);
|
|
|
|
MIXERLINECONTROLS cs;
|
|
MIXERCONTROL c;
|
|
ZeroMemory(&cs,sizeof(cs));
|
|
cs.cbStruct=sizeof(cs);
|
|
cs.cControls=1;
|
|
cs.dwLineID=ml.dwLineID;
|
|
cs.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME;
|
|
cs.cbmxctrl=sizeof(c);
|
|
cs.pamxctrl=&c;
|
|
ZeroMemory(&c,sizeof(c));
|
|
c.cbStruct=sizeof(c);
|
|
|
|
if (!mixerGetLineControls((HMIXEROBJ)mix_dev,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
|
|
{
|
|
DWORD val;
|
|
if (cfg_logvol)
|
|
{
|
|
double _vol=volume>0 ? 20*log10((double)volume/255.0) : -60.0;//in negative db
|
|
_vol=_vol/60.0+1;
|
|
if (_vol<0) _vol=0;
|
|
val=c.Bounds.dwMinimum + (int)( _vol * (double)(c.Bounds.dwMaximum-c.Bounds.dwMinimum) );
|
|
}
|
|
else val=c.Bounds.dwMinimum + volume * (c.Bounds.dwMaximum-c.Bounds.dwMinimum) / 255;
|
|
if (ml.cChannels==1)
|
|
{
|
|
MIXERCONTROLDETAILS_UNSIGNED ds={val};
|
|
MIXERCONTROLDETAILS d;
|
|
d.cbStruct=sizeof(d);
|
|
d.dwControlID=c.dwControlID;
|
|
d.cChannels=1;
|
|
d.cMultipleItems=0;
|
|
d.cbDetails=sizeof(ds);
|
|
d.paDetails=&ds;
|
|
mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
|
|
}
|
|
else if (ml.cChannels<16)
|
|
{
|
|
MIXERCONTROLDETAILS_UNSIGNED ds[16];
|
|
UINT n;
|
|
for(n=0;n<16;n++) ds[n].dwValue=val;
|
|
if (pan<0)
|
|
{
|
|
ds[1].dwValue=ds[1].dwValue*(128+pan)>>7;
|
|
}
|
|
else
|
|
{
|
|
ds[0].dwValue=ds[0].dwValue*(128-pan)>>7;
|
|
}
|
|
MIXERCONTROLDETAILS d;
|
|
d.cbStruct=sizeof(d);
|
|
d.dwControlID=c.dwControlID;
|
|
d.cChannels=ml.cChannels;
|
|
d.cMultipleItems=0;
|
|
d.cbDetails=sizeof(ds[0]);
|
|
d.paDetails=&ds;
|
|
mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
|
|
}
|
|
}
|
|
/*
|
|
ZeroMemory(&cs,sizeof(cs));
|
|
cs.cbStruct=sizeof(cs);
|
|
cs.cControls=1;
|
|
cs.dwLineID=ml.dwLineID;
|
|
cs.dwControlType=MIXERCONTROL_CONTROLTYPE_PAN;
|
|
cs.cbmxctrl=sizeof(c);
|
|
cs.pamxctrl=&c;
|
|
ZeroMemory(&c,sizeof(c));
|
|
c.cbStruct=sizeof(c);
|
|
|
|
if (!mixerGetLineControls((HMIXEROBJ)mix_dev,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
|
|
{
|
|
MIXERCONTROLDETAILS_SIGNED ds={c.Bounds.lMinimum + (pan+128) * (c.Bounds.lMaximum-c.Bounds.lMinimum) / 255};
|
|
MIXERCONTROLDETAILS d;
|
|
d.cbStruct=sizeof(d);
|
|
d.dwControlID=c.dwControlID;
|
|
d.cbDetails=sizeof(ds);
|
|
d.cChannels=ml.cChannels;
|
|
d.cMultipleItems=c.cMultipleItems;
|
|
d.paDetails=&ds;
|
|
mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
|
|
}*/
|
|
}
|
|
|
|
int MIDI_core::SetVolume(int _volume)
|
|
{
|
|
volume=_volume;
|
|
if (volmod==0) return 0;
|
|
else
|
|
{
|
|
if (volmod==1)
|
|
{
|
|
if ((use_out && !use_smp) || !plr)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return plr->setvol(player_getVol());
|
|
}
|
|
}
|
|
update_vol();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int MIDI_core::SetPan(int _pan)
|
|
{
|
|
pan=_pan;
|
|
if (volmod==0) return 0;
|
|
else
|
|
{
|
|
if (volmod==1)
|
|
{
|
|
if (plr) return plr->setpan(player_getPan());
|
|
else return 0;
|
|
}
|
|
else
|
|
{
|
|
update_vol();
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
int MIDI_core::SetPosition(int pos)
|
|
{
|
|
if (!plr) return 0;
|
|
if (!plr->settime(pos)) return 0;
|
|
sync.enter();
|
|
kmap_ptr=0;
|
|
LeaveCriticalSection(&sync);
|
|
|
|
if (data_src) data_src->Flush();
|
|
return 1;
|
|
}
|
|
|
|
void MIDI_core::Pause(int pause)
|
|
{
|
|
if (plr)
|
|
{
|
|
if (pause) plr->pause();
|
|
else plr->unpause();
|
|
}
|
|
if (data_src) data_src->Pause(pause);
|
|
}
|
|
|
|
int MIDI_core::GetPosition(void)
|
|
{
|
|
int i=0;
|
|
if (plr)
|
|
{
|
|
i=plr->gettime();
|
|
if (i<0) i=0;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
int MIDI_core::GetLength(void)
|
|
{
|
|
if (theFile) return theFile->len;
|
|
else return -1;
|
|
}
|
|
|
|
void MIDI_core::Close()
|
|
{
|
|
#ifdef USE_LOG
|
|
log_write("shutting down MIDI_core");
|
|
#endif
|
|
if (plr) {delete plr;plr=0;}
|
|
if (data_src) {delete data_src;data_src=0;}
|
|
if (kwnd) {DestroyWindow(kwnd);kwnd=0;}
|
|
if (kmap) {free(kmap);kmap=0;}
|
|
if (theFile) {theFile->Free();theFile=0;}
|
|
}
|
|
|
|
void MIDI_core::Eof()
|
|
{
|
|
eof=1;
|
|
if (data_src)
|
|
data_src->Eof();
|
|
else
|
|
MIDI_callback::NotifyEOF();
|
|
}
|
|
|
|
|
|
static char INI_FILE[MAX_PATH];
|
|
|
|
void MIDI_core::GlobalInit()
|
|
{
|
|
#ifdef USE_LOG
|
|
log_start();
|
|
log_write("initializing");
|
|
log_write(NAME);
|
|
#endif
|
|
|
|
char *p;
|
|
if (mod.hMainWindow &&
|
|
(p = (char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE))
|
|
&& p!= (char *)1)
|
|
{
|
|
strcpy(INI_FILE, p);
|
|
}
|
|
else
|
|
{
|
|
GetModuleFileNameA(NULL,INI_FILE,sizeof(INI_FILE));
|
|
p = INI_FILE + strlen(INI_FILE);
|
|
while (p >= INI_FILE && *p != '.') p--;
|
|
strcpy(++p,"ini");
|
|
}
|
|
cfg_var::config_read(INI_FILE,"in_midi");
|
|
}
|
|
|
|
void MIDI_core::GlobalQuit()
|
|
{
|
|
MIDI_driver::shutdown();
|
|
log_quit();
|
|
}
|
|
|
|
void MIDI_core::WriteConfig()
|
|
{
|
|
cfg_var::config_write(INI_FILE,"in_midi");
|
|
}
|
|
|
|
void MIDI_core::MM_error(DWORD code)
|
|
{
|
|
string temp;
|
|
if (!mciGetErrorStringA(code,string_buffer_a(temp,256),256))
|
|
{
|
|
temp=WASABI_API_LNGSTRING(STRING_UNKNOWN_MMSYSTEM);
|
|
}
|
|
MIDI_callback::Error(temp);
|
|
|
|
}
|
|
|
|
|
|
static void fix_size(HWND wnd)
|
|
{
|
|
RECT r;
|
|
GetClientRect(wnd,&r);
|
|
SetWindowPos(GetDlgItem(wnd,IDC_BLAH),0,0,0,r.right,r.bottom,SWP_NOZORDER|SWP_NOACTIVATE);
|
|
}
|
|
|
|
static cfg_struct_t<RECT> cfg_lyrics_pos("lyrics_pos",-1);
|
|
|
|
static void SetWindowRect(HWND w,RECT* r)
|
|
{
|
|
SetWindowPos(w,0,r->left,r->top,r->right-r->left,r->bottom-r->top,SWP_NOZORDER);
|
|
}
|
|
|
|
|
|
static cfg_int cfg_lyrics_min("lyrics_min",0),cfg_lyrics_max("lyrics_max",0);
|
|
|
|
BOOL CALLBACK MIDI_core::KarProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
|
|
{
|
|
switch(msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
SetDlgItemTextA(wnd,IDC_BLAH,MIDI_core::kmap_data);
|
|
|
|
if (cfg_lyrics_pos.get_val().left!=-1)
|
|
{
|
|
int sx=GetSystemMetrics(SM_CXSCREEN),sy=GetSystemMetrics(SM_CYSCREEN);
|
|
if (cfg_lyrics_pos.get_val().right>sx)
|
|
{
|
|
cfg_lyrics_pos.get_val().left-=cfg_lyrics_pos.get_val().right-sx;
|
|
cfg_lyrics_pos.get_val().right=sx;
|
|
}
|
|
if (cfg_lyrics_pos.get_val().bottom>sy)
|
|
{
|
|
cfg_lyrics_pos.get_val().top-=cfg_lyrics_pos.get_val().bottom-sy;
|
|
cfg_lyrics_pos.get_val().bottom=sy;
|
|
}
|
|
if (cfg_lyrics_pos.get_val().left<0)
|
|
{
|
|
cfg_lyrics_pos.get_val().right-=cfg_lyrics_pos.get_val().left;
|
|
cfg_lyrics_pos.get_val().left=0;
|
|
}
|
|
if (cfg_lyrics_pos.get_val().top<0)
|
|
{
|
|
cfg_lyrics_pos.get_val().bottom-=cfg_lyrics_pos.get_val().top;
|
|
cfg_lyrics_pos.get_val().top=0;
|
|
}
|
|
SetWindowRect(wnd,&cfg_lyrics_pos.get_val());
|
|
}
|
|
if (cfg_lyrics_min)
|
|
{
|
|
ShowWindow(wnd,SW_MINIMIZE);
|
|
}
|
|
else if (cfg_lyrics_max)
|
|
{
|
|
ShowWindow(wnd,SW_MAXIMIZE);
|
|
}
|
|
fix_size(wnd);
|
|
SetTimer(wnd,1,100,0);
|
|
return 1;
|
|
case WM_TIMER:
|
|
{
|
|
sync.enter();
|
|
UINT time=GetPosition();
|
|
KAR_ENTRY * set=0;
|
|
UINT ptr=kmap_ptr;
|
|
while(ptr<kmap_size && kmap[ptr].time<time)
|
|
{
|
|
if (!kmap[ptr].foo) set=&kmap[ptr];
|
|
ptr++;
|
|
}
|
|
kmap_ptr=ptr;
|
|
sync.leave();
|
|
if (set)
|
|
{
|
|
SendDlgItemMessage(wnd,IDC_BLAH,EM_SETSEL,set->start,set->end);
|
|
}
|
|
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
KillTimer(wnd,1);
|
|
kwnd=0;
|
|
GetWindowRect(wnd,&cfg_lyrics_pos.get_val());
|
|
cfg_lyrics_max=!!IsZoomed(wnd);
|
|
cfg_lyrics_min=!!IsIconic(wnd);
|
|
break;
|
|
case WM_CLOSE:
|
|
|
|
cfg_lyrics=0;
|
|
|
|
if (!((int)cfg_bugged & BUGGED_BLAH))
|
|
{
|
|
char title[32] = {0};
|
|
cfg_bugged = (int)cfg_bugged | BUGGED_BLAH;
|
|
MessageBoxA(wnd,WASABI_API_LNGSTRING(IDS_TO_ENABLE_LYRICS_DISPLAY),
|
|
WASABI_API_LNGSTRING_BUF(IDS_INFORMATION,title,32),MB_ICONINFORMATION);
|
|
}
|
|
DestroyWindow(wnd);
|
|
break;
|
|
case WM_SIZE:
|
|
fix_size(wnd);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//MIDI_core static crap
|
|
bool MIDI_core::use_out;
|
|
MIDI_file* MIDI_core::theFile;
|
|
CStream* MIDI_core::data_src;
|
|
player_base* MIDI_core::plr;
|
|
int MIDI_core::format_srate,MIDI_core::format_nch,MIDI_core::format_bps;
|
|
int MIDI_core::volume=255,MIDI_core::pan=0;
|
|
bool MIDI_core::eof;
|
|
UINT MIDI_core::volmod;
|
|
UINT MIDI_core::mix_dev,MIDI_core::mix_idx;
|
|
MIDI_device * MIDI_core::device;
|
|
bool MIDI_core::use_smp;
|
|
HWND MIDI_core::kwnd;
|
|
KAR_ENTRY* MIDI_core::kmap;
|
|
UINT MIDI_core::kmap_size,MIDI_core::kmap_ptr;
|
|
char * MIDI_core::kmap_data;
|
|
critical_section MIDI_core::sync; |