| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962 | #include "main.h"#include <math.h>#include "seq.h"#include "fakedsound.h"#include "resource.h"// {B84EB58A-29F5-410b-880A-EB473BF34291}static const GUID guid_output = { 0xb84eb58a, 0x29f5, 0x410b, { 0x88, 0xa, 0xeb, 0x47, 0x3b, 0xf3, 0x42, 0x91 } };// {DF0800B6-D1E1-4b53-9C1E-642AF4CB7136}static const GUID dmusic_driver_guid = { 0xdf0800b6, 0xd1e1, 0x4b53, { 0x9c, 0x1e, 0x64, 0x2a, 0xf4, 0xcb, 0x71, 0x36 } };enum{	MDD_OUT=1,};extern cfg_int cfg_dls_active,cfg_dm_keep_port;extern cfg_string cfg_dls_file;class MIDI_device_dmusic : public MIDI_device{private:	GUID guid,guid_dmusic;	DWORD dmFlags;	bool f_has_output;	virtual player_base * create();	virtual bool is_default() {return 0;}	virtual bool has_freq() {return !!(dmFlags&DMUS_PC_DIRECTSOUND);}	virtual bool volctrl_happy() {return (dmFlags&DMUS_PC_DIRECTSOUND) || (dmFlags&DMUS_PC_SOFTWARESYNTH);}public:	MIDI_device_dmusic(GUID p_guid,bool p_has_output,DWORD p_dmFlags,const wchar_t * p_name,const wchar_t * p_info)	{		guid = p_guid;		guid_dmusic = p_guid;		dmFlags = p_dmFlags;		set_name(p_name);		set_info(p_info);		f_has_output = p_has_output;		if (f_has_output)		{			const BYTE * src = (const BYTE*) &guid_output;			BYTE * dst = (BYTE*) &guid;			int n;			for(n=0;n<sizeof(GUID);n++) dst[n]^=src[n];		}		}	virtual GUID get_guid() {return guid;}	GUID get_dm_guid() {return guid_dmusic;}	virtual bool has_output() {return f_has_output;}	virtual bool has_dls() {return !!(dmFlags&DMUS_PC_DLS);}};//bool IsDrumBankOK(BYTE n);IDirectMusicLoader* pLoader=0;IDirectMusicPerformance* pPerf=0;static IDirectMusicCollection *pGM=0;static IDirectMusic* pDM;static IDirectMusicPort *pPort;static IDirectSoundBuffer* pHack;IDirectMusicCollection *pCDLS=0;static void SendMsg(IDirectMusicPerformance *pPerf,DWORD msg){    DMUS_MIDI_PMSG     *pMSG;    if(SUCCEEDED(pPerf->AllocPMsg(sizeof(DMUS_MIDI_PMSG),(DMUS_PMSG**)&pMSG)))    {		ZeroMemory(pMSG, sizeof(DMUS_MIDI_PMSG));		pMSG->dwSize = sizeof(DMUS_MIDI_PMSG);		pMSG->dwPChannel = msg&0xF;		pMSG->dwVirtualTrackID = 0;		pMSG->dwType = DMUS_PMSGT_MIDI;		pMSG->dwVoiceID = 0;		pMSG->dwGroupID = 0xFFFFFFFF;		pMSG->mtTime=0;		pMSG->dwFlags = DMUS_PMSGF_REFTIME|DMUS_PMSGF_TOOL_IMMEDIATE;//pMSG->dwFlags = DMUS_PMSGF_REFTIME|DMUS_PMSGF_TOOL_IMMEDIATE;		pMSG->bStatus=(BYTE)(msg&0xFF);		pMSG->bByte1=(BYTE)((msg>>8)&0xFF);		pMSG->bByte2=(BYTE)((msg>>16)&0xFF);		if (FAILED(pPerf->SendPMsg((DMUS_PMSG*)pMSG)))		{			pPerf->FreePMsg((DMUS_PMSG*)pMSG);		}    }}static void SendSysex(IDirectMusicPerformance *pPerf,BYTE* data,UINT len){    DMUS_SYSEX_PMSG     *pMSG;    if(SUCCEEDED(pPerf->AllocPMsg(sizeof(DMUS_SYSEX_PMSG) + len,(DMUS_PMSG**)&pMSG)))    {		ZeroMemory(pMSG, sizeof(DMUS_SYSEX_PMSG)+len);		pMSG->dwSize = sizeof(DMUS_SYSEX_PMSG);		pMSG->dwPChannel = 0;		pMSG->dwVirtualTrackID = 0;		pMSG->dwType = DMUS_PMSGT_SYSEX;		pMSG->dwVoiceID = 0;		pMSG->dwGroupID = 0xFFFFFFFF;		pMSG->dwLen = len;		memcpy(pMSG->abData, (void*)data, len);		pMSG->mtTime=0;		pMSG->dwFlags = DMUS_PMSGF_REFTIME|DMUS_PMSGF_TOOL_IMMEDIATE;//pMSG->dwFlags = |DMUS_PMSGF_TOOL_IMMEDIATE;		if (FAILED(pPerf->SendPMsg((DMUS_PMSG*)pMSG)))		{			pPerf->FreePMsg((DMUS_PMSG*)pMSG);		}    }}static void PortKill(){#ifdef USE_LOG	log_write("portkill()");#endif	if (pPort)	{		pPort->Activate(0);		if (pPerf) pPerf->RemovePort(pPort);		pPort->Release();		pPort=0;	}}static int PortInit(MIDI_device_dmusic * dev){#ifdef USE_LOG	log_write("portinit()");#endifstatic int _act_freq;static int _cfg_reverb,_cfg_chorus;static GUID last_port;	if (!pPort || last_port!=dev->get_guid() || _act_freq!=cfg_freq || _cfg_reverb!=cfg_reverb || _cfg_chorus!=cfg_chorus)	{#ifdef USE_LOG		log_write("port settings changed");#endif				if (pPort) PortKill();		DMUS_PORTPARAMS dmpp;		ZeroMemory(&dmpp,sizeof(dmpp));		dmpp.dwSize=sizeof(dmpp);		dmpp.dwValidParams=DMUS_PORTPARAMS_EFFECTS|DMUS_PORTPARAMS_SAMPLERATE|DMUS_PORTPARAMS_CHANNELGROUPS;		dmpp.dwChannelGroups=1;		dmpp.dwSampleRate=cfg_freq;		if (cfg_reverb) dmpp.dwEffectFlags=DMUS_EFFECT_REVERB;		if (cfg_chorus) dmpp.dwEffectFlags|=DMUS_EFFECT_CHORUS;		if (FAILED( pDM->CreatePort(dev->get_dm_guid(),&dmpp,&pPort,0) )) return 0;				pPerf->AddPort(pPort);		pPerf->AssignPChannelBlock(0,pPort,1);		last_port = dev->get_guid();		_act_freq=cfg_freq;		_cfg_reverb=cfg_reverb;		_cfg_chorus=cfg_chorus;	}	if ((dev->has_output()))	{#ifdef USE_LOG		log_write("initializing output hack");#endif		DWORD buf_s=0,blah=0;		pPort->GetFormat(0,&blah,&buf_s);		pHack=dhb_create(buf_s,cfg_freq);		if (FAILED(pPort->SetDirectSound(get_ds(),pHack)))		{//BORK			PortKill();			return 0;		}	}	return 1;}/*	int lastvol1=(vol==0)?0x80000000:((int)(2000.0*log((double)vol/256.0)));	if (pPerf)	{		return SUCCEEDED(pPerf->SetGlobalParam(GUID_PerfMasterVolume,&lastvol1,4));	}*/static int DM_setvol(int vol){	int lastvol1=(vol==0)?0x80000000:((int)(2000.0*log10((double)vol/255.0)));	if (pPerf)	{		return SUCCEEDED(pPerf->SetGlobalParam(GUID_PerfMasterVolume,&lastvol1,4));	}	return 0;}class player_dmusic_imm : public seq_base{private:	MIDI_device_dmusic * dev;	UINT n_ins,s_ins;	IDirectMusicDownloadedInstrument ** ins;	IDirectMusicCollection *edls;protected:	virtual void seq_shortmsg(DWORD msg) {SendMsg(pPerf,msg);}	virtual void seq_sysex(BYTE* d,UINT l) {SendSysex(pPerf,d,l);}	virtual void eof() {MIDI_core::Eof();}	int setvol(int t) {return DM_setvol(t);}public:	player_dmusic_imm(MIDI_device_dmusic * p_dev)	{		dev=p_dev;		s_ins=n_ins=0;		ins=0;		edls=0;				if (dev->has_dls())		{			s_ins=0x100;			ins=(IDirectMusicDownloadedInstrument**)malloc(s_ins*sizeof(void*));		}			}	~player_dmusic_imm();	int play();};int player_dmusic_imm::play(){	if (!PortInit(dev)) return 0;	MIDI_file * mf=MIDI_core::getFile();	if (ins)	{		if (mf->pDLSdata)		{			LoadDLS(mf);			if (mf->pDLS)			{				edls=mf->pDLS;			}		}				if (!edls) edls=pCDLS;		{			INSTRUMENT_DESC* instr=GetInstruments(mf,1);			while(instr)			{				DWORD i=instr->patch | (instr->bank_lo<<8) | (instr->bank_hi<<16);				if (instr->drum) i|=0x80000000;				if (n_ins>=s_ins)				{					s_ins<<=1;					void *t=realloc(ins,s_ins);//					if (!t) {s_ins>>=1;return ;}					ins=(IDirectMusicDownloadedInstrument**)t;				}				IDirectMusicInstrument * pi=0;start:				if (edls)				{					edls->GetInstrument(i,&pi);				}				if (!pi && pGM)				{					pGM->GetInstrument(i,&pi);				}				if (!pi)	//cleaner's hacks don't work here				{					if (i&0x80000000)					{						if (i&0xFFFF00) {i&=0x800000FF;goto start;}					}					else					{						if (i&0xFF00) {i&=0xFF00FF;goto start;}						if (i&0xFF0000) {i&=0xFF;goto start;}					}				}#if 0				if (!pi)				{					char tmp[128] = {0};					if (i&0x80000000)						wsprintf(tmp,"missing drum kit: %u",i&0xFF);					else						wsprintf(tmp,"missing instrument: bank %x:%x / patch %x",(i>>16)&0xFF,(i>>8)&0xFF,i&0xFF);					Warning(tmp);				}#endif				if (pi)				{//					DMUS_NOTERANGE nr = {instr->note_min,instr->note_max};//					pPort->DownloadInstrument(pi,&ins[n_ins++],&nr,1);					pPort->DownloadInstrument(pi,&ins[n_ins++],0,0);					pi->Release();				}				{					INSTRUMENT_DESC * d=instr->next;					delete instr;					instr=d;				}			}		}	}/*	UINT n;	for(n=0;n<16;n++)	{		pPort->SetChannelPriority(0,n,DAUD_CRITICAL_VOICE_PRIORITY);	}*/	pPort->Activate(1);	DM_setvol(MIDI_core::player_getVol());	return seq_cmd_start(CLEAN_DM);}player_dmusic_imm::~player_dmusic_imm(){	seq_cmd_stop();	if (ins)	{		if (pPort)		{			pPort->Activate(0);			UINT n;			for(n=0;n<n_ins;n++)			{				if (ins[n])				{					pPort->UnloadInstrument(ins[n]);					ins[n]=0;				}			}		}		free(ins);	}	if (pHack)	{		pPort->SetDirectSound(0,0);		pHack->Release();		pHack=0;	}	if (!cfg_dm_keep_port) PortKill();}static void CALLBACK TimerProc(HWND,UINT,UINT id,DWORD){	DMUS_NOTIFICATION_PMSG* pMsg;	while(pPerf->GetNotificationPMsg(&pMsg)==S_OK)	{		if (IsEqualGUID(pMsg->guidNotificationType,GUID_NOTIFICATION_SEGMENT))		{			if (MIDI_core::HavePlayer() && pMsg->dwNotificationOption == DMUS_NOTIFICATION_SEGEND)			{				MIDI_core::Eof();			}		}		pPerf->FreePMsg((DMUS_PMSG*)pMsg);	}}class player_dmusic : public player_base{public:	~player_dmusic();	int gettime();	int settime(int);	int setvol(int vol) {return DM_setvol(vol);}	void pause();	void unpause();	int play();	player_dmusic(MIDI_device_dmusic * p_dev)	{		dev = p_dev;		pSeg=0;		pSS=0;		rtStart=rtOffset=0;		mtStart=mtOffset=0;	}private:	MIDI_device_dmusic * dev;	IDirectMusicSegment* pSeg;	IDirectMusicSegmentState* pSS;	REFERENCE_TIME rtStart,rtOffset;	MUSIC_TIME mtOffset,mtStart;	bool dloaded,paused;	UINT timer_id;};player_base * MIDI_device_dmusic::create(){#ifdef USE_LOG	log_write("DM_create");#endif	CoInitialize(0);	if (!pLoader)	{		try {						CoCreateInstance(CLSID_DirectMusicLoader,0,CLSCTX_INPROC,IID_IDirectMusicLoader,(void**)&pLoader);			if (!pLoader) return 0;			pLoader->EnableCache(GUID_DirectMusicAllTypes,0);		} catch(...) {			return 0;		}	}	if (!pPerf)	{		try {			CoCreateInstance(CLSID_DirectMusicPerformance,0,CLSCTX_INPROC,IID_IDirectMusicPerformance,(void**)&pPerf);			if (!pPerf) return 0;			pPerf->Init(&pDM,0,0);			pPerf->AddNotificationType(GUID_NOTIFICATION_SEGMENT);		} catch(...) {			return 0;		}	}	if (!pGM)	{		DMUS_OBJECTDESC desc;		ZeroMemory(&desc,sizeof(desc));		desc.dwSize=sizeof(desc);		desc.dwValidData=DMUS_OBJ_OBJECT|DMUS_OBJ_CLASS;		desc.guidObject=GUID_DefaultGMCollection;		desc.guidClass=CLSID_DirectMusicCollection;		try {			pLoader->GetObject(&desc,IID_IDirectMusicCollection,(void**)&pGM);		} catch(...) {			return 0;		}	}			if (has_dls())	{		static string current_dls;		if (!cfg_dls_active)		{			if (pCDLS) {pCDLS->Release();pCDLS=0;}		}		else		{			if (pCDLS && _stricmp(current_dls,cfg_dls_file)) {pCDLS->Release();pCDLS=0;}			if (!pCDLS)			{				DMUS_OBJECTDESC desc;				ZeroMemory(&desc,sizeof(desc));				desc.dwSize=sizeof(desc);				desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;				desc.guidClass = CLSID_DirectMusicCollection;				mbstowcs(desc.wszFileName,cfg_dls_file,DMUS_MAX_FILENAME);				if (FAILED(pLoader->GetObject(&desc,IID_IDirectMusicCollection,(void**)&pCDLS)))				{//					ErrorBox(Can't load DLS file.);					pCDLS=0;					cfg_dls_active=0;				}				else				{					ReleaseObject(pCDLS);					current_dls = cfg_dls_file;				}			}		}	}	if (cfg_playback_mode)	{		player_dmusic_imm * p=new player_dmusic_imm(this);		if (p)		{			if (!p->play())			{				delete p;				p=0;			}		}		return p;	}	else	{		player_dmusic* p=new player_dmusic(this);		if (p)		{			if (!p->play()) {delete p;p=0;}		}		return p;	}}MUSIC_TIME GetMTforMS(IDirectMusicSegment* pS,DWORD ms){	MUSIC_TIME mtSeg,mct=0,mnt;	DMUS_TEMPO_PARAM tp;	pS->GetLength(&mtSeg);	double _r=0,r1;	while(mct<mtSeg)	{		if (FAILED(pS->GetParam(GUID_TempoParam,-1,0,mct,&mnt,&tp))) break;		if (!mnt) mnt=mtSeg-mct;		r1=_r;		_r+=(mnt)/tp.dblTempo*78;		if (_r>ms)		{			return (MUSIC_TIME)(mct+mnt*((double)ms-r1)/(_r-r1));		}		mct+=mnt;	}	return mtSeg;}DWORD GetSegLen(IDirectMusicSegment* pS){	MUSIC_TIME mtSeg,mct=0,mnt;	DMUS_TEMPO_PARAM tp;	pS->GetLength(&mtSeg);	double _r=0;	while(mct<mtSeg)	{		pS->GetParam(GUID_TempoParam,-1,0,mct,&mnt,&tp);		if (!mnt) mnt=mtSeg-mct;		_r+=(double)mnt/tp.dblTempo*78;		mct+=mnt;	}	return (DWORD)_r;}void ReleaseObject(IUnknown* o){	IDirectMusicObject* pObject=0;	if (pLoader && SUCCEEDED(o->QueryInterface(IID_IDirectMusicObject,(void**)&pObject)))	{		pLoader->ReleaseObject(pObject);		pObject->Release();	}}player_dmusic::~player_dmusic(){	pPerf->Stop(0,0,0,0);	if (pPort) pPort->Activate(0);//	pPerf->Invalidate(0,0);	mtOffset=0;	rtOffset=0;	mtStart=0;	rtStart=0;	if (pSS) {pSS->Release();pSS=0;}	if (pSeg)	{		if (dloaded) pSeg->SetParam(GUID_Unload,0xFFFFFFFF,0,0,(void*)pPerf);		pSeg->Release();		pSeg=0;	}	if (pHack)	{		pPort->SetDirectSound(0,0);		pHack->Release();		pHack=0;	} 	if (!cfg_dm_keep_port) PortKill();	if (timer_id) KillTimer(0,timer_id);}void player_dmusic::pause(){	MUSIC_TIME mt;	REFERENCE_TIME rt;	pPerf->Stop(0,0,0,0);	if (pSS)	{		pSS->Release();		pSS=0;	}	pPerf->GetTime(&rt,&mt);	mtOffset+=mt-mtStart;	rtOffset+=rt-rtStart;	pSeg->SetStartPoint(mtOffset);	paused=1;}void player_dmusic::unpause(){	if (pSS)	{		pSS->Release();		pSS=0;	}	if (SUCCEEDED(pPerf->PlaySegment(pSeg,0,0,&pSS)))	{		pSS->GetStartTime(&mtStart);		pPerf->MusicToReferenceTime(mtStart,&rtStart);	}	paused=0;}int player_dmusic::gettime(){	static DWORD tm;	if (pSS)	{		REFERENCE_TIME rt;		pPerf->GetTime(&rt,0);		tm=(int)((rt-rtStart+rtOffset)/10000);	}	return tm;}int player_dmusic::play(){#ifdef USE_LOG	log_write("player_dmusic::play()");#endif	if (!PortInit(dev)) return 0;	pSeg=LoadSegment(MIDI_core::getFile());	if (!pSeg)	{#ifdef USE_LOG		log_write("LoadSegment() failed");#endif//		Error("Unable to get IDirectMusicSegment.");		return 0;	}#ifdef USE_LOG	log_write("player_dmusic::play() : got IDirectMusicSegment");#endif	pSeg->SetRepeats( (cfg_loop_type==2 || (cfg_loop_type==1 && MIDI_core::getFile()->loopstart)) ? (cfg_loop_infinite ? -1 : cfg_loop_count-1) : 0);		dloaded=0;	if (dev->has_dls())		if (SUCCEEDED(pSeg->SetParam(GUID_Download,-1,0,0,(void*)pPerf)))			dloaded=1;	pSeg->SetStartPoint(0); #ifdef USE_LOG	log_write("Activating port...");#endif	pPort->Activate(1);#ifdef USE_LOG	log_write("IDirectMusicPort::Activate() returned");#endif	sysex_startup((SYSEXFUNC)SendSysex,pPerf);#ifdef USE_LOG	log_write("IDirectMusicPerformance::PlaySegment()");#endif	pSS=0;		DM_setvol(MIDI_core::player_getVol());	if (FAILED(pPerf->PlaySegment(pSeg,DMUS_SEGF_DEFAULT,0,&pSS)))	{//		Error("IDirectMusicPerformance::PlaySegment() failed.");		return 0;	}#ifdef USE_LOG	log_write("IDirectMusicPerformance::PlaySegment() returned OK");#endif		rtOffset=0;	if (pSS)	{		pSS->GetStartTime(&mtStart);	}	else	{#ifdef USE_LOG		log_write("no segment starte. WTF ?");#endif		mtStart=0;	}	pPerf->MusicToReferenceTime(mtStart,&rtStart);		timer_id=SetTimer(0,0,33,(TIMERPROC)TimerProc);	return 1;}static struct{	int name;	UINT flag;} DMCAPZ[]={/*#define DMUS_PC_DLS              (0x00000001)   // Supports DLS downloading and DLS level 1.#define DMUS_PC_EXTERNAL         (0x00000002)   // External MIDI module.#define DMUS_PC_SOFTWARESYNTH    (0x00000004)   // Software synthesizer.#define DMUS_PC_MEMORYSIZEFIXED  (0x00000008)   // Memory size is fixed.#define DMUS_PC_GMINHARDWARE     (0x00000010)   // GM sound set is built in, no need to download.#define DMUS_PC_GSINHARDWARE     (0x00000020)   // GS sound set is built in.#define DMUS_PC_XGINHARDWARE     (0x00000040)   // XG sound set is built in.#define DMUS_PC_DIRECTSOUND      (0x00000080)   // Connects to DirectSound via a DSound buffer.#define DMUS_PC_SHAREABLE        (0x00000100)   // Synth can be actively shared by multiple apps at once.#define DMUS_PC_DLS2             (0x00000200)   // Supports DLS2 instruments.#define DMUS_PC_AUDIOPATH        (0x00000400)   // Multiple outputs can be connected to DirectSound for audiopaths.#define DMUS_PC_WAVE             (0x00000800)   // Supports streaming and one shot waves.*/	{STRING_DMCAPS_DLS1,DMUS_PC_DLS},	{STRING_DMCAPS_DLS2,DMUS_PC_DLS2},	{STRING_DMCAPS_SOFTSYNTH,DMUS_PC_SOFTWARESYNTH},	{STRING_DMCAPS_GM,DMUS_PC_GMINHARDWARE},	{STRING_DMCAPS_GS,DMUS_PC_GSINHARDWARE},	{STRING_DMCAPS_XG,DMUS_PC_XGINHARDWARE},//	{STRING_DMCAPS_DSOUND,DMUS_PC_DIRECTSOUND},	{STRING_DMCAPS_SHARE,DMUS_PC_SHAREABLE},};#define N_DMCAPZ (sizeof(DMCAPZ)/sizeof(DMCAPZ[0]))static struct{	int name;	UINT flag;} DMCAPZ1[]=	//effects{	{STRING_REVERB,DMUS_EFFECT_REVERB},	{STRING_CHORUS,DMUS_EFFECT_CHORUS},};#define N_DMCAPZ1 (sizeof(DMCAPZ1)/sizeof(DMCAPZ1[0]))int player_dmusic::settime(int tm){	int rv;#ifdef USE_LOG	log_write("player_dmusic::settime");#endif	rtOffset=UInt32x32To64(tm,10000);#ifdef USE_LOG	log_write("calling IDirectMusicPerformance::Stop()");#endif	if (!paused)	{#ifdef USE_LOG		log_write("IDirectMusicPerformance::Stop() returned");#endif		if (pSS) {pSS->Release();pSS=0;}	}	// not ideal but a pause, seek and unpause seems to resolve a failed seek issue	// with the 'Direct Music / Microsoft Synthesizer' and 'streamed' output mode	pause();	MUSIC_TIME time=GetMTforMS(pSeg,tm);	rv = SUCCEEDED( pSeg->SetStartPoint(time) );	if (rv) mtOffset=time;	unpause();	if (!paused)	{#ifdef USE_LOG		log_write("calling IDirectMusicPerformance::PlaySegment()");#endif		pSS=0;		pPerf->PlaySegment(pSeg,0,0,&pSS);		if (pSS) pSS->GetStartTime(&mtStart);		pPerf->MusicToReferenceTime(mtStart,&rtStart);	}	return rv;}BOOL test_ins_dls(DWORD patch,IDirectMusicCollection* pDLS){	IDirectMusicInstrument *pi=0;	BOOL rv=0;	if (SUCCEEDED(pDLS->GetInstrument(patch,&pi)))	{		pi->Release();		rv=1;	}	return rv;}int test_drum_kit(DWORD no,IDirectMusicCollection* dls){	DWORD p=no|0x80000000;	if (pGM)		if (test_ins_dls(p,pGM)) return 1;	if (pCDLS)		if (test_ins_dls(p,pCDLS)) return 1;	if (dls)		if (test_ins_dls(p,dls)) return 1;	return 0;}void do_dls_check(DWORD * i,IDirectMusicCollection * dls){start:	if (pGM)		if (test_ins_dls(*i,pGM)) return;	if (pCDLS)		if (test_ins_dls(*i,pCDLS)) return;	if (dls)		if (test_ins_dls(*i,dls)) return;	//hack hack hack	if (*i&0xFF00)	{		*i&=0xFF00FF;		goto start;	}	if (*i&0xFF0000)	{		*i&=0xFF;		return;	}}static cfg_int cfg_show_all("dmusic_show_all",0);class MIDI_driver_dmusic : MIDI_driver{	bool dm_inited;	virtual void do_init()	{		dm_inited=1;		try {#ifdef USE_LOG			log_write("CoInitialize()");#endif			CoInitialize(0);#ifdef USE_LOG			log_write("CoCreateInstance / IDirectMusic");#endif			IDirectMusic* pDM=0;			if (SUCCEEDED(CoCreateInstance(CLSID_DirectMusic,0,CLSCTX_INPROC,IID_IDirectMusic,(void**)&pDM)) && pDM)			{#ifdef USE_LOG				log_write("IDirectMusic created OK");#endif				DMUS_PORTCAPS dmpc;				memset(&dmpc,0,sizeof(dmpc));				dmpc.dwSize=sizeof(dmpc);				UINT np=0;				GUID def;				pDM->GetDefaultPort(&def);				while(1)				{					if (pDM->EnumPort(np++,&dmpc)==S_FALSE) break;					if (dmpc.dwClass==DMUS_PC_OUTPUTCLASS && (cfg_show_all || (dmpc.dwType!=DMUS_PORT_WINMM_DRIVER && dmpc.dwType==DMUS_PORT_KERNEL_MODE) || (dmpc.dwFlags&DMUS_PC_DLS) ))					{						wchar_t name_mbs[2*DMUS_MAX_DESCRIPTION] = {0};						wcsncpy(name_mbs,dmpc.wszDescription,256);						string_w info;						{							if (dmpc.dwType<3)							{								int dmport_types[3]={STRING_DMCAPS_WINMM,STRING_DMCAPS_USERMODE,STRING_DMCAPS_WDM};								info+=WASABI_API_LNGSTRINGW(STRING_DEVICE_TYPE);								info+=WASABI_API_LNGSTRINGW(dmport_types[dmpc.dwType]);								info+=L"\x0d\x0a";							}							UINT z;							for(z=0;z<N_DMCAPZ;z++)							{								if (dmpc.dwFlags & DMCAPZ[z].flag)								{									info+=WASABI_API_LNGSTRINGW(DMCAPZ[z].name);									info+=L"\x0d\x0a";								}							}							UINT n_effects=0;							for(z=0;z<N_DMCAPZ1;z++)							{								if (dmpc.dwEffectFlags&DMCAPZ1[z].flag)								{									info+=n_effects ? L", " : WASABI_API_LNGSTRINGW(STRING_EFFECTS);									info+=WASABI_API_LNGSTRINGW(DMCAPZ1[z].name);									n_effects++;								}							}							if (n_effects) info+=L"\x0d\x0a";						}						add_device(new MIDI_device_dmusic(dmpc.guidPort,0,dmpc.dwFlags,name_mbs,info));						if ((dmpc.dwFlags&DMUS_PC_DIRECTSOUND)&&(dmpc.dwFlags&DMUS_PC_SOFTWARESYNTH))						{							wcscat(name_mbs,WASABI_API_LNGSTRINGW(IDS_WITH_OUTPUT));							info+=WASABI_API_LNGSTRINGW(IDS_USES_WINAMPS_OUTPUT_PLUGINS);							add_device(new MIDI_device_dmusic(dmpc.guidPort,1,dmpc.dwFlags,name_mbs,info));						}					}				}				pDM->Release();			} 		} catch(...) {			// bewm.			reset_devices();		}	}	virtual const wchar_t * get_name() {return L"DirectMusic";}	virtual GUID get_guid() {return dmusic_driver_guid;}public:	MIDI_driver_dmusic() {dm_inited=0;}protected:	void do_deinit()	{		if (!dm_inited) return;		if (pGM)		{			pGM->Release();			pGM=0;		}		if (pCDLS) {pCDLS->Release();pCDLS=0;}		if (pLoader) {pLoader->Release();pLoader=0;}		if (pPort) PortKill();		if (pDM)		{			pDM->Release();			pDM=0;		}		if (pPerf)		{			pPerf->CloseDown();			pPerf->Release();			pPerf=0;		}		CoUninitialize();	}};static MIDI_driver_dmusic midi_driver_dmusic;
 |