Signed-off-by: Andrew Eikum aeikum@codeweavers.com
On Thu, Apr 21, 2022 at 07:52:15AM +0100, Huw Davies wrote:
Signed-off-by: Huw Davies huw@codeweavers.com
dlls/wineoss.drv/midi.c | 538 ++++++++++++++++++++-------------------- 1 file changed, 268 insertions(+), 270 deletions(-)
diff --git a/dlls/wineoss.drv/midi.c b/dlls/wineoss.drv/midi.c index d66e926655d..70bc4b7b9bd 100644 --- a/dlls/wineoss.drv/midi.c +++ b/dlls/wineoss.drv/midi.c @@ -747,15 +747,274 @@ 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) {
WORD evt = LOBYTE(LOWORD(dwParam));
WORD d1 = HIBYTE(LOWORD(dwParam));
WORD d2 = LOBYTE(HIWORD(dwParam));
TRACE("(%04X, %08X);\n", wDevID, dwParam);
if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
@@ -767,275 +1026,14 @@ static DWORD modData(WORD wDevID, DWORD dwParam) } switch (MidiOutDev[wDevID].caps.wTechnology) { case MOD_FMSYNTH:
- /* FIXME:
* - chorus depth controller is not used*/- {
sFMextra* extra = MidiOutDev[wDevID].lpExtra;sVoice* voice = extra->voice;sChannel* channel = extra->channel;int chn = (evt & 0x0F);int i, nv;switch (evt & 0xF0) {case MIDI_NOTEOFF:for (i = 0; i < MidiOutDev[wDevID].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(wDevID, i, d1, d2);}}break;case MIDI_NOTEON:if (d2 == 0) { /* note off if velocity == 0 */for (i = 0; i < MidiOutDev[wDevID].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(wDevID, 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 < MidiOutDev[wDevID].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(wDevID, nv, IS_DRUM_CHANNEL(extra, chn) ?(128 + d1) : channel[chn].program);SEQ_BENDER_RANGE(wDevID, nv, channel[chn].benderRange * 100);SEQ_BENDER(wDevID, nv, channel[chn].bender);SEQ_CONTROL(wDevID, nv, CTL_PAN, channel[chn].balance);SEQ_CONTROL(wDevID, nv, CTL_EXPRESSION, channel[chn].expression);-#if 0
/* FIXME: does not really seem to work on my SB card and* screws everything up... so lay it down*/SEQ_CONTROL(wDevID, nv, CTL_MAIN_VOLUME, channel[chn].volume);-#endif
SEQ_START_NOTE(wDevID, 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 < MidiOutDev[wDevID].caps.wVoices; i++) {if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1) {SEQ_KEY_PRESSURE(wDevID, 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 < MidiOutDev[wDevID].caps.wVoices; i++) {if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {voice[i].status = sVS_SUSTAINED;}}} else {for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn) {voice[i].status = sVS_UNUSED;SEQ_STOP_NOTE(wDevID, 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 < MidiOutDev[wDevID].caps.wVoices; i++) {if (voice[i].channel == chn) {SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);}}}break;case 0x7F7F:channel[chn].benderRange = 2;for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {if (voice[i].channel == chn) {SEQ_BENDER_RANGE(wDevID, 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 < MidiOutDev[wDevID].caps.wVoices; i++) {if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {voice[i].status = sVS_UNUSED;SEQ_STOP_NOTE(wDevID, 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 < MidiOutDev[wDevID].caps.wVoices; i++) {if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {voice[i].status = sVS_UNUSED;SEQ_STOP_NOTE(wDevID, 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 < MidiOutDev[wDevID].caps.wVoices; i++) {if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {SEQ_KEY_PRESSURE(wDevID, i, voice[i].note, d1);}}break;case MIDI_PITCH_BEND:channel[chn].bender = (d2 << 7) + d1;for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {if (voice[i].channel == chn) {SEQ_BENDER(wDevID, i, channel[chn].bender);}}break;case MIDI_SYSTEM_PREFIX:switch (evt & 0x0F) {case 0x0F: /* Reset */OSS_CALL(midi_out_fm_reset, (void *)(UINT_PTR)wDevID);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;}- }
- break;
case MOD_MIDIPORT:return midi_out_fm_data(wDevID, dwParam);
- {
int dev = wDevID - MODM_NumFMSynthDevs;if (dev < 0) {WARN("Internal error on devID (%u) !\n", wDevID);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 modData,* should require modLongData*/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, evt);this other way may be better */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;}- }
- break;
- default:
- WARN("Technology not supported (yet) %d !\n",
MidiOutDev[wDevID].caps.wTechnology);- return MMSYSERR_NOTENABLED;
}return midi_out_port_data(wDevID, dwParam);
- SEQ_DUMPBUF();
- return MMSYSERR_NOERROR;
- WARN("Technology not supported (yet) %d !\n",
MidiOutDev[wDevID].caps.wTechnology);- return MMSYSERR_NOTENABLED;
}
/**************************************************************************
2.25.1