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

📄 midi.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * Sample MIDI Wine Driver for ALSA (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 * Copyright 2003      Christian Costa : *                     ALSA port * * 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 * * TODO: Finish midi record * */#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>#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winuser.h"#include "mmddk.h"#ifdef HAVE_ALSA# include "alsa.h"#endif#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(midi);#if defined(HAVE_ALSA) && ((SND_LIB_MAJOR == 0 && SND_LIB_MINOR >= 9) || SND_LIB_MAJOR >= 1)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;    snd_seq_addr_t      addr;} 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;    snd_seq_addr_t      addr;} 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 total number of MIDI out devices found */static	int 		MIDM_NumDevs = 0;static	snd_seq_t*      midiSeq = NULL;static	int		numOpenMidiSeq = 0;static	UINT		midiInTimerID = 0;static	int		numStartedMidiIn = 0;int port_in;int port_out;/*======================================================================* *                  Low level MIDI implementation			* *======================================================================*/static int midiOpenSeq(int);static int midiCloseSeq(void);#if 0 /* Debug Purpose */static void error_handler(const char* file, int line, const char* function, int err, const char* fmt, ...){    va_list arg;    if (err == ENOENT)        return;    va_start(arg, fmt);    fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function);    vfprintf(stderr, fmt, arg);    if (err)        fprintf(stderr, ": %s", snd_strerror(err));    putc('\n', stderr);    va_end(arg);}#endif/************************************************************************** * 			MIDI_unixToWindowsDeviceType  		[internal] * * return the Windows equivalent to a Unix Device Type * */static	int 	MIDI_AlsaToWindowsDeviceType(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 ALSA to       Windows Sound type */    if (type & SND_SEQ_PORT_TYPE_SYNTH)        return MOD_FMSYNTH;    if (type & (SND_SEQ_PORT_TYPE_DIRECT_SAMPLE|SND_SEQ_PORT_TYPE_SAMPLE))        return MOD_SYNTH;    if (type & SND_SEQ_PORT_TYPE_MIDI_GENERIC)        return MOD_MIDIPORT;        ERR("Cannot determine the type of this midi device. Assuming FM Synth\n");    return MOD_FMSYNTH;}/************************************************************************** * 			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(int create_client){    if (numOpenMidiSeq == 0) {	if (snd_seq_open(&midiSeq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0)        {	    if (midi_warn)	    {		WARN("Error opening ALSA sequencer.\n");	    }	    midi_warn = 0;	    return -1;	}	if (create_client) {	    /* Setting the client name is the only init to do */	    snd_seq_set_client_name(midiSeq, "WINE midi driver");#if 0 /* FIXME: Is it possible to use a port for READ & WRITE ops */            port_in = port_out = snd_seq_create_simple_port(midiSeq, "WINE ALSA Input/Output", SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE,	             	                                                 SND_SEQ_PORT_TYPE_APPLICATION);            if (port_out < 0)               TRACE("Unable to create output port\n");            else	       TRACE("Outport port created successfully (%d)\n", port_out);#else            port_out = snd_seq_create_simple_port(midiSeq, "WINE ALSA Output", SND_SEQ_PORT_CAP_READ,	                 	                                                 SND_SEQ_PORT_TYPE_APPLICATION);	    if (port_out < 0)		TRACE("Unable to create output port\n");	    else		TRACE("Outport port created successfully (%d)\n", port_out);	    port_in = snd_seq_create_simple_port(midiSeq, "WINE ALSA Input", SND_SEQ_PORT_CAP_WRITE,	             	                                               SND_SEQ_PORT_TYPE_APPLICATION);            if (port_in < 0)                TRACE("Unable to create input port\n");            else	        TRACE("Input port created successfully (%d)\n", port_in);#endif       }    }    numOpenMidiSeq++;    return 0;}/************************************************************************** * 			midiCloseSeq				[internal] */static int midiCloseSeq(void){    if (--numOpenMidiSeq == 0) {	snd_seq_delete_simple_port(midiSeq, port_out);	snd_seq_delete_simple_port(midiSeq, port_in);	snd_seq_close(midiSeq);	midiSeq = NULL;    }    return 0;}static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime){    TRACE("(%p, %d, %d, %lu)\n", hwnd, msg, id, dwTime);    while(snd_seq_event_input_pending(midiSeq, 0) > 0) {	snd_seq_event_t* ev;	TRACE("An event is pending\n");	snd_seq_event_input(midiSeq, &ev);	TRACE("Event received, type = %d\n", ev->type);	snd_seq_free_event(ev);    }}/************************************************************************** * 				midGetDevCaps			[internal] */static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPSA lpCaps, DWORD dwSize){    TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;    if (lpCaps == NULL)		return MMSYSERR_INVALPARAM;    memcpy(lpCaps, &MidiInDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));    return MMSYSERR_NOERROR;}/************************************************************************** * 			midOpen					[internal] */static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags){    TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);    if (lpDesc == NULL) {	WARN("Invalid Parameter !\n");	return MMSYSERR_INVALPARAM;    }    /* FIXME :     *	how to check that content of lpDesc is correct ?     */    if (wDevID >= MIDM_NumDevs) {	WARN("wDevID too large (%u) !\n", wDevID);	return MMSYSERR_BADDEVICEID;    }    if (MidiInDev[wDevID].state == -1) {                WARN("device disabled\n");        return MIDIERR_NODEVICE;    }    if (MidiInDev[wDevID].midiDesc.hMidi != 0) {	WARN("device already open !\n");	return MMSYSERR_ALLOCATED;    }    if ((dwFlags & MIDI_IO_STATUS) != 0) {	WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n");	dwFlags &= ~MIDI_IO_STATUS;    }    if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {	FIXME("Bad dwFlags\n");	return MMSYSERR_INVALFLAG;    }    if (midiOpenSeq(1) < 0) {	return MMSYSERR_ERROR;    }    /* Connect our app port to the device port */    if (snd_seq_connect_from(midiSeq, port_in, MidiInDev[wDevID].addr.client, MidiInDev[wDevID].addr.port) < 0)	return MMSYSERR_NOTENABLED;    TRACE("input port connected %d %d %d\n",port_in,MidiInDev[wDevID].addr.client,MidiInDev[wDevID].addr.port);   if (numStartedMidiIn++ == 0) {	midiInTimerID = SetTimer(0, 0, 250, midTimeCallback);	if (!midiInTimerID) {	    numStartedMidiIn = 0;	    WARN("Couldn't start timer for midi-in\n");	    midiCloseSeq();	    return MMSYSERR_ERROR;	}	TRACE("Starting timer (%u) for midi-in\n", midiInTimerID);    }    MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);    MidiInDev[wDevID].lpQueueHdr = NULL;    MidiInDev[wDevID].dwTotalPlayed = 0;    MidiInDev[wDevID].bufsize = 0x3FFF;    MidiInDev[wDevID].midiDesc = *lpDesc;    MidiInDev[wDevID].state = 0;    MidiInDev[wDevID].incLen = 0;    MidiInDev[wDevID].startTime = 0;    if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {	WARN("can't notify client !\n");	return MMSYSERR_INVALPARAM;    }    return MMSYSERR_NOERROR;}/************************************************************************** * 			midClose				[internal] */static DWORD midClose(WORD wDevID){    int		ret = MMSYSERR_NOERROR;    TRACE("(%04X);\n", wDevID);    if (wDevID >= MIDM_NumDevs) {	WARN("wDevID too big (%u) !\n", wDevID);	return MMSYSERR_BADDEVICEID;    }    if (MidiInDev[wDevID].midiDesc.hMidi == 0) {	WARN("device not opened !\n");	return MMSYSERR_ERROR;    }    if (MidiInDev[wDevID].lpQueueHdr != 0) {	return MIDIERR_STILLPLAYING;    }    if (midiSeq == NULL) {	WARN("ooops !\n");	return MMSYSERR_ERROR;    }    if (--numStartedMidiIn == 0) {	TRACE("Stopping timer for midi-in\n");

⌨️ 快捷键说明

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