Signed-off-by: Huw Davies huw@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;
Signed-off-by: Andrew Eikum aeikum@codeweavers.com
On Thu, Apr 21, 2022 at 07:52:16AM +0100, Huw Davies wrote:
Signed-off-by: Huw Davies huw@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);
} case MOD_MIDIPORT:midi_out_fm_reset(dev_id); break;
@@ -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);
default: TRACE("Unsupported message\n"); *params->err = MMSYSERR_NOTSUPPORTED;break;
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