[PATCH 1/4] wineoss: Use separate functions to handle MODM_DATA for FM synths and ports.
Andrew Eikum
aeikum at codeweavers.com
Thu Apr 21 08:42:09 CDT 2022
Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
On Thu, Apr 21, 2022 at 07:52:15AM +0100, Huw Davies wrote:
> Signed-off-by: Huw Davies <huw at 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;
> + return midi_out_fm_data(wDevID, dwParam);
> case MOD_MIDIPORT:
> - {
> - 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
>
>
More information about the wine-devel
mailing list