diff --git a/dlls/dmime/midi.c b/dlls/dmime/midi.c index e4aa165815d..57b6a3adf90 100644 --- a/dlls/dmime/midi.c +++ b/dlls/dmime/midi.c @@ -187,22 +187,12 @@ static HRESULT read_midi_event(IStream *stream, struct midi_event *event, BYTE * status_type = event->status & 0xf0; event->data[0] = byte; - if (status_type == MIDI_PROGRAM_CHANGE) - { - TRACE("MIDI program change event status %#02x, data: %#02x, time +%lu\n", event->status, - event->data[0], delta_time); - } - else - { - if (status_type != MIDI_CHANNEL_PRESSURE && (hr = stream_read_at_most(stream, &byte, 1, bytes_left)) != S_OK) - return hr; - event->data[1] = byte; - if (status_type == MIDI_NOTE_ON || status_type == MIDI_NOTE_OFF) - TRACE("MIDI note event status %#02x, data: %#02x, %#02x, time +%lu\n", event->status, - event->data[0], event->data[1], delta_time); - else - FIXME("MIDI event status %#02x, time +%lu, not supported\n", event->status, delta_time); - } + if (status_type != MIDI_PROGRAM_CHANGE && status_type != MIDI_CHANNEL_PRESSURE && + (hr = stream_read_at_most(stream, &byte, 1, bytes_left)) != S_OK) + return hr; + event->data[1] = byte; + TRACE("MIDI event status %#02x, data: %#02x, %#02x, time +%lu\n", event->status, event->data[0], + event->data[1], delta_time); return S_OK; } @@ -303,6 +293,27 @@ static HRESULT midi_parser_handle_note_on_off(struct midi_parser *parser, struct return S_OK; } +static HRESULT midi_parser_handle_control(struct midi_parser *parser, struct midi_event *event) +{ + struct midi_seqtrack_item *item; + DMUS_IO_SEQ_ITEM *seq_item; + MUSIC_TIME dmusic_time = (ULONGLONG)parser->time * DMUS_PPQ / parser->division; + + if ((item = calloc(1, sizeof(struct midi_seqtrack_item))) == NULL) return E_OUTOFMEMORY; + + seq_item = &item->item; + seq_item->mtTime = dmusic_time; + seq_item->mtDuration = 0; + seq_item->dwPChannel = event->status & 0xf; + seq_item->bStatus = event->status & 0xf0; + seq_item->bByte1 = event->data[0]; + seq_item->bByte2 = event->data[1]; + list_add_tail(&parser->seqtrack_items, &item->entry); + parser->seqtrack_items_count++; + + return S_OK; +} + static int midi_seqtrack_item_compare(const void *a, const void *b) { const DMUS_IO_SEQ_ITEM *item_a = a, *item_b = b; @@ -351,6 +362,11 @@ static HRESULT midi_parser_parse(struct midi_parser *parser, IDirectMusicSegment case MIDI_NOTE_OFF: hr = midi_parser_handle_note_on_off(parser, &event); break; + case MIDI_CHANNEL_PRESSURE: + case MIDI_PITCH_BEND_CHANGE: + case MIDI_CONTROL_CHANGE: + hr = midi_parser_handle_control(parser, &event); + break; case MIDI_PROGRAM_CHANGE: hr = midi_parser_handle_program_change(parser, &event); break; diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index fc50009402a..1b0e99bd77c 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "dmusic_midi.h" #include "dmime_private.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); @@ -130,27 +131,46 @@ static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *state for (i = 0; SUCCEEDED(hr) &&i < This->count; i++) { DMUS_IO_SEQ_ITEM *item = This->items + i; - DMUS_NOTE_PMSG *msg; + DMUS_PMSG *msg; if (item->mtTime < start_time) continue; if (item->mtTime >= end_time) continue; - if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg), - (DMUS_PMSG **)&msg))) - break; + if (item->bStatus == MIDI_NOTE_ON) + { + DMUS_NOTE_PMSG *note; + if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*note), + (DMUS_PMSG **)¬e))) + break; + + note->dwType = DMUS_PMSGT_NOTE; + note->mtDuration = item->mtDuration; + note->wMusicValue = item->bByte1; + note->nOffset = item->nOffset; + note->bVelocity = item->bByte2; + note->bFlags = 1; + note->bMidiValue = item->bByte1; + msg = (DMUS_PMSG *)note; + } + else + { + DMUS_MIDI_PMSG *midi; + if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*midi), + (DMUS_PMSG **)&midi))) + break; + + midi->dwType = DMUS_PMSGT_MIDI; + midi->bStatus = item->bStatus; + midi->bByte1 = item->bByte1; + midi->bByte2 = item->bByte2; + msg = (DMUS_PMSG *)midi; + } msg->mtTime = item->mtTime + time_offset; msg->dwFlags = DMUS_PMSGF_MUSICTIME; msg->dwPChannel = item->dwPChannel; msg->dwVirtualTrackID = track_id; - msg->dwType = DMUS_PMSGT_NOTE; msg->dwGroupID = 1; - msg->mtDuration = item->mtDuration; - msg->wMusicValue = item->bByte1; - msg->nOffset = item->nOffset; - msg->bVelocity = item->bByte2; - msg->bFlags = 1; - msg->bMidiValue = item->bByte1; if (FAILED(hr = IDirectMusicGraph_StampPMsg(graph, (DMUS_PMSG *)msg)) || FAILED(hr = IDirectMusicPerformance_SendPMsg(performance, (DMUS_PMSG *)msg))) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 3086dcaf978..9a2cd9d803c 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1633,6 +1633,13 @@ static void test_midi(void) 0xc1, /* event type, program change, channel 1 */ 0x30, /* event data, patch 48 */ }; + static const char midi_control_change[] = + { + 0x04, /* delta time = 4 */ + 0xb1, /* event type, control change, channel 1 */ + 0x07, /* event data, channel volume */ + 0x40, /* event data, 64 */ + }; static const char midi_note_on[] = { 0x04, /* delta time = 4 */ @@ -1667,10 +1674,11 @@ static void test_midi(void) WCHAR test_mid[MAX_PATH], bogus_mid[MAX_PATH]; HRESULT hr; ULONG ret; - DWORD track_length; + DWORD track_length, trace2_length; MUSIC_TIME next; DMUS_PMSG *msg; DMUS_NOTE_PMSG *note; + DMUS_MIDI_PMSG *midi; DMUS_PATCH_PMSG *patch; DMUS_TEMPO_PARAM tempo_param; #include @@ -1873,13 +1881,16 @@ static void test_midi(void) ok(hr == S_OK, "got %#lx\n", hr); /* Add a second track, to test the duration of the trailing note. */ - track_header.length = RtlUlongByteSwap(sizeof(track_header) - 8 + sizeof(midi_note_on) + sizeof(midi_note_off)); + trace2_length = sizeof(midi_note_on) + sizeof(midi_note_off2) + sizeof(midi_control_change); + track_header.length = RtlUlongByteSwap(sizeof(track_header) - 8 + trace2_length); hr = IStream_Write(stream, &track_header, sizeof(track_header), NULL); ok(hr == S_OK, "got %#lx\n", hr); hr = IStream_Write(stream, midi_note_on, sizeof(midi_note_on), NULL); ok(hr == S_OK, "got %#lx\n", hr); hr = IStream_Write(stream, midi_note_off2, sizeof(midi_note_off2), NULL); ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Write(stream, midi_control_change, sizeof(midi_control_change), NULL); + ok(hr == S_OK, "got %#lx\n", hr); hr = IStream_Seek(stream, zero, 0, NULL); ok(hr == S_OK, "got %#lx\n", hr); @@ -1887,7 +1898,7 @@ static void test_midi(void) ok(hr == S_OK, "got %#lx\n", hr); hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &position); ok(hr == S_OK, "got %#lx\n", hr); - ok(position.QuadPart == sizeof(header) + sizeof(track_header) * 2 + track_length + sizeof(midi_note_on) + sizeof(midi_note_off), + ok(position.QuadPart == sizeof(header) + sizeof(track_header) * 2 + track_length + trace2_length, "got %lld\n", position.QuadPart); IPersistStream_Release(persist); IStream_Release(stream); @@ -1981,6 +1992,18 @@ static void test_midi(void) hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&msg); + ok(!ret, "got %#lx\n", ret); + ok(msg->dwType == DMUS_PMSGT_MIDI, "got msg type %#lx, expected MIDI\n", msg->dwType); + ok(msg->mtTime == 649, "got mtTime %lu, expected 649\n", msg->mtTime); + ok(msg->dwPChannel == 1, "got pchannel %lu, expected 1\n", msg->dwPChannel); + midi = (DMUS_MIDI_PMSG *)msg; + ok(midi->bStatus == 0xb0, "got status %#x, expected 0xb1\n", midi->bStatus); + ok(midi->bByte1 == 0x07, "got byte1 %#x, expected 0x07\n", midi->bByte1); + ok(midi->bByte2 == 0x40, "got byte2 %#x, expected 0x40\n", midi->bByte2); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + /* wine generates an extra DIRTY event. */ ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&msg); todo_wine ok(ret == WAIT_TIMEOUT, "unexpected message\n");