⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 midi.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 4 页
字号:
    TRACE("(%04X);\n", wDevID);    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;    MidiInDev[wDevID].state = 1;    MidiInDev[wDevID].startTime = GetTickCount();    return MMSYSERR_NOERROR;}/************************************************************************** *			midStop					[internal] */static DWORD midStop(WORD wDevID){    TRACE("(%04X);\n", wDevID);    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;    MidiInDev[wDevID].state = 0;    return MMSYSERR_NOERROR;}/*-----------------------------------------------------------------------*/typedef struct sVoice {    int			note;			/* 0 means not used */    int			channel;    unsigned		cntMark : 30,	                status : 2;#define sVS_UNUSED	0#define sVS_PLAYING	1#define sVS_SUSTAINED	2} sVoice;typedef struct sChannel {    int			program;    int			bender;    int			benderRange;    /* controlers */    int			bank;		/* CTL_BANK_SELECT */    int			volume;		/* CTL_MAIN_VOLUME */    int			balance;	/* CTL_BALANCE     */    int			expression;	/* CTL_EXPRESSION  */    int			sustain;	/* CTL_SUSTAIN     */    unsigned char	nrgPmtMSB;	/* Non register Parameters */    unsigned char	nrgPmtLSB;    unsigned char	regPmtMSB;	/* Non register Parameters */    unsigned char	regPmtLSB;} sChannel;typedef struct sFMextra {    unsigned		counter;    int			drumSetMask;    sChannel		channel[16];	/* MIDI has only 16 channels */    sVoice		voice[1];	/* dyn allocated according to sound card */    /* do not append fields below voice[1] since the size of this structure     * depends on the number of available voices on the FM synth...     */} sFMextra;extern	unsigned char midiFMInstrumentPatches[16 * 128];extern	unsigned char midiFMDrumsPatches     [16 * 128];/************************************************************************** * 			modFMLoad				[internal] */static int modFMLoad(int dev){    int				i;    struct sbi_instrument	sbi;    sbi.device = dev;    sbi.key = FM_PATCH;    memset(sbi.operators + 16, 0, 16);    for (i = 0; i < 128; i++) {	sbi.channel = i;	memcpy(sbi.operators, midiFMInstrumentPatches + i * 16, 16);	if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) {	    WARN("Couldn't write patch for instrument %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));	    return -1;	}    }    for (i = 0; i < 128; i++) {	sbi.channel = 128 + i;	memcpy(sbi.operators, midiFMDrumsPatches + i * 16, 16);	if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) {	    WARN("Couldn't write patch for drum %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));	    return -1;	}    }    return 0;}/************************************************************************** * 			modFMReset				[internal] */static	void modFMReset(WORD wDevID){    sFMextra*	extra   = (sFMextra*)MidiOutDev[wDevID].lpExtra;    sVoice* 	voice   = extra->voice;    sChannel*	channel = extra->channel;    int		i;    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {	if (voice[i].status != sVS_UNUSED) {	    SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);	}	SEQ_KEY_PRESSURE(wDevID, i, 127, 0);	SEQ_CONTROL(wDevID, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);	voice[i].note = 0;	voice[i].channel = -1;	voice[i].cntMark = 0;	voice[i].status = sVS_UNUSED;    }    for (i = 0; i < 16; i++) {	channel[i].program = 0;	channel[i].bender = 8192;	channel[i].benderRange = 2;	channel[i].bank = 0;	channel[i].volume = 127;	channel[i].balance = 64;	channel[i].expression = 0;	channel[i].sustain = 0;    }    extra->counter = 0;    extra->drumSetMask = 1 << 9; /* channel 10 is normally drums, sometimes 16 also */    SEQ_DUMPBUF();}#define		IS_DRUM_CHANNEL(_xtra, _chn)	((_xtra)->drumSetMask & (1 << (_chn)))/************************************************************************** * 				modGetDevCaps			[internal] */static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSA lpCaps, DWORD dwSize){    TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);    if (wDevID >= MODM_NumDevs)	return MMSYSERR_BADDEVICEID;    if (lpCaps == NULL) 	return MMSYSERR_INVALPARAM;    memcpy(lpCaps, &MidiOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));    return MMSYSERR_NOERROR;}/************************************************************************** * 			modOpen					[internal] */static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags){    TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);    if (lpDesc == NULL) {	WARN("Invalid Parameter !\n");	return MMSYSERR_INVALPARAM;    }    if (wDevID >= MODM_NumDevs) {	TRACE("MAX_MIDIOUTDRV reached !\n");	return MMSYSERR_BADDEVICEID;    }    if (MidiOutDev[wDevID].midiDesc.hMidi != 0) {	WARN("device already open !\n");	return MMSYSERR_ALLOCATED;    }    if (!MidiOutDev[wDevID].bEnabled) {	WARN("device disabled !\n");	return MIDIERR_NODEVICE;    }    if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {	WARN("bad dwFlags\n");	return MMSYSERR_INVALFLAG;    }    if (!MidiOutDev[wDevID].bEnabled) {	TRACE("disabled wDevID\n");	return MMSYSERR_NOTENABLED;    }    MidiOutDev[wDevID].lpExtra = 0;    switch (MidiOutDev[wDevID].caps.wTechnology) {    case MOD_FMSYNTH:	{	    void*	extra;            extra = HeapAlloc(GetProcessHeap(), 0,                              sizeof(struct sFMextra) +                              sizeof(struct sVoice) * (MidiOutDev[wDevID].caps.wVoices - 1));	    if (extra == 0) {		WARN("can't alloc extra data !\n");		return MMSYSERR_NOMEM;	    }	    MidiOutDev[wDevID].lpExtra = extra;	    if (midiOpenSeq() < 0) {		MidiOutDev[wDevID].lpExtra = 0;		HeapFree(GetProcessHeap(), 0, extra);		return MMSYSERR_ERROR;	    }	    if (modFMLoad(wDevID) < 0) {		midiCloseSeq();		MidiOutDev[wDevID].lpExtra = 0;		HeapFree(GetProcessHeap(), 0, extra);		return MMSYSERR_ERROR;	    }	    modFMReset(wDevID);	}	break;    case MOD_MIDIPORT:    case MOD_SYNTH:	if (midiOpenSeq() < 0) {	    return MMSYSERR_ALLOCATED;	}	break;    default:	WARN("Technology not supported (yet) %d !\n",	     MidiOutDev[wDevID].caps.wTechnology);	return MMSYSERR_NOTENABLED;    }    MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);    MidiOutDev[wDevID].lpQueueHdr = NULL;    MidiOutDev[wDevID].dwTotalPlayed = 0;    MidiOutDev[wDevID].bufsize = 0x3FFF;    MidiOutDev[wDevID].midiDesc = *lpDesc;    if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {	WARN("can't notify client !\n");	return MMSYSERR_INVALPARAM;    }    TRACE("Successful !\n");    return MMSYSERR_NOERROR;}/************************************************************************** * 			modClose				[internal] */static DWORD modClose(WORD wDevID){    int	ret = MMSYSERR_NOERROR;    TRACE("(%04X);\n", wDevID);    if (MidiOutDev[wDevID].midiDesc.hMidi == 0) {	WARN("device not opened !\n");	return MMSYSERR_ERROR;    }    /* FIXME: should test that no pending buffer is still in the queue for     * playing */    if (midiSeqFD == -1) {	WARN("can't close !\n");	return MMSYSERR_ERROR;    }    switch (MidiOutDev[wDevID].caps.wTechnology) {    case MOD_FMSYNTH:    case MOD_MIDIPORT:	midiCloseSeq();	break;    default:	WARN("Technology not supported (yet) %d !\n",	     MidiOutDev[wDevID].caps.wTechnology);	return MMSYSERR_NOTENABLED;    }    if (MidiOutDev[wDevID].lpExtra != 0) {        HeapFree(GetProcessHeap(), 0, MidiOutDev[wDevID].lpExtra);	MidiOutDev[wDevID].lpExtra = 0;    }    MidiOutDev[wDevID].bufsize = 0;    if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {	WARN("can't notify client !\n");	ret = MMSYSERR_INVALPARAM;    }    MidiOutDev[wDevID].midiDesc.hMidi = 0;    return ret;}/************************************************************************** * 			modData					[internal] */static DWORD modData(WORD wDevID, DWORD dwParam){    WORD	evt = LOBYTE(LOWORD(dwParam));    WORD	d1  = HIBYTE(LOWORD(dwParam));    WORD	d2  = LOBYTE(HIWORD(dwParam));    TRACE("(%04X, %08lX);\n", wDevID, dwParam);    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;    if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;    if (midiSeqFD == -1) {	WARN("can't play !\n");	return MIDIERR_NODEVICE;    }    switch (MidiOutDev[wDevID].caps.wTechnology) {    case MOD_FMSYNTH:	/* FIXME:	 *	- chorus depth controller is not used	 */	{	    sFMextra*	extra   = (sFMextra*)MidiOutDev[wDevID].lpExtra;	    sVoice* 	voice   = extra->voice;	    sChannel*	channel = extra->channel;	    int		chn = (evt & 0x0F);	    int		i, nv;	    switch (evt & 0xF0) {	    case MIDI_NOTEOFF:		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {				/* don't stop sustained notes */		    if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) {			voice[i].status = sVS_UNUSED;			SEQ_STOP_NOTE(wDevID, i, d1, d2);		    }		}		break;	    case MIDI_NOTEON:		if (d2 == 0) { /* note off if velocity == 0 */		    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {			/* don't stop sustained notes */			if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) {			    voice[i].status = sVS_UNUSED;			    SEQ_STOP_NOTE(wDevID, i, d1, 64);			}		    }		    break;		}		/* finding out in this order :		 *	- an empty voice		 *	- if replaying the same note on the same channel		 *	- the older voice (LRU)		 */		for (i = nv = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {		    if (voice[i].status == sVS_UNUSED ||			(voice[i].note == d1 && voice[i].channel == chn)) {			nv = i;			break;		    }		    if (voice[i].cntMark < voice[0].cntMark) {			nv = i;		    }		}		TRACE(		      "playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, "		      "bender=0x%02X, note=0x%02X, vel=0x%02X\n",		      nv, channel[chn].program,		      channel[chn].balance,		      channel[chn].volume,		      channel[chn].bender, d1, d2);		SEQ_SET_PATCH(wDevID, nv, IS_DRUM_CHANNEL(extra, chn) ?			      (128 + d1) : channel[chn].program);		SEQ_BENDER_RANGE(wDevID, nv, channel[chn].benderRange * 100);		SEQ_BENDER(wDevID, nv, channel[chn].bender);		SEQ_CONTROL(wDevID, nv, CTL_PAN, channel[chn].balance);		SEQ_CONTROL(wDevID, nv, CTL_EXPRESSION, channel[chn].expression);#if 0		/* FIXME: does not really seem to work on my SB card and		 * screws everything up... so lay it down		 */		SEQ_CONTROL(wDevID, nv, CTL_MAIN_VOLUME, channel[chn].volume);#endif		SEQ_START_NOTE(wDevID, nv, d1, d2);		voice[nv].status = channel[chn].sustain ? sVS_SUSTAINED : sVS_PLAYING;		voice[nv].note = d1;		voice[nv].channel = chn;		voice[nv].cntMark = extra->counter++;		break;	    case MIDI_KEY_PRESSURE:		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {		    if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1) {			SEQ_KEY_PRESSURE(wDevID, i, d1, d2);		    }		}		break;	    case MIDI_CTL_CHANGE:		switch (d1) {		case CTL_BANK_SELECT:	channel[chn].bank = d2;		break;		case CTL_MAIN_VOLUME:	channel[chn].volume = d2;	break;		case CTL_PAN:		channel[chn].balance = d2;	break;		case CTL_EXPRESSION:	channel[chn].expression = d2;	break;		case CTL_SUSTAIN:	channel[chn].sustain = d2;		    if (d2) {			for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {			    if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {				voice[i].status = sVS_SUSTAINED;			    }			}		    } else {			for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {			    if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn) {				voice[i].status = sVS_UNUSED;				SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);			    }			}		    }		    break;		case CTL_NONREG_PARM_NUM_LSB:	channel[chn].nrgPmtLSB = d2;	break;		case CTL_NONREG_PARM_NUM_MSB:	channel[chn].nrgPmtMSB = d2;	break;		case CTL_REGIST_PARM_NUM_LSB:	channel[chn].regPmtLSB = d2;	break;		case CTL_REGIST_PARM_NUM_MSB:	channel[chn].regPmtMSB = d2;	break;		case CTL_DATA_ENTRY:		    switch ((channel[chn].regPmtMSB << 8) | channel[chn].regPmtLSB) {		    case 0x0000:			if (channel[chn].benderRange != d2) {			    channel[chn].benderRange = d2;			    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -