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

📄 midi.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 4 页
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * Sample MIDI Wine Driver for Open Sound System (basically Linux) * * Copyright 1994 	Martin Ayotte * Copyright 1998 	Luiz Otavio L. Zorzella (init procedures) * Copyright 1998/1999	Eric POUECH : * 		98/7 	changes for making this MIDI driver work on OSS * 			current support is limited to MIDI ports of OSS systems * 		98/9	rewriting MCI code for MIDI * 		98/11 	splitted in midi.c and mcimidi.c * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "config.h"#include <string.h>#include <stdarg.h>#include <stdio.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <fcntl.h>#include <errno.h>#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winuser.h"#include "mmddk.h"#include "oss.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(midi);#ifdef HAVE_OSS_MIDI#define MIDI_SEQ "/dev/sequencer"typedef struct {    int			state;                  /* -1 disabled, 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */    DWORD		bufsize;    MIDIOPENDESC	midiDesc;    WORD		wFlags;    LPMIDIHDR	 	lpQueueHdr;    DWORD		dwTotalPlayed;    unsigned char	incoming[3];    unsigned char	incPrev;    char		incLen;    DWORD		startTime;    MIDIINCAPSA         caps;} WINE_MIDIIN;typedef struct {    BOOL                bEnabled;    DWORD		bufsize;    MIDIOPENDESC	midiDesc;    WORD		wFlags;    LPMIDIHDR	 	lpQueueHdr;    DWORD		dwTotalPlayed;    void*		lpExtra;	 	/* according to port type (MIDI, FM...), extra data when needed */    MIDIOUTCAPSA        caps;} WINE_MIDIOUT;static WINE_MIDIIN	MidiInDev [MAX_MIDIINDRV ];static WINE_MIDIOUT	MidiOutDev[MAX_MIDIOUTDRV];/* this is the total number of MIDI out devices found (synth and port) */static	int 		MODM_NumDevs = 0;/* this is the number of FM synthetizers (index from 0 to NUMFMSYNTHDEVS - 1) */static	int		MODM_NumFMSynthDevs = 0;/* the Midi ports have index from NUMFMSYNTHDEVS to NumDevs - 1 *//* this is the total number of MIDI out devices found */static	int 		MIDM_NumDevs = 0;static	int		midiSeqFD = -1;static	int		numOpenMidiSeq = 0;static	UINT		midiInTimerID = 0;static	int		numStartedMidiIn = 0;/*======================================================================* *                  Low level MIDI implementation			* *======================================================================*/static int midiOpenSeq(void);static int midiCloseSeq(void);/************************************************************************** * 			MIDI_unixToWindowsDeviceType  		[internal] * * return the Windows equivalent to a Unix Device Type * */static	int 	MIDI_UnixToWindowsDeviceType(int type){    /* MOD_MIDIPORT     output port     * MOD_SYNTH        generic internal synth     * MOD_SQSYNTH      square wave internal synth     * MOD_FMSYNTH      FM internal synth     * MOD_MAPPER       MIDI mapper     * MOD_WAVETABLE    hardware watetable internal synth     * MOD_SWSYNTH      software internal synth     */    /* FIXME Is this really the correct equivalence from UNIX to       Windows Sound type */    switch (type) {    case SYNTH_TYPE_FM:     return MOD_FMSYNTH;    case SYNTH_TYPE_SAMPLE: return MOD_SYNTH;    case SYNTH_TYPE_MIDI:   return MOD_MIDIPORT;    default:	ERR("Cannot determine the type of this midi device. "	    "Assuming FM Synth\n");	return MOD_FMSYNTH;    }    return MOD_FMSYNTH;}/************************************************************************** * 			OSS_MidiInit				[internal] * * Initializes the MIDI devices information variables */BOOL OSS_MidiInit(void){    int 		i, status, numsynthdevs = 255, nummididevs = 255;    struct synth_info 	sinfo;    struct midi_info 	minfo;    static	BOOL	bInitDone = FALSE;    if (bInitDone)	return TRUE;    TRACE("Initializing the MIDI variables.\n");    bInitDone = TRUE;    /* try to open device */    if (midiOpenSeq() == -1) {	return TRUE;    }    /* find how many Synth devices are there in the system */    status = ioctl(midiSeqFD, SNDCTL_SEQ_NRSYNTHS, &numsynthdevs);    if (status == -1) {	ERR("ioctl for nr synth failed.\n");	midiCloseSeq();	return TRUE;    }    if (numsynthdevs > MAX_MIDIOUTDRV) {	ERR("MAX_MIDIOUTDRV (%d) was enough for the number of devices (%d). "	    "Some FM devices will not be available.\n",MAX_MIDIOUTDRV,numsynthdevs);	numsynthdevs = MAX_MIDIOUTDRV;    }    for (i = 0; i < numsynthdevs; i++) {	/* Manufac ID. We do not have access to this with soundcard.h	 * Does not seem to be a problem, because in mmsystem.h only	 * Microsoft's ID is listed.	 */	MidiOutDev[i].caps.wMid = 0x00FF;	MidiOutDev[i].caps.wPid = 0x0001; 	/* FIXME Product ID  */	/* Product Version. We simply say "1" */	MidiOutDev[i].caps.vDriverVersion = 0x001;	MidiOutDev[i].caps.wChannelMask   = 0xFFFF;	/* FIXME Do we have this information?	 * Assuming the soundcards can handle	 * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but	 * not MIDICAPS_CACHE.	 */	MidiOutDev[i].caps.dwSupport      = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;	sinfo.device = i;	status = ioctl(midiSeqFD, SNDCTL_SYNTH_INFO, &sinfo);	if (status == -1) {	    ERR("ioctl for synth info failed on %d, disabling it.\n", i);            sprintf(MidiOutDev[i].caps.szPname, "Wine OSS Midi Out (#%d) - disabled", i);            MidiOutDev[i].caps.wTechnology = MOD_MIDIPORT;            MidiOutDev[i].caps.wVoices     = 16;            MidiOutDev[i].caps.wNotes      = 16;            MidiOutDev[i].bEnabled = FALSE;	} else {            strcpy(MidiOutDev[i].caps.szPname, sinfo.name);            MidiOutDev[i].caps.wTechnology = MIDI_UnixToWindowsDeviceType(sinfo.synth_type);            MidiOutDev[i].caps.wVoices     = sinfo.nr_voices;            /* FIXME Is it possible to know the maximum             * number of simultaneous notes of a soundcard ?             * I believe we don't have this information, but             * it's probably equal or more than wVoices             */            MidiOutDev[i].caps.wNotes      = sinfo.nr_voices;            MidiOutDev[i].bEnabled = TRUE;        }	/* We also have the information sinfo.synth_subtype, not used here	 */	if (sinfo.capabilities & SYNTH_CAP_INPUT) {	    FIXME("Synthesizer support MIDI in. Not supported yet (please report)\n");	}	TRACE("SynthOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%ld\n"	      "\tOSS info: synth subtype=%d capa=%lx\n",	      i, MidiOutDev[i].caps.szPname, MidiOutDev[i].caps.wTechnology,               MidiOutDev[i].caps.wVoices, MidiOutDev[i].caps.wNotes,               MidiOutDev[i].caps.wChannelMask, MidiOutDev[i].caps.dwSupport,	      sinfo.synth_subtype, (long)sinfo.capabilities);    }    /* find how many MIDI devices are there in the system */    status = ioctl(midiSeqFD, SNDCTL_SEQ_NRMIDIS, &nummididevs);    if (status == -1) {	ERR("ioctl on nr midi failed.\n");        nummididevs = 0;        goto wrapup;    }    /* FIXME: the two restrictions below could be loosen in some cases */    if (numsynthdevs + nummididevs > MAX_MIDIOUTDRV) {	ERR("MAX_MIDIOUTDRV was not enough for the number of devices. "	    "Some MIDI devices will not be available.\n");	nummididevs = MAX_MIDIOUTDRV - numsynthdevs;    }    if (nummididevs > MAX_MIDIINDRV) {	ERR("MAX_MIDIINDRV (%d) was not enough for the number of devices (%d). "	    "Some MIDI devices will not be available.\n",MAX_MIDIINDRV,nummididevs);	nummididevs = MAX_MIDIINDRV;    }    for (i = 0; i < nummididevs; i++) {	minfo.device = i;	status = ioctl(midiSeqFD, SNDCTL_MIDI_INFO, &minfo);	if (status == -1) WARN("ioctl on midi info for device %d failed.\n", i);	/* This whole part is somewhat obscure to me. I'll keep trying to dig	   info about it. If you happen to know, please tell us. The very	   descritive minfo.dev_type was not used here.	*/	/* Manufac ID. We do not have access to this with soundcard.h	   Does not seem to be a problem, because in mmsystem.h only	   Microsoft's ID is listed */	MidiOutDev[numsynthdevs + i].caps.wMid = 0x00FF;	MidiOutDev[numsynthdevs + i].caps.wPid = 0x0001; 	/* FIXME Product ID */	/* Product Version. We simply say "1" */	MidiOutDev[numsynthdevs + i].caps.vDriverVersion = 0x001;        if (status == -1) {            sprintf(MidiOutDev[numsynthdevs + i].caps.szPname, "Wine OSS Midi Out (#%d) - disabled", numsynthdevs + i);            MidiOutDev[numsynthdevs + i].bEnabled = FALSE;        } else {            strcpy(MidiOutDev[numsynthdevs + i].caps.szPname, minfo.name);            MidiOutDev[numsynthdevs + i].bEnabled = TRUE;        }	MidiOutDev[numsynthdevs + i].caps.wTechnology = MOD_MIDIPORT; /* FIXME Is this right? */	/* Does it make any difference? */	MidiOutDev[numsynthdevs + i].caps.wVoices     = 16;	/* Does it make any difference? */	MidiOutDev[numsynthdevs + i].caps.wNotes      = 16;	MidiOutDev[numsynthdevs + i].caps.wChannelMask= 0xFFFF;	/* FIXME Does it make any difference? */	MidiOutDev[numsynthdevs + i].caps.dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;	/* This whole part is somewhat obscure to me. I'll keep trying to dig	   info about it. If you happen to know, please tell us. The very	   descritive minfo.dev_type was not used here.	*/	/* Manufac ID. We do not have access to this with soundcard.h	   Does not seem to be a problem, because in mmsystem.h only	   Microsoft's ID is listed */	MidiInDev[i].caps.wMid = 0x00FF;	MidiInDev[i].caps.wPid = 0x0001; 	/* FIXME Product ID */	/* Product Version. We simply say "1" */	MidiInDev[i].caps.vDriverVersion = 0x001;        if (status == -1) {            sprintf(MidiInDev[i].caps.szPname, "Wine OSS Midi In (#%d) - disabled", numsynthdevs + i);            MidiInDev[i].state = -1;        } else {            strcpy(MidiInDev[i].caps.szPname, minfo.name);            MidiInDev[i].state = 0;        }	/* FIXME : could we get better information than that ? */	MidiInDev[i].caps.dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;	TRACE("MidiOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%ld\n"              "MidiIn [%d]\tname='%s' support=%ld\n"	      "\tOSS info: midi dev-type=%d, capa=%lx\n",	      i, MidiOutDev[numsynthdevs + i].caps.szPname, MidiOutDev[numsynthdevs + i].caps.wTechnology,	      MidiOutDev[numsynthdevs + i].caps.wVoices, MidiOutDev[numsynthdevs + i].caps.wNotes,	      MidiOutDev[numsynthdevs + i].caps.wChannelMask, MidiOutDev[numsynthdevs + i].caps.dwSupport,	      i, MidiInDev[i].caps.szPname, MidiInDev[i].caps.dwSupport,	      minfo.dev_type, (long)minfo.capabilities);    } wrapup:    /* windows does not seem to differentiate Synth from MIDI devices */    MODM_NumFMSynthDevs = numsynthdevs;    MODM_NumDevs        = numsynthdevs + nummididevs;    MIDM_NumDevs        = nummididevs;    /* close file and exit */    midiCloseSeq();    return TRUE;}/************************************************************************** * 			MIDI_NotifyClient			[internal] */static DWORD MIDI_NotifyClient(UINT wDevID, WORD wMsg,			       DWORD dwParam1, DWORD dwParam2){    DWORD 		dwCallBack;    UINT 		uFlags;    HANDLE		hDev;    DWORD 		dwInstance;    TRACE("wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",	  wDevID, wMsg, dwParam1, dwParam2);    switch (wMsg) {    case MOM_OPEN:    case MOM_CLOSE:    case MOM_DONE:	if (wDevID > MODM_NumDevs)	    return MMSYSERR_BADDEVICEID;	dwCallBack = MidiOutDev[wDevID].midiDesc.dwCallback;	uFlags = MidiOutDev[wDevID].wFlags;	hDev = MidiOutDev[wDevID].midiDesc.hMidi;	dwInstance = MidiOutDev[wDevID].midiDesc.dwInstance;	break;    case MIM_OPEN:    case MIM_CLOSE:    case MIM_DATA:    case MIM_ERROR:	if (wDevID > MIDM_NumDevs)	    return MMSYSERR_BADDEVICEID;	dwCallBack = MidiInDev[wDevID].midiDesc.dwCallback;	uFlags = MidiInDev[wDevID].wFlags;	hDev = MidiInDev[wDevID].midiDesc.hMidi;	dwInstance = MidiInDev[wDevID].midiDesc.dwInstance;	break;    default:	WARN("Unsupported MSW-MIDI message %u\n", wMsg);	return MMSYSERR_ERROR;    }    return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2) ?	0 : MMSYSERR_ERROR;}static int midi_warn = 1;/************************************************************************** * 			midiOpenSeq				[internal] */static int midiOpenSeq(void){    if (numOpenMidiSeq == 0) {	midiSeqFD = open(MIDI_SEQ, O_RDWR, 0);	if (midiSeqFD == -1) {	    if (midi_warn)	    {		WARN("Can't open MIDI device '%s' ! (%s). If your "                        "program needs this (probably not): %s\n",			MIDI_SEQ, strerror(errno),			errno == ENOENT ?			"create it ! (\"man MAKEDEV\" ?)" :			errno == ENODEV ?			"load MIDI sequencer kernel driver !" :			errno == EACCES ?			"grant access ! (\"man chmod\")" : ""		);	    }	    midi_warn = 0;	    return -1;	}	if (fcntl(midiSeqFD, F_SETFL, O_NONBLOCK) < 0) {	    WARN("can't set sequencer fd to non-blocking, errno %d (%s)\n", errno, strerror(errno));	    close(midiSeqFD);	    midiSeqFD = -1;	    return -1;	}	fcntl(midiSeqFD, F_SETFD, 1); /* set close on exec flag */	ioctl(midiSeqFD, SNDCTL_SEQ_RESET);    }    numOpenMidiSeq++;    return 0;}/**************************************************************************

⌨️ 快捷键说明

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