mirror of
https://github.com/libretro/NP2kai.git
synced 2024-10-07 14:53:33 +00:00
815 lines
16 KiB
C
Executable File
815 lines
16 KiB
C
Executable File
#include "compiler.h"
|
|
|
|
#include "np2.h"
|
|
#include "commng.h"
|
|
#include "kdispwin.h"
|
|
#include "mimpidef.h"
|
|
#include "sound.h"
|
|
|
|
#include "sound/vermouth/vermouth.h"
|
|
|
|
#if defined(VERMOUTH_LIB)
|
|
extern MIDIMOD vermouth_module;
|
|
|
|
const char cmmidi_vermouth[] = "VERMOUTH";
|
|
#endif
|
|
|
|
#define MIDI_RESETWAIT 80000
|
|
|
|
const char cmmidi_midiout_device[] = "MIDI-OUT device";
|
|
const char cmmidi_midiin_device[] = "MIDI-IN device";
|
|
|
|
#define MIDIOUTS(a, b, c) (((c) << 16) + (b << 8) + (a))
|
|
#define MIDIOUTS2(a) ((a)[0] + ((a)[1] << 8))
|
|
#define MIDIOUTS3(a) ((a)[0] + ((a)[1] << 8) + ((a)[2] << 16))
|
|
|
|
const char *cmmidi_mdlname[] = {
|
|
"MT-32", "CM-32L", "CM-64",
|
|
"CM-300", "CM-500(LA)", "CM-500(GS)",
|
|
"SC-55", "SC-88", "LA",
|
|
"GM", "GS", "XG"
|
|
};
|
|
|
|
static const UINT8 EXCV_MTRESET[] = {
|
|
0xfe, 0xfe, 0xfe
|
|
};
|
|
static const UINT8 EXCV_GMRESET[] = {
|
|
0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7
|
|
};
|
|
static const UINT8 EXCV_GSRESET[] = {
|
|
0xf0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7
|
|
};
|
|
static const UINT8 EXCV_XGRESET[] = {
|
|
0xf0, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7
|
|
};
|
|
static const UINT8 EXCV_GMVOLUME[] = {
|
|
0xf0, 0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00, 0xf7
|
|
};
|
|
|
|
enum {
|
|
MIDI_EXCLUSIVE = 0xf0,
|
|
MIDI_TIMECODE = 0xf1,
|
|
MIDI_SONGPOS = 0xf2,
|
|
MIDI_SONGSELECT = 0xf3,
|
|
MIDI_TUNEREQUEST = 0xf6,
|
|
MIDI_EOX = 0xf7,
|
|
MIDI_TIMING = 0xf8,
|
|
MIDI_START = 0xfa,
|
|
MIDI_CONTINUE = 0xfb,
|
|
MIDI_STOP = 0xfc,
|
|
MIDI_ACTIVESENSE = 0xfe,
|
|
MIDI_SYSTEMRESET = 0xff
|
|
};
|
|
|
|
enum {
|
|
MIDI_BUFFER = (1 << 10),
|
|
MIDIIN_MAX = 4,
|
|
|
|
CMMIDI_MIDIOUT = 0x01,
|
|
CMMIDI_MIDIIN = 0x02,
|
|
CMMIDI_MIDIINSTART = 0x04,
|
|
CMMIDI_VERMOUTH = 0x08,
|
|
|
|
MIDICTRL_READY = 0,
|
|
MIDICTRL_2BYTES,
|
|
MIDICTRL_3BYTES,
|
|
MIDICTRL_EXCLUSIVE,
|
|
MIDICTRL_TIMECODE,
|
|
MIDICTRL_SYSTEM
|
|
};
|
|
|
|
struct _cmmidi;
|
|
typedef struct _cmmidi _CMMIDI;
|
|
typedef struct _cmmidi *CMMIDI;
|
|
|
|
typedef struct {
|
|
UINT8 prog;
|
|
UINT8 press;
|
|
UINT16 bend;
|
|
UINT8 ctrl[28];
|
|
} _MIDICH, *MIDICH;
|
|
|
|
struct _cmmidi {
|
|
int opened;
|
|
void (*outfn)(CMMIDI self, UINT32 msg, UINT cnt);
|
|
int hmidiin;
|
|
int hmidiout;
|
|
struct timeval hmidiout_nextstart;
|
|
MIDIHDL vermouth;
|
|
|
|
UINT midictrl;
|
|
UINT midisyscnt;
|
|
UINT mpos;
|
|
|
|
UINT8 midilast;
|
|
UINT8 midiexcvwait;
|
|
UINT8 midimodule;
|
|
|
|
UINT8 buffer[MIDI_BUFFER];
|
|
_MIDICH mch[16];
|
|
UINT8 excvbuf[MIDI_BUFFER];
|
|
|
|
UINT8 def_en;
|
|
MIMPIDEF def;
|
|
|
|
UINT recvpos;
|
|
UINT recvsize;
|
|
UINT8 recvbuf[MIDI_BUFFER];
|
|
UINT8 midiinbuf[MIDI_BUFFER];
|
|
|
|
#if defined(VAEG_FIX)
|
|
BYTE rsflag; // RS-232C bit5..RTS bit1..DTR
|
|
// ToDo: STATSAVEで保存するべき
|
|
#endif
|
|
};
|
|
|
|
static const UINT8 midictrltbl[] = {
|
|
0, 1, 5, 7, 10, 11, 64,
|
|
65, 66, 67, 84, 91, 93,
|
|
94, // for SC-88
|
|
71, 72, 73, 74 // for XG
|
|
};
|
|
|
|
static UINT8 midictrlindex[128];
|
|
|
|
|
|
// ----
|
|
|
|
static int
|
|
getmidiout(const UINT device, const char *midiout)
|
|
{
|
|
int hmidiout = -1;
|
|
char* devfile = NULL;
|
|
|
|
#if defined(SUPPORT_SMPU98)
|
|
switch(device) {
|
|
case COMCREATE_MPU98II:
|
|
devfile = np2oscfg.MIDIDEV[0];
|
|
break;
|
|
case COMCREATE_SMPU98_A:
|
|
devfile = np2oscfg.MIDIDEVA[0];
|
|
break;
|
|
case COMCREATE_SMPU98_B:
|
|
devfile = np2oscfg.MIDIDEVB[0];
|
|
break;
|
|
}
|
|
#else
|
|
devfile = np2oscfg.MIDIDEV[0];
|
|
#endif
|
|
|
|
if (midiout && midiout[0] != '\0') {
|
|
if ((!milstr_cmp(midiout, cmmidi_midiout_device))
|
|
&& (devfile[0] != '\0')) {
|
|
hmidiout = open(devfile, O_WRONLY | O_NONBLOCK);
|
|
if (hmidiout < 0) {
|
|
perror("getmidiout");
|
|
}
|
|
}
|
|
}
|
|
return hmidiout;
|
|
}
|
|
|
|
static int
|
|
getmidiin(const UINT device, const char *midiin)
|
|
{
|
|
int hmidiin = -1;
|
|
char* devfile = NULL;
|
|
|
|
#if defined(SUPPORT_SMPU98)
|
|
switch(device) {
|
|
case COMCREATE_MPU98II:
|
|
devfile = np2oscfg.MIDIDEV[1];
|
|
break;
|
|
case COMCREATE_SMPU98_A:
|
|
devfile = np2oscfg.MIDIDEVA[1];
|
|
break;
|
|
case COMCREATE_SMPU98_B:
|
|
devfile = np2oscfg.MIDIDEVB[1];
|
|
break;
|
|
}
|
|
#else
|
|
devfile = np2oscfg.MIDIDEV[1];
|
|
#endif
|
|
|
|
if (midiin && midiin[0] != '\0') {
|
|
if ((!milstr_cmp(midiin, cmmidi_midiin_device))
|
|
&& (devfile[0] != '\0')) {
|
|
hmidiin = open(devfile, O_RDONLY | O_NONBLOCK);
|
|
if (hmidiin < 0) {
|
|
perror("getmidiin");
|
|
}
|
|
}
|
|
}
|
|
return hmidiin;
|
|
}
|
|
|
|
static UINT
|
|
module2number(const char *module)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NELEMENTS(cmmidi_mdlname); i++) {
|
|
if (milstr_extendcmp(module, cmmidi_mdlname[i])) {
|
|
return i;
|
|
}
|
|
}
|
|
return MIDI_OTHER;
|
|
}
|
|
|
|
static INLINE void
|
|
midi_write(CMMIDI midi, const UINT8 *cmd, UINT cnt)
|
|
{
|
|
struct timeval ct;
|
|
int ds, du;
|
|
int rv;
|
|
UINT i;
|
|
|
|
for (;;) {
|
|
gettimeofday(&ct, NULL);
|
|
ds = ct.tv_sec - midi->hmidiout_nextstart.tv_sec;
|
|
if (ds > 0)
|
|
break;
|
|
du = ct.tv_usec - midi->hmidiout_nextstart.tv_usec;
|
|
if ((ds == 0) && (du >= 0))
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
do {
|
|
rv = write(midi->hmidiout, cmd + i, 1);
|
|
} while (rv != 1);
|
|
}
|
|
|
|
gettimeofday(&midi->hmidiout_nextstart, NULL);
|
|
midi->hmidiout_nextstart.tv_usec += np2oscfg.MIDIWAIT * cnt;
|
|
if ((memcmp(cmd, EXCV_GMRESET, sizeof(EXCV_GMRESET)) == 0)
|
|
|| (memcmp(cmd, EXCV_GSRESET, sizeof(EXCV_GSRESET)) == 0)
|
|
|| (memcmp(cmd, EXCV_XGRESET, sizeof(EXCV_XGRESET)) == 0)
|
|
|| (memcmp(cmd, EXCV_MTRESET, sizeof(EXCV_MTRESET)) == 0)) {
|
|
midi->hmidiout_nextstart.tv_usec += MIDI_RESETWAIT;
|
|
}
|
|
while (midi->hmidiout_nextstart.tv_usec >= 1000000) {
|
|
midi->hmidiout_nextstart.tv_usec -= 1000000;
|
|
midi->hmidiout_nextstart.tv_sec++;
|
|
}
|
|
}
|
|
|
|
#if 1
|
|
#define waitlastexclusiveout(midip) midip->midiexcvwait = 0
|
|
#else
|
|
static void
|
|
waitlastexclusiveout(CMMIDI midi)
|
|
{
|
|
struct timeval ct;
|
|
int ds, du;
|
|
|
|
if (midi->midiexcvwait) {
|
|
for (;;) {
|
|
gettimeofday(&ct, NULL);
|
|
ds = ct.tv_sec - midi->hmidiout_nextstart.tv_sec;
|
|
if (ds > 0)
|
|
break;
|
|
du = ct.tv_usec - midi->hmidiout_nextstart.tv_usec;
|
|
if ((ds == 0) && (du >= 0))
|
|
break;
|
|
}
|
|
midi->midiexcvwait = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
sendexclusive(CMMIDI midi, const UINT8 *buf, UINT leng)
|
|
{
|
|
|
|
CopyMemory(midi->excvbuf, buf, leng);
|
|
midi_write(midi, midi->excvbuf, leng);
|
|
midi->midiexcvwait = 1;
|
|
}
|
|
|
|
static void
|
|
midiout_none(CMMIDI midi, UINT32 msg, UINT cnt)
|
|
{
|
|
|
|
/* Nothing to do */
|
|
}
|
|
|
|
static void
|
|
midiout_device(CMMIDI midi, UINT32 msg, UINT cnt)
|
|
{
|
|
UINT8 buf[3];
|
|
UINT i;
|
|
|
|
for (i = 0; i < cnt; i++, msg >>= 8) {
|
|
buf[i] = msg & 0xff;
|
|
}
|
|
waitlastexclusiveout(midi);
|
|
midi_write(midi, buf, cnt);
|
|
}
|
|
|
|
#if defined(VERMOUTH_LIB)
|
|
static void
|
|
midiout_vermouth(CMMIDI midi, UINT32 msg, UINT cnt)
|
|
{
|
|
|
|
sound_sync();
|
|
midiout_shortmsg(midi->vermouth, msg);
|
|
}
|
|
|
|
static void SOUNDCALL
|
|
vermouth_getpcm(MIDIHDL hdl, SINT32 *pcm, UINT count)
|
|
{
|
|
const SINT32 *ptr;
|
|
UINT size;
|
|
|
|
while (count) {
|
|
size = count;
|
|
ptr = midiout_get(hdl, &size);
|
|
if (ptr == NULL) {
|
|
break;
|
|
}
|
|
count -= size;
|
|
do {
|
|
pcm[0] += ptr[0];
|
|
pcm[1] += ptr[1];
|
|
ptr += 2;
|
|
pcm += 2;
|
|
} while (--size);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
midireset(CMMIDI midi)
|
|
{
|
|
const UINT8 *excv;
|
|
UINT excvsize;
|
|
UINT8 work[4];
|
|
|
|
switch (midi->midimodule) {
|
|
case MIDI_GM:
|
|
excv = EXCV_GMRESET;
|
|
excvsize = sizeof(EXCV_GMRESET);
|
|
break;
|
|
|
|
case MIDI_CM300:
|
|
case MIDI_CM500GS:
|
|
case MIDI_SC55:
|
|
case MIDI_SC88:
|
|
case MIDI_GS:
|
|
excv = EXCV_GSRESET;
|
|
excvsize = sizeof(EXCV_GSRESET);
|
|
break;
|
|
|
|
case MIDI_XG:
|
|
excv = EXCV_XGRESET;
|
|
excvsize = sizeof(EXCV_XGRESET);
|
|
break;
|
|
|
|
case MIDI_MT32:
|
|
case MIDI_CM32L:
|
|
case MIDI_CM64:
|
|
case MIDI_CM500LA:
|
|
case MIDI_LA:
|
|
excv = EXCV_MTRESET;
|
|
excvsize = sizeof(EXCV_MTRESET);
|
|
break;
|
|
|
|
default:
|
|
excv = NULL;
|
|
excvsize = 0;
|
|
break;
|
|
}
|
|
if (excv) {
|
|
if (midi->opened & CMMIDI_MIDIOUT) {
|
|
waitlastexclusiveout(midi);
|
|
sendexclusive(midi, excv, excvsize);
|
|
}
|
|
#if defined(VERMOUTH_LIB)
|
|
else if (midi->opened & CMMIDI_VERMOUTH) {
|
|
midiout_longmsg(midi->vermouth, excv, excvsize);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
work[1] = 0x7b;
|
|
work[2] = 0x00;
|
|
for (work[0] = 0xb0; work[0] < 0xc0; work[0]++) {
|
|
keydisp_midi(work);
|
|
(*midi->outfn)(midi, MIDIOUTS3(work), 3);
|
|
}
|
|
}
|
|
|
|
static void
|
|
midisetparam(CMMIDI midi)
|
|
{
|
|
MIDICH mch;
|
|
UINT i, j;
|
|
|
|
mch = midi->mch;
|
|
sound_sync();
|
|
for (i = 0; i < 16; i++, mch++) {
|
|
if (mch->press != 0xff) {
|
|
(*midi->outfn)(midi, MIDIOUTS(0xa0+i, mch->press, 0),3);
|
|
}
|
|
if (mch->bend != 0xffff) {
|
|
(*midi->outfn)(midi, (mch->bend << 8) + 0xe0+i, 3);
|
|
}
|
|
for (j = 0; j < sizeof(midictrltbl) / sizeof(UINT8); j++) {
|
|
if (mch->ctrl[j+1] != 0xff) {
|
|
(*midi->outfn)(midi, MIDIOUTS(0xb0+i, midictrltbl[j], mch->ctrl[j+1]), 3);
|
|
}
|
|
}
|
|
if (mch->prog != 0xff) {
|
|
(*midi->outfn)(midi, MIDIOUTS(0xc0+i, mch->prog, 0), 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ----
|
|
|
|
static UINT
|
|
midiread(COMMNG self, UINT8 *data)
|
|
{
|
|
CMMIDI midi = (CMMIDI)(self + 1);
|
|
|
|
if (midi->recvsize > 0) {
|
|
midi->recvsize--;
|
|
*data = midi->recvbuf[midi->recvpos];
|
|
midi->recvpos = (midi->recvpos + 1) & (MIDI_BUFFER - 1);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static UINT
|
|
midiwrite(COMMNG self, UINT8 data)
|
|
{
|
|
CMMIDI midi;
|
|
MIDICH mch;
|
|
int type;
|
|
|
|
midi = (CMMIDI)(self + 1);
|
|
switch (data) {
|
|
case MIDI_TIMING:
|
|
case MIDI_START:
|
|
case MIDI_CONTINUE:
|
|
case MIDI_STOP:
|
|
case MIDI_ACTIVESENSE:
|
|
case MIDI_SYSTEMRESET:
|
|
return 1;
|
|
}
|
|
if (midi->midictrl == MIDICTRL_READY) {
|
|
if (data & 0x80) {
|
|
midi->mpos = 0;
|
|
switch (data & 0xf0) {
|
|
case 0xc0:
|
|
case 0xd0:
|
|
midi->midictrl = MIDICTRL_2BYTES;
|
|
midi->midilast = data;
|
|
break;
|
|
|
|
case 0x80:
|
|
case 0x90:
|
|
case 0xa0:
|
|
case 0xb0:
|
|
case 0xe0:
|
|
midi->midictrl = MIDICTRL_3BYTES;
|
|
midi->midilast = data;
|
|
break;
|
|
|
|
default:
|
|
switch (data) {
|
|
case MIDI_EXCLUSIVE:
|
|
midi->midictrl = MIDICTRL_EXCLUSIVE;
|
|
break;
|
|
|
|
case MIDI_TIMECODE:
|
|
midi->midictrl = MIDICTRL_TIMECODE;
|
|
break;
|
|
|
|
case MIDI_SONGPOS:
|
|
midi->midictrl = MIDICTRL_SYSTEM;
|
|
midi->midisyscnt = 3;
|
|
break;
|
|
|
|
case MIDI_SONGSELECT:
|
|
midi->midictrl = MIDICTRL_SYSTEM;
|
|
midi->midisyscnt = 2;
|
|
break;
|
|
|
|
case MIDI_TUNEREQUEST:
|
|
midi->midictrl = MIDICTRL_SYSTEM;
|
|
midi->midisyscnt = 1;
|
|
break;
|
|
|
|
#if 0
|
|
case MIDI_EOX:
|
|
#endif
|
|
default:
|
|
return(1);
|
|
}
|
|
break;
|
|
}
|
|
} else { /* Key-onのみな気がしたんだけど忘れた… */
|
|
/* running status */
|
|
midi->buffer[0] = midi->midilast;
|
|
midi->mpos = 1;
|
|
switch (midi->midilast & 0xf0)
|
|
{
|
|
case 0xc0:
|
|
case 0xd0:
|
|
midi->midictrl = MIDICTRL_2BYTES;
|
|
break;
|
|
|
|
case 0x80:
|
|
case 0x90:
|
|
case 0xa0:
|
|
case 0xb0:
|
|
case 0xe0:
|
|
midi->midictrl = MIDICTRL_3BYTES;
|
|
break;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
midi->buffer[midi->mpos] = data;
|
|
midi->mpos++;
|
|
|
|
switch (midi->midictrl) {
|
|
case MIDICTRL_2BYTES:
|
|
if (midi->mpos >= 2) {
|
|
midi->buffer[1] &= 0x7f;
|
|
mch = midi->mch + (midi->buffer[0] & 0xf);
|
|
switch (midi->buffer[0] & 0xf0) {
|
|
case 0xa0:
|
|
mch->press = midi->buffer[1];
|
|
break;
|
|
|
|
case 0xc0:
|
|
if (midi->def_en) {
|
|
type = midi->def.ch[midi->buffer[0] & 0x0f];
|
|
if (type < MIMPI_RHYTHM) {
|
|
midi->buffer[1] = midi->def.map[type][midi->buffer[1]];
|
|
}
|
|
}
|
|
mch->prog = midi->buffer[1];
|
|
break;
|
|
}
|
|
keydisp_midi(midi->buffer);
|
|
(*midi->outfn)(midi, MIDIOUTS2(midi->buffer), 2);
|
|
midi->midictrl = MIDICTRL_READY;
|
|
return 2;
|
|
}
|
|
break;
|
|
|
|
case MIDICTRL_3BYTES:
|
|
if (midi->mpos >= 3) {
|
|
midi->buffer[1] &= 0x7f;
|
|
midi->buffer[2] &= 0x7f;
|
|
mch = midi->mch + (midi->buffer[0] & 0xf);
|
|
switch (midi->buffer[0] & 0xf0) {
|
|
case 0xb0:
|
|
if (midi->buffer[1] == 123) {
|
|
mch->press = 0;
|
|
mch->bend = 0x4000;
|
|
mch->ctrl[1+1] = 0; // Modulation
|
|
mch->ctrl[5+1] = 127; // Explession
|
|
mch->ctrl[6+1] = 0; // Hold
|
|
mch->ctrl[7+1] = 0; // Portament
|
|
mch->ctrl[8+1] = 0; // Sostenute
|
|
mch->ctrl[9+1] = 0; // Soft
|
|
} else {
|
|
mch->ctrl[midictrlindex[midi->buffer[1]]] = midi->buffer[2];
|
|
}
|
|
break;
|
|
|
|
case 0xe0:
|
|
mch->bend = LOADINTELWORD(midi->buffer + 1);
|
|
break;
|
|
}
|
|
keydisp_midi(midi->buffer);
|
|
(*midi->outfn)(midi, MIDIOUTS3(midi->buffer), 3);
|
|
midi->midictrl = MIDICTRL_READY;
|
|
return 3;
|
|
}
|
|
break;
|
|
|
|
case MIDICTRL_EXCLUSIVE:
|
|
if (data == MIDI_EOX) {
|
|
if (midi->opened & CMMIDI_MIDIOUT) {
|
|
waitlastexclusiveout(midi);
|
|
sendexclusive(midi, midi->buffer, midi->mpos);
|
|
}
|
|
#if defined(VERMOUTH_LIB)
|
|
else if (midi->opened & CMMIDI_VERMOUTH) {
|
|
midiout_longmsg(midi->vermouth, midi->buffer, midi->mpos);
|
|
}
|
|
#endif
|
|
midi->midictrl = MIDICTRL_READY;
|
|
return midi->mpos;
|
|
} else if (midi->mpos >= MIDI_BUFFER) { // おーばーふろー
|
|
midi->midictrl = MIDICTRL_READY;
|
|
}
|
|
break;
|
|
|
|
case MIDICTRL_TIMECODE:
|
|
if (midi->mpos >= 2) {
|
|
if ((data == 0x7e) || (data == 0x7f)) {
|
|
// exclusiveと同じでいい筈…
|
|
midi->midictrl = MIDICTRL_EXCLUSIVE;
|
|
} else {
|
|
midi->midictrl = MIDICTRL_READY;
|
|
return 2;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MIDICTRL_SYSTEM:
|
|
if (midi->mpos >= midi->midisyscnt) {
|
|
midi->midictrl = MIDICTRL_READY;
|
|
return midi->midisyscnt;
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static UINT8
|
|
midigetstat(COMMNG self)
|
|
{
|
|
|
|
return 0x00;
|
|
}
|
|
|
|
static INTPTR
|
|
midimsg(COMMNG self, UINT msg, INTPTR param)
|
|
{
|
|
CMMIDI midi;
|
|
COMFLAG flag;
|
|
|
|
midi = (CMMIDI)(self + 1);
|
|
switch (msg) {
|
|
case COMMSG_MIDIRESET:
|
|
midireset(midi);
|
|
return 1;
|
|
|
|
case COMMSG_SETFLAG:
|
|
flag = (COMFLAG)param;
|
|
if ((flag) &&
|
|
(flag->size == sizeof(_COMFLAG) + sizeof(midi->mch)) &&
|
|
(flag->sig == COMSIG_MIDI)) {
|
|
CopyMemory(midi->mch, flag + 1, sizeof(midi->mch));
|
|
midisetparam(midi);
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
case COMMSG_GETFLAG:
|
|
flag = (COMFLAG)_MALLOC(sizeof(_COMFLAG) + sizeof(midi->mch), "MIDI FLAG");
|
|
if (flag) {
|
|
flag->size = sizeof(_COMFLAG) + sizeof(midi->mch);
|
|
flag->sig = COMSIG_MIDI;
|
|
flag->ver = 0;
|
|
flag->param = 0;
|
|
CopyMemory(flag + 1, midi->mch, sizeof(midi->mch));
|
|
return (INTPTR)flag;
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
midirelease(COMMNG self)
|
|
{
|
|
CMMIDI midi;
|
|
|
|
midi = (CMMIDI)(self + 1);
|
|
if (midi->opened & CMMIDI_MIDIIN) {
|
|
if (midi->opened & CMMIDI_MIDIINSTART) {
|
|
/* XXX */
|
|
}
|
|
close(midi->hmidiin);
|
|
}
|
|
if (midi->opened & CMMIDI_MIDIOUT) {
|
|
waitlastexclusiveout(midi);
|
|
close(midi->hmidiout);
|
|
}
|
|
#if defined(VERMOUTH_LIB)
|
|
if (midi->opened & CMMIDI_VERMOUTH) {
|
|
midiout_destroy(midi->vermouth);
|
|
}
|
|
#endif
|
|
_MFREE(self);
|
|
}
|
|
|
|
|
|
// ----
|
|
|
|
void
|
|
cmmidi_initailize(void)
|
|
{
|
|
UINT i;
|
|
|
|
ZeroMemory(midictrlindex, sizeof(midictrlindex));
|
|
for (i = 0; i < sizeof(midictrltbl) / sizeof(UINT8); i++) {
|
|
midictrlindex[midictrltbl[i]] = (UINT8)(i + 1);
|
|
}
|
|
midictrlindex[32] = 1;
|
|
}
|
|
|
|
COMMNG
|
|
cmmidi_create(const UINT device, const char *midiout, const char *midiin, const char *module)
|
|
{
|
|
COMMNG ret;
|
|
CMMIDI midi;
|
|
void (*outfn)(CMMIDI midi, UINT32 msg, UINT cnt);
|
|
int hmidiout;
|
|
int hmidiin;
|
|
#if defined(VERMOUTH_LIB)
|
|
MIDIHDL vermouth = NULL;
|
|
#endif
|
|
int opened = 0;
|
|
|
|
/* MIDI-IN */
|
|
hmidiin = getmidiin(device, midiin);
|
|
if (hmidiin >= 0) {
|
|
opened |= CMMIDI_MIDIIN;
|
|
}
|
|
|
|
/* MIDI-OUT */
|
|
outfn = midiout_none;
|
|
hmidiout = getmidiout(device, midiout);
|
|
if (hmidiout >= 0) {
|
|
outfn = midiout_device;
|
|
opened |= CMMIDI_MIDIOUT;
|
|
}
|
|
#if defined(VERMOUTH_LIB)
|
|
else if (!milstr_cmp(midiout, cmmidi_vermouth)) {
|
|
vermouth = midiout_create(vermouth_module, 512);
|
|
if (vermouth != NULL) {
|
|
outfn = midiout_vermouth;
|
|
opened |= CMMIDI_VERMOUTH;
|
|
}
|
|
}
|
|
#endif
|
|
if (!opened) {
|
|
goto cmcre_err1;
|
|
}
|
|
ret = (COMMNG)_MALLOC(sizeof(_COMMNG) + sizeof(_CMMIDI), "MIDI");
|
|
if (ret == NULL) {
|
|
goto cmcre_err2;
|
|
}
|
|
ret->connect = COMCONNECT_MIDI;
|
|
ret->read = midiread;
|
|
ret->write = midiwrite;
|
|
ret->getstat = midigetstat;
|
|
ret->msg = midimsg;
|
|
ret->release = midirelease;
|
|
|
|
midi = (CMMIDI)(ret + 1);
|
|
ZeroMemory(midi, sizeof(_CMMIDI));
|
|
midi->opened = opened;
|
|
midi->outfn = outfn;
|
|
midi->midictrl = MIDICTRL_READY;
|
|
midi->hmidiout = hmidiout;
|
|
if (opened & CMMIDI_MIDIOUT) {
|
|
gettimeofday(&midi->hmidiout_nextstart, NULL);
|
|
}
|
|
#if defined(VERMOUTH_LIB)
|
|
midi->vermouth = vermouth;
|
|
if (opened & CMMIDI_VERMOUTH) {
|
|
sound_streamregist((void *)vermouth, (SOUNDCB)vermouth_getpcm);
|
|
}
|
|
#endif
|
|
midi->midilast = 0x80;
|
|
midi->midimodule = (UINT8)module2number(module);
|
|
FillMemory(midi->mch, sizeof(midi->mch), 0xff);
|
|
return ret;
|
|
|
|
cmcre_err2:
|
|
if (opened & CMMIDI_MIDIIN) {
|
|
if (hmidiin >= 0) {
|
|
close(hmidiin);
|
|
}
|
|
}
|
|
if (opened & CMMIDI_MIDIOUT) {
|
|
if (hmidiout >= 0) {
|
|
close(hmidiout);
|
|
}
|
|
}
|
|
#if defined(VERMOUTH_LIB)
|
|
if (opened & CMMIDI_VERMOUTH) {
|
|
midiout_destroy(vermouth);
|
|
}
|
|
#endif
|
|
cmcre_err1:
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// ---- midiin callback
|