Commit 60f97504 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

wineoss: Move the midi in data handlers to the unixlib.

The syscall itself is temporary. Signed-off-by: 's avatarHuw Davies <huw@codeweavers.com> Signed-off-by: 's avatarAndrew Eikum <aeikum@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 31c5a82b
......@@ -126,16 +126,6 @@ static LRESULT OSS_MidiExit(void)
return 0;
}
static void in_buffer_lock(void)
{
OSS_CALL(midi_in_lock, ULongToPtr(1));
}
static void in_buffer_unlock(void)
{
OSS_CALL(midi_in_lock, ULongToPtr(0));
}
static void notify_client(struct notify_context *notify)
{
TRACE("dev_id = %d msg = %d param1 = %04lX param2 = %04lX\n",
......@@ -210,123 +200,13 @@ static int midiCloseSeq(int fd)
return 0;
}
static void handle_sysex_data(struct midi_src *src, unsigned char value, UINT time)
{
MIDIHDR *hdr;
BOOL done = FALSE;
src->state |= 2;
src->incLen = 0;
in_buffer_lock();
hdr = src->lpQueueHdr;
if (hdr)
{
BYTE *data = (BYTE *)hdr->lpData;
data[hdr->dwBytesRecorded++] = value;
if (hdr->dwBytesRecorded == hdr->dwBufferLength)
done = TRUE;
}
if (value == 0xf7) /* end */
{
src->state &= ~2;
done = TRUE;
}
if (done && hdr)
{
src->lpQueueHdr = hdr->lpNext;
hdr->dwFlags &= ~MHDR_INQUEUE;
hdr->dwFlags |= MHDR_DONE;
MIDI_NotifyClient(src - MidiInDev, MIM_LONGDATA, (UINT_PTR)hdr, time);
}
in_buffer_unlock();
}
static void handle_regular_data(struct midi_src *src, unsigned char value, UINT time)
{
UINT to_send = 0;
#define IS_CMD(_x) (((_x) & 0x80) == 0x80)
#define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0)
if (!IS_CMD(value) && src->incLen == 0) /* try to reuse old cmd */
{
if (IS_CMD(src->incPrev) && !IS_SYS_CMD(src->incPrev))
{
src->incoming[0] = src->incPrev;
src->incLen = 1;
}
else
{
/* FIXME: should generate MIM_ERROR notification */
return;
}
}
src->incoming[(int)src->incLen++] = value;
if (src->incLen == 1 && !IS_SYS_CMD(src->incoming[0]))
/* store new cmd, just in case */
src->incPrev = src->incoming[0];
#undef IS_CMD
#undef IS_SYS_CMD
switch (src->incoming[0] & 0xF0)
{
case MIDI_NOTEOFF:
case MIDI_NOTEON:
case MIDI_KEY_PRESSURE:
case MIDI_CTL_CHANGE:
case MIDI_PITCH_BEND:
if (src->incLen == 3)
to_send = (src->incoming[2] << 16) | (src->incoming[1] << 8) |
src->incoming[0];
break;
case MIDI_PGM_CHANGE:
case MIDI_CHN_PRESSURE:
if (src->incLen == 2)
to_send = (src->incoming[1] << 8) | src->incoming[0];
break;
case MIDI_SYSTEM_PREFIX:
if (src->incLen == 1)
to_send = src->incoming[0];
break;
}
if (to_send)
{
src->incLen = 0;
MIDI_NotifyClient(src - MidiInDev, MIM_DATA, to_send, time);
}
}
static void handle_midi_data(unsigned char *buffer, unsigned int len)
{
unsigned int time = GetTickCount(), i;
struct midi_src *src;
unsigned char value;
WORD dev_id;
struct midi_handle_data_params params;
for (i = 0; i < len; i += (buffer[i] & 0x80) ? 8 : 4)
{
if (buffer[i] != SEQ_MIDIPUTC) continue;
dev_id = buffer[i + 2];
value = buffer[i + 1];
if (dev_id >= MIDM_NumDevs) continue;
src = MidiInDev + dev_id;
if (src->state <= 0) continue;
if (value == 0xf0 || src->state & 2) /* system exclusive */
handle_sysex_data(src, value, time - src->startTime);
else
handle_regular_data(src, value, time - src->startTime);
}
params.buffer = buffer;
params.len = len;
OSS_CALL(midi_handle_data, &params);
}
static DWORD WINAPI midRecThread(void *arg)
......@@ -565,6 +445,7 @@ static DWORD WINAPI notify_thread(void *p)
{
OSS_CALL(midi_notify_wait, &params);
if (quit) break;
if (notify.send_notify) notify_client(&notify);
}
return 0;
}
......
......@@ -1412,5 +1412,5 @@ unixlib_entry_t __wine_unix_call_funcs[] =
midi_notify_wait,
midi_seq_open,
midi_in_lock,
midi_handle_data,
};
......@@ -68,7 +68,11 @@ static struct midi_src srcs[MAX_MIDIINDRV];
static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t notify_read_cond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t notify_write_cond = PTHREAD_COND_INITIALIZER;
static BOOL notify_quit;
#define NOTIFY_BUFFER_SIZE 64 + 1 /* + 1 for the sentinel */
static struct notify_context notify_buffer[NOTIFY_BUFFER_SIZE];
static struct notify_context *notify_read = notify_buffer, *notify_write = notify_buffer;
typedef struct sVoice
{
......@@ -151,19 +155,59 @@ static void in_buffer_unlock(void)
pthread_mutex_unlock(&in_buffer_mutex);
}
NTSTATUS midi_in_lock(void *args)
/*
* notify buffer: The notification ring buffer is implemented so that
* there is always at least one unused sentinel before the current
* read position in order to allow detection of the full vs empty
* state.
*/
static struct notify_context *notify_buffer_next(struct notify_context *notify)
{
if (args) in_buffer_lock();
else in_buffer_unlock();
if (++notify >= notify_buffer + ARRAY_SIZE(notify_buffer))
notify = notify_buffer;
return STATUS_SUCCESS;
return notify;
}
static BOOL notify_buffer_empty(void)
{
return notify_read == notify_write;
}
static BOOL notify_buffer_full(void)
{
return notify_buffer_next(notify_write) == notify_read;
}
static BOOL notify_buffer_add(struct notify_context *notify)
{
if (notify_buffer_full()) return FALSE;
*notify_write = *notify;
notify_write = notify_buffer_next(notify_write);
return TRUE;
}
static BOOL notify_buffer_remove(struct notify_context *notify)
{
if (notify_buffer_empty()) return FALSE;
*notify = *notify_read;
notify_read = notify_buffer_next(notify_read);
return TRUE;
}
static void notify_post(struct notify_context *notify)
{
pthread_mutex_lock(&notify_mutex);
if (notify) FIXME("Not yet handled\n");
if (notify)
{
while (notify_buffer_full())
pthread_cond_wait(&notify_write_cond, &notify_mutex);
notify_buffer_add(notify);
}
else notify_quit = TRUE;
pthread_cond_signal(&notify_read_cond);
......@@ -1157,6 +1201,133 @@ static UINT midi_out_reset(WORD dev_id)
return MMSYSERR_NOERROR;
}
static void handle_sysex_data(struct midi_src *src, unsigned char value, UINT time)
{
struct notify_context notify;
MIDIHDR *hdr;
BOOL done = FALSE;
src->state |= 2;
src->incLen = 0;
in_buffer_lock();
hdr = src->lpQueueHdr;
if (hdr)
{
BYTE *data = (BYTE *)hdr->lpData;
data[hdr->dwBytesRecorded++] = value;
if (hdr->dwBytesRecorded == hdr->dwBufferLength)
done = TRUE;
}
if (value == 0xf7) /* end */
{
src->state &= ~2;
done = TRUE;
}
if (done && hdr)
{
src->lpQueueHdr = hdr->lpNext;
hdr->dwFlags &= ~MHDR_INQUEUE;
hdr->dwFlags |= MHDR_DONE;
set_in_notify(&notify, src, src - srcs, MIM_LONGDATA, (UINT_PTR)hdr, time);
notify_post(&notify);
}
in_buffer_unlock();
}
static void handle_regular_data(struct midi_src *src, unsigned char value, UINT time)
{
struct notify_context notify;
UINT to_send = 0;
#define IS_CMD(_x) (((_x) & 0x80) == 0x80)
#define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0)
if (!IS_CMD(value) && src->incLen == 0) /* try to reuse old cmd */
{
if (IS_CMD(src->incPrev) && !IS_SYS_CMD(src->incPrev))
{
src->incoming[0] = src->incPrev;
src->incLen = 1;
}
else
{
/* FIXME: should generate MIM_ERROR notification */
return;
}
}
src->incoming[(int)src->incLen++] = value;
if (src->incLen == 1 && !IS_SYS_CMD(src->incoming[0]))
/* store new cmd, just in case */
src->incPrev = src->incoming[0];
#undef IS_CMD
#undef IS_SYS_CMD
switch (src->incoming[0] & 0xF0)
{
case MIDI_NOTEOFF:
case MIDI_NOTEON:
case MIDI_KEY_PRESSURE:
case MIDI_CTL_CHANGE:
case MIDI_PITCH_BEND:
if (src->incLen == 3)
to_send = (src->incoming[2] << 16) | (src->incoming[1] << 8) |
src->incoming[0];
break;
case MIDI_PGM_CHANGE:
case MIDI_CHN_PRESSURE:
if (src->incLen == 2)
to_send = (src->incoming[1] << 8) | src->incoming[0];
break;
case MIDI_SYSTEM_PREFIX:
if (src->incLen == 1)
to_send = src->incoming[0];
break;
}
if (to_send)
{
src->incLen = 0;
set_in_notify(&notify, src, src - srcs, MIM_DATA, to_send, time);
notify_post(&notify);
}
}
NTSTATUS midi_handle_data(void *args)
{
struct midi_handle_data_params *params = args;
unsigned char *buffer = params->buffer;
unsigned int len = params->len;
unsigned int time = NtGetTickCount(), i;
struct midi_src *src;
unsigned char value;
WORD dev_id;
for (i = 0; i < len; i += (buffer[i] & 0x80) ? 8 : 4)
{
if (buffer[i] != SEQ_MIDIPUTC) continue;
dev_id = buffer[i + 2];
value = buffer[i + 1];
if (dev_id >= num_srcs) continue;
src = srcs + dev_id;
if (src->state <= 0) continue;
if (value == 0xf0 || src->state & 2) /* system exclusive */
handle_sysex_data(src, value, time - src->startTime);
else
handle_regular_data(src, value, time - src->startTime);
}
return STATUS_SUCCESS;
}
static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
{
struct midi_src *src;
......@@ -1397,11 +1568,15 @@ NTSTATUS midi_notify_wait(void *args)
pthread_mutex_lock(&notify_mutex);
while (!notify_quit)
while (!notify_quit && notify_buffer_empty())
pthread_cond_wait(&notify_read_cond, &notify_mutex);
*params->quit = notify_quit;
if (!notify_quit)
{
notify_buffer_remove(params->notify);
pthread_cond_signal(&notify_write_cond);
}
pthread_mutex_unlock(&notify_mutex);
return STATUS_SUCCESS;
......
......@@ -279,6 +279,12 @@ struct midi_seq_open_params
int fd;
};
struct midi_handle_data_params
{
unsigned char *buffer;
unsigned int len;
};
enum oss_funcs
{
oss_test_connect,
......@@ -311,7 +317,7 @@ enum oss_funcs
oss_midi_notify_wait,
oss_midi_seq_open, /* temporary */
oss_midi_in_lock,
oss_midi_handle_data,
};
NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN;
......@@ -320,7 +326,7 @@ NTSTATUS midi_out_message(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_in_message(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_notify_wait(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_seq_open(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_in_lock(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_handle_data(void *args) DECLSPEC_HIDDEN;
extern unixlib_handle_t oss_handle;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment