[PATCH 2/4] wineoss: Move MODM_DATA to the unixlib.
Huw Davies
huw at codeweavers.com
Thu Apr 21 01:52:16 CDT 2022
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
dlls/wineoss.drv/midi.c | 338 +------------------------------------
dlls/wineoss.drv/oss.c | 1 -
dlls/wineoss.drv/ossmidi.c | 301 ++++++++++++++++++++++++++++++++-
dlls/wineoss.drv/unixlib.h | 9 -
4 files changed, 301 insertions(+), 348 deletions(-)
diff --git a/dlls/wineoss.drv/midi.c b/dlls/wineoss.drv/midi.c
index 70bc4b7b9bd..1751af2349e 100644
--- a/dlls/wineoss.drv/midi.c
+++ b/dlls/wineoss.drv/midi.c
@@ -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:
diff --git a/dlls/wineoss.drv/oss.c b/dlls/wineoss.drv/oss.c
index 1bd5ddb5762..db2f705a0c5 100644
--- a/dlls/wineoss.drv/oss.c
+++ b/dlls/wineoss.drv/oss.c
@@ -1409,5 +1409,4 @@ unixlib_entry_t __wine_unix_call_funcs[] =
midi_out_message,
midi_seq_open,
- midi_out_fm_reset,
};
diff --git a/dlls/wineoss.drv/ossmidi.c b/dlls/wineoss.drv/ossmidi.c
index 613b070fde5..ee83da8bfcd 100644
--- a/dlls/wineoss.drv/ossmidi.c
+++ b/dlls/wineoss.drv/ossmidi.c
@@ -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;
diff --git a/dlls/wineoss.drv/unixlib.h b/dlls/wineoss.drv/unixlib.h
index 75506d445bc..d56e11b8d23 100644
--- a/dlls/wineoss.drv/unixlib.h
+++ b/dlls/wineoss.drv/unixlib.h
@@ -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;
--
2.25.1
More information about the wine-devel
mailing list