mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-15 06:31:03 +00:00
wineoss: Move MODM_DATA to the unixlib.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Andrew Eikum <aeikum@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
4e90f801f9
commit
2cc89ecc10
|
@ -692,46 +692,6 @@ static DWORD midStop(WORD wDevID)
|
|||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
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;
|
||||
/* controllers */
|
||||
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;
|
||||
|
||||
#define IS_DRUM_CHANNEL(_xtra, _chn) ((_xtra)->drumSetMask & (1 << (_chn)))
|
||||
|
||||
/**************************************************************************
|
||||
* modGetDevCaps [internal]
|
||||
*/
|
||||
|
@ -747,295 +707,6 @@ static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSW lpCaps, DWORD dwSize)
|
|||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
static UINT midi_out_fm_data(WORD dev_id, UINT data)
|
||||
{
|
||||
struct midi_dest *dest = MidiOutDev + dev_id;
|
||||
WORD evt = LOBYTE(LOWORD(data));
|
||||
WORD d1 = HIBYTE(LOWORD(data));
|
||||
WORD d2 = LOBYTE(HIWORD(data));
|
||||
sFMextra *extra = dest->lpExtra;
|
||||
sVoice *voice = extra->voice;
|
||||
sChannel *channel = extra->channel;
|
||||
int chn = (evt & 0x0F), i, nv;
|
||||
|
||||
/* FIXME: chorus depth controller is not used */
|
||||
|
||||
switch (evt & 0xF0)
|
||||
{
|
||||
case MIDI_NOTEOFF:
|
||||
for (i = 0; i < dest->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(dev_id, i, d1, d2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MIDI_NOTEON:
|
||||
if (d2 == 0) /* note off if velocity == 0 */
|
||||
{
|
||||
for (i = 0; i < dest->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(dev_id, 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 < dest->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(dev_id, nv, IS_DRUM_CHANNEL(extra, chn) ?
|
||||
(128 + d1) : channel[chn].program);
|
||||
SEQ_BENDER_RANGE(dev_id, nv, channel[chn].benderRange * 100);
|
||||
SEQ_BENDER(dev_id, nv, channel[chn].bender);
|
||||
SEQ_CONTROL(dev_id, nv, CTL_PAN, channel[chn].balance);
|
||||
SEQ_CONTROL(dev_id, nv, CTL_EXPRESSION, channel[chn].expression);
|
||||
SEQ_START_NOTE(dev_id, 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 < dest->caps.wVoices; i++)
|
||||
if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1)
|
||||
SEQ_KEY_PRESSURE(dev_id, 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 < dest->caps.wVoices; i++)
|
||||
if (voice[i].status == sVS_PLAYING && voice[i].channel == chn)
|
||||
voice[i].status = sVS_SUSTAINED;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
{
|
||||
if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn)
|
||||
{
|
||||
voice[i].status = sVS_UNUSED;
|
||||
SEQ_STOP_NOTE(dev_id, 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 < dest->caps.wVoices; i++)
|
||||
if (voice[i].channel == chn)
|
||||
SEQ_BENDER_RANGE(dev_id, i, channel[chn].benderRange);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7F7F:
|
||||
channel[chn].benderRange = 2;
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
if (voice[i].channel == chn)
|
||||
SEQ_BENDER_RANGE(dev_id, i, channel[chn].benderRange);
|
||||
break;
|
||||
default:
|
||||
TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
|
||||
channel[chn].regPmtMSB, channel[chn].regPmtLSB,
|
||||
channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB, d2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x78: /* all sounds off */
|
||||
/* FIXME: I don't know if I have to take care of the channel for this control? */
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
{
|
||||
if (voice[i].status != sVS_UNUSED && voice[i].channel == chn)
|
||||
{
|
||||
voice[i].status = sVS_UNUSED;
|
||||
SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x7B: /* all notes off */
|
||||
/* FIXME: I don't know if I have to take care of the channel for this control? */
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
{
|
||||
if (voice[i].status == sVS_PLAYING && voice[i].channel == chn)
|
||||
{
|
||||
voice[i].status = sVS_UNUSED;
|
||||
SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n", d1, d2, chn);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MIDI_PGM_CHANGE:
|
||||
channel[chn].program = d1;
|
||||
break;
|
||||
case MIDI_CHN_PRESSURE:
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
if (voice[i].status != sVS_UNUSED && voice[i].channel == chn)
|
||||
SEQ_KEY_PRESSURE(dev_id, i, voice[i].note, d1);
|
||||
|
||||
break;
|
||||
case MIDI_PITCH_BEND:
|
||||
channel[chn].bender = (d2 << 7) + d1;
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
if (voice[i].channel == chn)
|
||||
SEQ_BENDER(dev_id, i, channel[chn].bender);
|
||||
break;
|
||||
case MIDI_SYSTEM_PREFIX:
|
||||
switch (evt & 0x0F)
|
||||
{
|
||||
case 0x0F: /* Reset */
|
||||
OSS_CALL(midi_out_fm_reset, (void *)(UINT_PTR)dev_id);
|
||||
break;
|
||||
default:
|
||||
WARN("Unsupported (yet) system event %02x\n", evt & 0x0F);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0);
|
||||
return MMSYSERR_NOTENABLED;
|
||||
}
|
||||
|
||||
SEQ_DUMPBUF();
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
static UINT midi_out_port_data(WORD dev_id, UINT data)
|
||||
{
|
||||
WORD evt = LOBYTE(LOWORD(data));
|
||||
WORD d1 = HIBYTE(LOWORD(data));
|
||||
WORD d2 = LOBYTE(HIWORD(data));
|
||||
int dev = dev_id - MODM_NumFMSynthDevs;
|
||||
|
||||
if (dev < 0)
|
||||
{
|
||||
WARN("Internal error on devID (%u) !\n", dev_id);
|
||||
return MIDIERR_NODEVICE;
|
||||
}
|
||||
|
||||
switch (evt & 0xF0)
|
||||
{
|
||||
case MIDI_NOTEOFF:
|
||||
case MIDI_NOTEON:
|
||||
case MIDI_KEY_PRESSURE:
|
||||
case MIDI_CTL_CHANGE:
|
||||
case MIDI_PITCH_BEND:
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
SEQ_MIDIOUT(dev, d1);
|
||||
SEQ_MIDIOUT(dev, d2);
|
||||
break;
|
||||
case MIDI_PGM_CHANGE:
|
||||
case MIDI_CHN_PRESSURE:
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
SEQ_MIDIOUT(dev, d1);
|
||||
break;
|
||||
case MIDI_SYSTEM_PREFIX:
|
||||
switch (evt & 0x0F)
|
||||
{
|
||||
case 0x00: /* System Exclusive, don't do it on MODM_DATA, should require MODM_LONGDATA */
|
||||
case 0x04: /* Undefined. */
|
||||
case 0x05: /* Undefined. */
|
||||
case 0x07: /* End of Exclusive. */
|
||||
case 0x09: /* Undefined. */
|
||||
case 0x0D: /* Undefined. */
|
||||
break;
|
||||
case 0x06: /* Tune Request */
|
||||
case 0x08: /* Timing Clock. */
|
||||
case 0x0A: /* Start. */
|
||||
case 0x0B: /* Continue */
|
||||
case 0x0C: /* Stop */
|
||||
case 0x0E: /* Active Sensing. */
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
break;
|
||||
case 0x0F: /* Reset */
|
||||
SEQ_MIDIOUT(dev, MIDI_SYSTEM_PREFIX);
|
||||
SEQ_MIDIOUT(dev, 0x7e);
|
||||
SEQ_MIDIOUT(dev, 0x7f);
|
||||
SEQ_MIDIOUT(dev, 0x09);
|
||||
SEQ_MIDIOUT(dev, 0x01);
|
||||
SEQ_MIDIOUT(dev, 0xf7);
|
||||
break;
|
||||
case 0x01: /* MTC Quarter frame */
|
||||
case 0x03: /* Song Select. */
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
SEQ_MIDIOUT(dev, d1);
|
||||
case 0x02: /* Song Position Pointer. */
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
SEQ_MIDIOUT(dev, d1);
|
||||
SEQ_MIDIOUT(dev, d2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SEQ_DUMPBUF();
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* modData [internal]
|
||||
*/
|
||||
static DWORD modData(WORD wDevID, DWORD dwParam)
|
||||
{
|
||||
TRACE("(%04X, %08X);\n", wDevID, dwParam);
|
||||
|
||||
if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
|
||||
if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;
|
||||
|
||||
if (MidiOutDev[wDevID].fd == -1) {
|
||||
WARN("can't play !\n");
|
||||
return MIDIERR_NODEVICE;
|
||||
}
|
||||
switch (MidiOutDev[wDevID].caps.wTechnology) {
|
||||
case MOD_FMSYNTH:
|
||||
return midi_out_fm_data(wDevID, dwParam);
|
||||
case MOD_MIDIPORT:
|
||||
return midi_out_port_data(wDevID, dwParam);
|
||||
}
|
||||
|
||||
WARN("Technology not supported (yet) %d !\n",
|
||||
MidiOutDev[wDevID].caps.wTechnology);
|
||||
return MMSYSERR_NOTENABLED;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* modLongData [internal]
|
||||
*/
|
||||
|
@ -1164,6 +835,9 @@ static DWORD modGetVolume(WORD wDevID, DWORD* lpdwVolume)
|
|||
return (MidiOutDev[wDevID].caps.dwSupport & MIDICAPS_VOLUME) ? 0 : MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
|
||||
DWORD_PTR dwParam1, DWORD_PTR dwParam2);
|
||||
|
||||
/**************************************************************************
|
||||
* modReset [internal]
|
||||
*/
|
||||
|
@ -1182,9 +856,9 @@ static DWORD modReset(WORD wDevID)
|
|||
*/
|
||||
for (chn = 0; chn < 16; chn++) {
|
||||
/* turn off every note */
|
||||
modData(wDevID, 0x7800 | MIDI_CTL_CHANGE | chn);
|
||||
OSS_modMessage(wDevID, MODM_DATA, 0, 0x7800 | MIDI_CTL_CHANGE | chn, 0);
|
||||
/* remove sustain on all channels */
|
||||
modData(wDevID, (CTL_SUSTAIN << 8) | MIDI_CTL_CHANGE | chn);
|
||||
OSS_modMessage(wDevID, MODM_DATA, 0, (CTL_SUSTAIN << 8) | MIDI_CTL_CHANGE | chn, 0);
|
||||
}
|
||||
/* FIXME: the LongData buffers must also be returned to the app */
|
||||
return MMSYSERR_NOERROR;
|
||||
|
@ -1255,8 +929,6 @@ DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
|
|||
return OSS_MidiInit();
|
||||
case DRVM_EXIT:
|
||||
return OSS_MidiExit();
|
||||
case MODM_DATA:
|
||||
return modData(wDevID, dwParam1);
|
||||
case MODM_LONGDATA:
|
||||
return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
|
||||
case MODM_PREPARE:
|
||||
|
|
|
@ -1409,5 +1409,4 @@ unixlib_entry_t __wine_unix_call_funcs[] =
|
|||
midi_out_message,
|
||||
|
||||
midi_seq_open,
|
||||
midi_out_fm_reset,
|
||||
};
|
||||
|
|
|
@ -93,6 +93,8 @@ typedef struct sFMextra
|
|||
*/
|
||||
} sFMextra;
|
||||
|
||||
#define IS_DRUM_CHANNEL(_xtra, _chn) ((_xtra)->drumSetMask & (1 << (_chn)))
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(midi);
|
||||
|
||||
static int oss_to_win_device_type(int type)
|
||||
|
@ -458,9 +460,8 @@ static int midi_out_fm_load(WORD dev_id, int fd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NTSTATUS midi_out_fm_reset(void *args)
|
||||
static void midi_out_fm_reset(WORD dev_id)
|
||||
{
|
||||
WORD dev_id = (WORD)(UINT_PTR)args;
|
||||
struct midi_dest *dest = dests + dev_id;
|
||||
sFMextra *extra = dest->lpExtra;
|
||||
sVoice *voice = extra->voice;
|
||||
|
@ -492,8 +493,6 @@ NTSTATUS midi_out_fm_reset(void *args)
|
|||
extra->counter = 0;
|
||||
extra->drumSetMask = 1 << 9; /* channel 10 is normally drums, sometimes 16 also */
|
||||
SEQ_DUMPBUF();
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void set_out_notify(struct notify_context *notify, struct midi_dest *dest, WORD dev_id, WORD msg,
|
||||
|
@ -572,7 +571,7 @@ static UINT midi_out_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, stru
|
|||
free(extra);
|
||||
return MMSYSERR_ERROR;
|
||||
}
|
||||
midi_out_fm_reset((void *)(UINT_PTR)dev_id);
|
||||
midi_out_fm_reset(dev_id);
|
||||
break;
|
||||
}
|
||||
case MOD_MIDIPORT:
|
||||
|
@ -645,6 +644,295 @@ static UINT midi_out_close(WORD dev_id, struct notify_context *notify)
|
|||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
static UINT midi_out_fm_data(WORD dev_id, UINT data)
|
||||
{
|
||||
struct midi_dest *dest = dests + dev_id;
|
||||
WORD evt = LOBYTE(LOWORD(data));
|
||||
WORD d1 = HIBYTE(LOWORD(data));
|
||||
WORD d2 = LOBYTE(HIWORD(data));
|
||||
sFMextra *extra = dest->lpExtra;
|
||||
sVoice *voice = extra->voice;
|
||||
sChannel *channel = extra->channel;
|
||||
int chn = (evt & 0x0F), i, nv;
|
||||
|
||||
/* FIXME: chorus depth controller is not used */
|
||||
|
||||
switch (evt & 0xF0)
|
||||
{
|
||||
case MIDI_NOTEOFF:
|
||||
for (i = 0; i < dest->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(dev_id, i, d1, d2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MIDI_NOTEON:
|
||||
if (d2 == 0) /* note off if velocity == 0 */
|
||||
{
|
||||
for (i = 0; i < dest->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(dev_id, 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 < dest->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(dev_id, nv, IS_DRUM_CHANNEL(extra, chn) ?
|
||||
(128 + d1) : channel[chn].program);
|
||||
SEQ_BENDER_RANGE(dev_id, nv, channel[chn].benderRange * 100);
|
||||
SEQ_BENDER(dev_id, nv, channel[chn].bender);
|
||||
SEQ_CONTROL(dev_id, nv, CTL_PAN, channel[chn].balance);
|
||||
SEQ_CONTROL(dev_id, nv, CTL_EXPRESSION, channel[chn].expression);
|
||||
SEQ_START_NOTE(dev_id, 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 < dest->caps.wVoices; i++)
|
||||
if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1)
|
||||
SEQ_KEY_PRESSURE(dev_id, 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 < dest->caps.wVoices; i++)
|
||||
if (voice[i].status == sVS_PLAYING && voice[i].channel == chn)
|
||||
voice[i].status = sVS_SUSTAINED;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
{
|
||||
if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn)
|
||||
{
|
||||
voice[i].status = sVS_UNUSED;
|
||||
SEQ_STOP_NOTE(dev_id, 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 < dest->caps.wVoices; i++)
|
||||
if (voice[i].channel == chn)
|
||||
SEQ_BENDER_RANGE(dev_id, i, channel[chn].benderRange);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7F7F:
|
||||
channel[chn].benderRange = 2;
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
if (voice[i].channel == chn)
|
||||
SEQ_BENDER_RANGE(dev_id, i, channel[chn].benderRange);
|
||||
break;
|
||||
default:
|
||||
TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
|
||||
channel[chn].regPmtMSB, channel[chn].regPmtLSB,
|
||||
channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB, d2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x78: /* all sounds off */
|
||||
/* FIXME: I don't know if I have to take care of the channel for this control? */
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
{
|
||||
if (voice[i].status != sVS_UNUSED && voice[i].channel == chn)
|
||||
{
|
||||
voice[i].status = sVS_UNUSED;
|
||||
SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x7B: /* all notes off */
|
||||
/* FIXME: I don't know if I have to take care of the channel for this control? */
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
{
|
||||
if (voice[i].status == sVS_PLAYING && voice[i].channel == chn)
|
||||
{
|
||||
voice[i].status = sVS_UNUSED;
|
||||
SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n", d1, d2, chn);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MIDI_PGM_CHANGE:
|
||||
channel[chn].program = d1;
|
||||
break;
|
||||
case MIDI_CHN_PRESSURE:
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
if (voice[i].status != sVS_UNUSED && voice[i].channel == chn)
|
||||
SEQ_KEY_PRESSURE(dev_id, i, voice[i].note, d1);
|
||||
|
||||
break;
|
||||
case MIDI_PITCH_BEND:
|
||||
channel[chn].bender = (d2 << 7) + d1;
|
||||
for (i = 0; i < dest->caps.wVoices; i++)
|
||||
if (voice[i].channel == chn)
|
||||
SEQ_BENDER(dev_id, i, channel[chn].bender);
|
||||
break;
|
||||
case MIDI_SYSTEM_PREFIX:
|
||||
switch (evt & 0x0F)
|
||||
{
|
||||
case 0x0F: /* Reset */
|
||||
midi_out_fm_reset(dev_id);
|
||||
break;
|
||||
default:
|
||||
WARN("Unsupported (yet) system event %02x\n", evt & 0x0F);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0);
|
||||
return MMSYSERR_NOTENABLED;
|
||||
}
|
||||
|
||||
SEQ_DUMPBUF();
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
static UINT midi_out_port_data(WORD dev_id, UINT data)
|
||||
{
|
||||
WORD evt = LOBYTE(LOWORD(data));
|
||||
WORD d1 = HIBYTE(LOWORD(data));
|
||||
WORD d2 = LOBYTE(HIWORD(data));
|
||||
int dev = dev_id - num_synths;
|
||||
|
||||
if (dev < 0)
|
||||
{
|
||||
WARN("Internal error on devID (%u) !\n", dev_id);
|
||||
return MIDIERR_NODEVICE;
|
||||
}
|
||||
|
||||
switch (evt & 0xF0)
|
||||
{
|
||||
case MIDI_NOTEOFF:
|
||||
case MIDI_NOTEON:
|
||||
case MIDI_KEY_PRESSURE:
|
||||
case MIDI_CTL_CHANGE:
|
||||
case MIDI_PITCH_BEND:
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
SEQ_MIDIOUT(dev, d1);
|
||||
SEQ_MIDIOUT(dev, d2);
|
||||
break;
|
||||
case MIDI_PGM_CHANGE:
|
||||
case MIDI_CHN_PRESSURE:
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
SEQ_MIDIOUT(dev, d1);
|
||||
break;
|
||||
case MIDI_SYSTEM_PREFIX:
|
||||
switch (evt & 0x0F)
|
||||
{
|
||||
case 0x00: /* System Exclusive, don't do it on MODM_DATA, should require MODM_LONGDATA */
|
||||
case 0x04: /* Undefined. */
|
||||
case 0x05: /* Undefined. */
|
||||
case 0x07: /* End of Exclusive. */
|
||||
case 0x09: /* Undefined. */
|
||||
case 0x0D: /* Undefined. */
|
||||
break;
|
||||
case 0x06: /* Tune Request */
|
||||
case 0x08: /* Timing Clock. */
|
||||
case 0x0A: /* Start. */
|
||||
case 0x0B: /* Continue */
|
||||
case 0x0C: /* Stop */
|
||||
case 0x0E: /* Active Sensing. */
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
break;
|
||||
case 0x0F: /* Reset */
|
||||
SEQ_MIDIOUT(dev, MIDI_SYSTEM_PREFIX);
|
||||
SEQ_MIDIOUT(dev, 0x7e);
|
||||
SEQ_MIDIOUT(dev, 0x7f);
|
||||
SEQ_MIDIOUT(dev, 0x09);
|
||||
SEQ_MIDIOUT(dev, 0x01);
|
||||
SEQ_MIDIOUT(dev, 0xf7);
|
||||
break;
|
||||
case 0x01: /* MTC Quarter frame */
|
||||
case 0x03: /* Song Select. */
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
SEQ_MIDIOUT(dev, d1);
|
||||
case 0x02: /* Song Position Pointer. */
|
||||
SEQ_MIDIOUT(dev, evt);
|
||||
SEQ_MIDIOUT(dev, d1);
|
||||
SEQ_MIDIOUT(dev, d2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SEQ_DUMPBUF();
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
static UINT midi_out_data(WORD dev_id, UINT data)
|
||||
{
|
||||
struct midi_dest *dest;
|
||||
|
||||
TRACE("(%04X, %08X);\n", dev_id, data);
|
||||
|
||||
if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID;
|
||||
dest = dests + dev_id;
|
||||
if (!dest->bEnabled) return MIDIERR_NODEVICE;
|
||||
|
||||
if (dest->fd == -1)
|
||||
{
|
||||
WARN("can't play !\n");
|
||||
return MIDIERR_NODEVICE;
|
||||
}
|
||||
switch (dest->caps.wTechnology)
|
||||
{
|
||||
case MOD_FMSYNTH:
|
||||
return midi_out_fm_data(dev_id, data);
|
||||
case MOD_MIDIPORT:
|
||||
return midi_out_port_data(dev_id, data);
|
||||
}
|
||||
|
||||
WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology);
|
||||
return MMSYSERR_NOTENABLED;
|
||||
}
|
||||
|
||||
NTSTATUS midi_out_message(void *args)
|
||||
{
|
||||
|
@ -665,6 +953,9 @@ NTSTATUS midi_out_message(void *args)
|
|||
case MODM_CLOSE:
|
||||
*params->err = midi_out_close(params->dev_id, params->notify);
|
||||
break;
|
||||
case MODM_DATA:
|
||||
*params->err = midi_out_data(params->dev_id, params->param_1);
|
||||
break;
|
||||
default:
|
||||
TRACE("Unsupported message\n");
|
||||
*params->err = MMSYSERR_NOTSUPPORTED;
|
||||
|
|
|
@ -276,13 +276,6 @@ struct midi_seq_open_params
|
|||
int fd;
|
||||
};
|
||||
|
||||
struct midi_out_fm_load_params
|
||||
{
|
||||
WORD dev_id;
|
||||
int fd;
|
||||
int ret;
|
||||
};
|
||||
|
||||
enum oss_funcs
|
||||
{
|
||||
oss_test_connect,
|
||||
|
@ -312,13 +305,11 @@ enum oss_funcs
|
|||
oss_midi_out_message,
|
||||
|
||||
oss_midi_seq_open, /* temporary */
|
||||
oss_midi_out_fm_reset,
|
||||
};
|
||||
|
||||
NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN;
|
||||
NTSTATUS midi_out_message(void *args) DECLSPEC_HIDDEN;
|
||||
NTSTATUS midi_seq_open(void *args) DECLSPEC_HIDDEN;
|
||||
NTSTATUS midi_out_fm_reset(void *args) DECLSPEC_HIDDEN;
|
||||
|
||||
extern unixlib_handle_t oss_handle;
|
||||
|
||||
|
|
Loading…
Reference in a new issue