dmime: Parse note on/off events and generate a seqtrack.
This commit is contained in:
parent
1df0e34293
commit
5ff94358a0
4 changed files with 235 additions and 17 deletions
|
@ -89,6 +89,8 @@ extern BOOL segment_state_has_track(IDirectMusicSegmentState *iface, DWORD track
|
|||
extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent,
|
||||
IDirectMusicTrack8 **ret_iface);
|
||||
|
||||
extern void sequence_track_set_items(IDirectMusicTrack8 *track, DMUS_IO_SEQ_ITEM *items, unsigned int count);
|
||||
|
||||
extern HRESULT performance_get_dsound(IDirectMusicPerformance8 *iface, IDirectSound **dsound);
|
||||
extern HRESULT performance_send_segment_start(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time,
|
||||
IDirectMusicSegmentState *state);
|
||||
|
|
|
@ -49,8 +49,20 @@ struct midi_event
|
|||
};
|
||||
};
|
||||
|
||||
struct midi_seqtrack_item
|
||||
{
|
||||
struct list entry;
|
||||
DMUS_IO_SEQ_ITEM item;
|
||||
};
|
||||
|
||||
struct midi_parser
|
||||
{
|
||||
IDirectMusicTrack8 *seqtrack;
|
||||
ULONG seqtrack_items_count;
|
||||
struct list seqtrack_items;
|
||||
/* Track the initial note on event generated for a note that is currently on. NULL if the note is off. */
|
||||
struct midi_seqtrack_item *note_states[128 * 16];
|
||||
|
||||
IDirectMusicTrack *chordtrack;
|
||||
IDirectMusicTrack *bandtrack;
|
||||
IDirectMusicTrack *tempotrack;
|
||||
|
@ -174,9 +186,9 @@ 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)
|
||||
{
|
||||
event->data[0] = byte;
|
||||
TRACE("MIDI program change event status %#02x, data: %#02x, time +%lu\n", event->status,
|
||||
event->data[0], delta_time);
|
||||
}
|
||||
|
@ -184,7 +196,12 @@ static HRESULT read_midi_event(IStream *stream, struct midi_event *event, BYTE *
|
|||
{
|
||||
if (status_type != MIDI_CHANNEL_PRESSURE && (hr = stream_read_at_most(stream, &byte, 1, bytes_left)) != S_OK)
|
||||
return hr;
|
||||
FIXME("MIDI event status %#02x, time +%lu, not supported\n", event->status, delta_time);
|
||||
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);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
@ -234,11 +251,71 @@ static HRESULT midi_parser_handle_program_change(struct midi_parser *parser, str
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT midi_parser_handle_note_on_off(struct midi_parser *parser, struct midi_event *event)
|
||||
{
|
||||
BYTE new_velocity = (event->status & 0xf0) == MIDI_NOTE_OFF ? 0 : event->data[1]; /* DirectMusic doesn't have noteoff velocity */
|
||||
BYTE note = event->data[0], channel = event->status & 0xf;
|
||||
DWORD index = (DWORD)channel * 128 + note;
|
||||
MUSIC_TIME dmusic_time;
|
||||
struct midi_seqtrack_item *note_state = parser->note_states[index];
|
||||
DMUS_IO_SEQ_ITEM *seq_item;
|
||||
struct midi_seqtrack_item *item;
|
||||
|
||||
/* Testing shows there are 2 cases to deal with here:
|
||||
*
|
||||
* 1. Got note on when the note is already on, generate a NOTE event with
|
||||
* new velocity and duration 1.
|
||||
* 2. Got note on when the note is off, generate a NOTE event that lasts
|
||||
* until the next note off event, intervening note on event doesn't matter.
|
||||
*/
|
||||
if (new_velocity)
|
||||
{
|
||||
TRACE("Adding note event at time %lu, note %u, velocity %u\n", parser->time, note, new_velocity);
|
||||
|
||||
dmusic_time = (ULONGLONG)parser->time * DMUS_PPQ / parser->division;
|
||||
|
||||
item = calloc(1, sizeof(struct midi_seqtrack_item));
|
||||
if (!item) return E_OUTOFMEMORY;
|
||||
|
||||
seq_item = &item->item;
|
||||
seq_item->mtTime = dmusic_time;
|
||||
seq_item->mtDuration = 1;
|
||||
seq_item->dwPChannel = channel;
|
||||
seq_item->bStatus = MIDI_NOTE_ON;
|
||||
seq_item->bByte1 = note;
|
||||
seq_item->bByte2 = new_velocity;
|
||||
list_add_tail(&parser->seqtrack_items, &item->entry);
|
||||
parser->seqtrack_items_count++;
|
||||
|
||||
if (!note_state) parser->note_states[index] = item;
|
||||
}
|
||||
else if (note_state)
|
||||
{
|
||||
note_state->item.mtDuration = (ULONGLONG)parser->time * DMUS_PPQ / parser->division -
|
||||
note_state->item.mtTime;
|
||||
if (note_state->item.mtDuration == 0) note_state->item.mtDuration = 1;
|
||||
|
||||
TRACE("Note off at time %lu, note %u, duration %ld\n", parser->time, note, note_state->item.mtDuration);
|
||||
|
||||
parser->note_states[index] = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
return item_a->mtTime - item_b->mtTime;
|
||||
}
|
||||
|
||||
static HRESULT midi_parser_parse(struct midi_parser *parser, IDirectMusicSegment8 *segment)
|
||||
{
|
||||
WORD i = 0;
|
||||
HRESULT hr;
|
||||
MUSIC_TIME music_length = 0;
|
||||
DMUS_IO_SEQ_ITEM *seq_items = NULL;
|
||||
struct midi_seqtrack_item *item;
|
||||
|
||||
TRACE("(%p, %p): semi-stub\n", parser, segment);
|
||||
|
||||
|
@ -266,35 +343,70 @@ static HRESULT midi_parser_parse(struct midi_parser *parser, IDirectMusicSegment
|
|||
parser->time += event.delta_time;
|
||||
if (event.status == 0xff && event.meta_type == MIDI_META_SET_TEMPO)
|
||||
hr = midi_parser_handle_set_tempo(parser, &event);
|
||||
else if ((event.status & 0xf0) == MIDI_PROGRAM_CHANGE)
|
||||
hr = midi_parser_handle_program_change(parser, &event);
|
||||
else
|
||||
{
|
||||
switch (event.status & 0xf0)
|
||||
{
|
||||
case MIDI_NOTE_ON:
|
||||
case MIDI_NOTE_OFF:
|
||||
hr = midi_parser_handle_note_on_off(parser, &event);
|
||||
break;
|
||||
case MIDI_PROGRAM_CHANGE:
|
||||
hr = midi_parser_handle_program_change(parser, &event);
|
||||
break;
|
||||
default:
|
||||
FIXME("Unhandled MIDI event type %#02x at time +%lu\n", event.status, parser->time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (FAILED(hr)) break;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) break;
|
||||
|
||||
TRACE("End of track %u\n", i);
|
||||
if (parser->time > music_length) music_length = parser->time;
|
||||
parser->time = 0;
|
||||
memset(parser->note_states, 0, sizeof(parser->note_states));
|
||||
}
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
TRACE("End of file\n");
|
||||
|
||||
if ((seq_items = calloc(parser->seqtrack_items_count, sizeof(DMUS_IO_SEQ_ITEM))) == NULL)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
i = 0;
|
||||
LIST_FOR_EACH_ENTRY(item, &parser->seqtrack_items, struct midi_seqtrack_item, entry)
|
||||
seq_items[i++] = item->item;
|
||||
sequence_track_set_items(parser->seqtrack, seq_items, parser->seqtrack_items_count);
|
||||
qsort(seq_items, parser->seqtrack_items_count, sizeof(DMUS_IO_SEQ_ITEM), midi_seqtrack_item_compare);
|
||||
|
||||
music_length = (ULONGLONG)music_length * DMUS_PPQ / parser->division + 1;
|
||||
if (SUCCEEDED(hr)) hr = IDirectMusicSegment8_SetLength(segment, music_length);
|
||||
if (SUCCEEDED(hr)) hr = IDirectMusicSegment8_InsertTrack(segment, parser->bandtrack, 0xffff);
|
||||
if (SUCCEEDED(hr)) hr = IDirectMusicSegment8_InsertTrack(segment, parser->chordtrack, 0xffff);
|
||||
if (SUCCEEDED(hr) && parser->tempotrack)
|
||||
hr = IDirectMusicSegment8_InsertTrack(segment, parser->tempotrack, 0xffff);
|
||||
if (SUCCEEDED(hr))
|
||||
hr = IDirectMusicSegment8_InsertTrack(segment, (IDirectMusicTrack *)parser->seqtrack, 0xffff);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void midi_parser_destroy(struct midi_parser *parser)
|
||||
{
|
||||
struct midi_seqtrack_item *item, *next_item;
|
||||
IStream_Release(parser->stream);
|
||||
if (parser->bandtrack) IDirectMusicTrack_Release(parser->bandtrack);
|
||||
if (parser->chordtrack) IDirectMusicTrack_Release(parser->chordtrack);
|
||||
if (parser->tempotrack) IDirectMusicTrack_Release(parser->tempotrack);
|
||||
if (parser->seqtrack) IDirectMusicTrack_Release(parser->seqtrack);
|
||||
LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &parser->seqtrack_items, struct midi_seqtrack_item, entry)
|
||||
{
|
||||
list_remove(&item->entry);
|
||||
free(item);
|
||||
}
|
||||
free(parser);
|
||||
}
|
||||
|
||||
|
@ -334,6 +446,7 @@ static HRESULT midi_parser_new(IStream *stream, struct midi_parser **out_parser)
|
|||
|
||||
parser = calloc(1, sizeof(struct midi_parser));
|
||||
if (!parser) return E_OUTOFMEMORY;
|
||||
list_init(&parser->seqtrack_items);
|
||||
IStream_AddRef(stream);
|
||||
parser->stream = stream;
|
||||
parser->division = division;
|
||||
|
@ -342,6 +455,10 @@ static HRESULT midi_parser_new(IStream *stream, struct midi_parser **out_parser)
|
|||
if (SUCCEEDED(hr))
|
||||
hr = CoCreateInstance(&CLSID_DirectMusicChordTrack, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IDirectMusicTrack, (void **)&parser->chordtrack);
|
||||
if (SUCCEEDED(hr))
|
||||
hr = CoCreateInstance(&CLSID_DirectMusicSeqTrack, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IDirectMusicTrack, (void **)&parser->seqtrack);
|
||||
|
||||
if (FAILED(hr)) midi_parser_destroy(parser);
|
||||
else *out_parser = parser;
|
||||
return hr;
|
||||
|
|
|
@ -483,3 +483,11 @@ HRESULT create_dmseqtrack(REFIID lpcGUID, void **ppobj)
|
|||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void sequence_track_set_items(IDirectMusicTrack8 *track, DMUS_IO_SEQ_ITEM *items, unsigned int count)
|
||||
{
|
||||
struct sequence_track *This = impl_from_IDirectMusicTrack8(track);
|
||||
free(This->items);
|
||||
This->items = items;
|
||||
This->count = count;
|
||||
}
|
||||
|
|
|
@ -1633,6 +1633,27 @@ static void test_midi(void)
|
|||
0xc1, /* event type, program change, channel 1 */
|
||||
0x30, /* event data, patch 48 */
|
||||
};
|
||||
static const char midi_note_on[] =
|
||||
{
|
||||
0x04, /* delta time = 4 */
|
||||
0x91, /* event type, note on, channel 1 */
|
||||
0x3c, /* event data, middle C */
|
||||
0x40, /* event data, velocity 64 */
|
||||
};
|
||||
static const char midi_note_off[] =
|
||||
{
|
||||
0x04, /* delta time = 4 */
|
||||
0x81, /* event type, note off, channel 1 */
|
||||
0x3c, /* event data, middle C */
|
||||
0x0,
|
||||
};
|
||||
static const char midi_note_off2[] =
|
||||
{
|
||||
0x60, /* delta time = 96 */
|
||||
0x81, /* event type, note off, channel 1 */
|
||||
0x3c, /* event data, middle C */
|
||||
0x0,
|
||||
};
|
||||
IDirectMusicSegment8 *segment = NULL;
|
||||
IDirectMusicTrack *track = NULL;
|
||||
IDirectMusicLoader8 *loader;
|
||||
|
@ -1646,8 +1667,10 @@ static void test_midi(void)
|
|||
WCHAR test_mid[MAX_PATH], bogus_mid[MAX_PATH];
|
||||
HRESULT hr;
|
||||
ULONG ret;
|
||||
DWORD track_length;
|
||||
MUSIC_TIME next;
|
||||
DMUS_PMSG *msg;
|
||||
DMUS_NOTE_PMSG *note;
|
||||
DMUS_PATCH_PMSG *patch;
|
||||
DMUS_TEMPO_PARAM tempo_param;
|
||||
#include <pshpack1.h>
|
||||
|
@ -1685,8 +1708,8 @@ static void test_midi(void)
|
|||
expect_track(segment, BandTrack, -1, 0);
|
||||
expect_track(segment, ChordTrack, -1, 1);
|
||||
expect_track(segment, TempoTrack, -1, 2);
|
||||
todo_wine expect_track(segment, TimeSigTrack, -1, 3);
|
||||
todo_wine expect_track(segment, SeqTrack, -1, 4);
|
||||
todo_wine expect_guid_track(segment, TimeSigTrack, -1, 0);
|
||||
expect_guid_track(segment, SeqTrack, -1, 0);
|
||||
/* no more tracks */
|
||||
hr = IDirectMusicSegment8_GetTrack(segment, &GUID_NULL, -1, 5, &track);
|
||||
ok(hr == DMUS_E_NOT_FOUND, "unexpected extra track\n");
|
||||
|
@ -1726,7 +1749,7 @@ static void test_midi(void)
|
|||
/* TempoTrack and TimeSigTrack seems to be optional. */
|
||||
expect_track(segment, BandTrack, -1, 0);
|
||||
expect_track(segment, ChordTrack, -1, 1);
|
||||
todo_wine expect_track(segment, SeqTrack, -1, 2);
|
||||
expect_track(segment, SeqTrack, -1, 2);
|
||||
IDirectMusicSegment_Release(segment);
|
||||
|
||||
/* parse MIDI file with 1 track that has 1 event. */
|
||||
|
@ -1763,7 +1786,7 @@ static void test_midi(void)
|
|||
expect_track(segment, BandTrack, -1, 0);
|
||||
expect_track(segment, ChordTrack, -1, 1);
|
||||
expect_track(segment, TempoTrack, -1, 2);
|
||||
todo_wine expect_track(segment, SeqTrack, -1, 3);
|
||||
expect_track(segment, SeqTrack, -1, 3);
|
||||
|
||||
hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, &next, &tempo_param);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
@ -1811,7 +1834,7 @@ static void test_midi(void)
|
|||
expect_track(segment, BandTrack, -1, 0);
|
||||
expect_track(segment, ChordTrack, -1, 1);
|
||||
/* there is no tempo track. */
|
||||
todo_wine expect_track(segment, SeqTrack, -1, 2);
|
||||
expect_track(segment, SeqTrack, -1, 2);
|
||||
IDirectMusicSegment_Release(segment);
|
||||
|
||||
/* parse MIDI file with program change event. */
|
||||
|
@ -1830,24 +1853,47 @@ static void test_midi(void)
|
|||
header.length = GET_BE_DWORD(sizeof(header) - 8);
|
||||
hr = IStream_Write(stream, &header, sizeof(header), NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
track_header.length = RtlUlongByteSwap(sizeof(track_header) - 8 + sizeof(midi_program_change));
|
||||
track_length = sizeof(midi_program_change) + sizeof(midi_note_on) * 3 + sizeof(midi_note_off);
|
||||
track_header.length = RtlUlongByteSwap(sizeof(track_header) - 8 + track_length);
|
||||
hr = IStream_Write(stream, &track_header, sizeof(track_header), NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IStream_Write(stream, midi_program_change, sizeof(midi_program_change), NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
||||
/* Add note on/off events, like this:
|
||||
* on, on, off, on
|
||||
* So we can test what happens when we have two consecutive note on, and what happens with trailing note on. */
|
||||
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_on, sizeof(midi_note_on), NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IStream_Write(stream, midi_note_off, sizeof(midi_note_off), 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);
|
||||
|
||||
/* 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));
|
||||
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_Seek(stream, zero, 0, NULL);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IPersistStream_Load(persist, stream);
|
||||
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) + sizeof(midi_program_change),
|
||||
ok(position.QuadPart == sizeof(header) + sizeof(track_header) * 2 + track_length + sizeof(midi_note_on) + sizeof(midi_note_off),
|
||||
"got %lld\n", position.QuadPart);
|
||||
IPersistStream_Release(persist);
|
||||
IStream_Release(stream);
|
||||
expect_track(segment, BandTrack, -1, 0);
|
||||
expect_track(segment, ChordTrack, -1, 1);
|
||||
todo_wine expect_track(segment, SeqTrack, -1, 2);
|
||||
expect_track(segment, SeqTrack, -1, 2);
|
||||
|
||||
hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
|
@ -1865,11 +1911,7 @@ static void test_midi(void)
|
|||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
IDirectMusicGraph_Release(graph);
|
||||
|
||||
/* now play the segment, and check produced messages
|
||||
* wine generates: DIRTY, PATCH, DIRTY.
|
||||
* native generates: DIRTY, PATCH
|
||||
*/
|
||||
|
||||
/* now play the segment, and check produced messages */
|
||||
hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0);
|
||||
ok(hr == S_OK, "got %#lx\n", hr);
|
||||
hr = IDirectMusicPerformance_PlaySegment(performance, (IDirectMusicSegment *)segment, 0x800, 0, NULL);
|
||||
|
@ -1891,6 +1933,55 @@ 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_NOTE, "got msg type %#lx, expected NOTE\n", msg->dwType);
|
||||
ok(msg->mtTime == 24, "got mtTime %lu, expected 24\n", msg->mtTime);
|
||||
note = (DMUS_NOTE_PMSG *)msg;
|
||||
ok(note->bMidiValue == 0x3c, "got note %#x, expected 0x3c\n", note->bMidiValue);
|
||||
ok(note->bVelocity == 0x40, "got velocity %#x, expected 0x40\n", note->bVelocity);
|
||||
ok(note->mtDuration == 600, "got mtDuration %lu, expected 600\n", note->mtDuration);
|
||||
ok(note->dwPChannel == 1, "got pchannel %lu, expected 1\n", note->dwPChannel);
|
||||
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_NOTE, "got msg type %#lx, expected NOTE\n", msg->dwType);
|
||||
ok(msg->mtTime == 49, "got mtTime %lu, expected 49\n", msg->mtTime);
|
||||
note = (DMUS_NOTE_PMSG *)msg;
|
||||
ok(note->bMidiValue == 0x3c, "got note %#x, expected 0x3c\n", note->bMidiValue);
|
||||
ok(note->bVelocity == 0x40, "got velocity %#x, expected 0x40\n", note->bVelocity);
|
||||
ok(note->mtDuration == 50, "got mtDuration %lu, expected 50\n", note->mtDuration);
|
||||
ok(note->dwPChannel == 1, "got pchannel %lu, expected 1\n", note->dwPChannel);
|
||||
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_NOTE, "got msg type %#lx, expected NOTE\n", msg->dwType);
|
||||
ok(msg->mtTime == 74, "got mtTime %lu, expected 74\n", msg->mtTime);
|
||||
note = (DMUS_NOTE_PMSG *)msg;
|
||||
ok(note->bMidiValue == 0x3c, "got note %#x, expected 0x3c\n", note->bMidiValue);
|
||||
ok(note->bVelocity == 0x40, "got velocity %#x, expected 0x40\n", note->bVelocity);
|
||||
ok(note->mtDuration == 1, "got mtDuration %lu, expected 1\n", note->mtDuration);
|
||||
ok(note->dwPChannel == 1, "got pchannel %lu, expected 1\n", note->dwPChannel);
|
||||
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_NOTE, "got msg type %#lx, expected NOTE\n", msg->dwType);
|
||||
ok(msg->mtTime == 124, "got mtTime %lu, expected 124\n", msg->mtTime);
|
||||
note = (DMUS_NOTE_PMSG *)msg;
|
||||
ok(note->bMidiValue == 0x3c, "got note %#x, expected 0x3c\n", note->bMidiValue);
|
||||
ok(note->bVelocity == 0x40, "got velocity %#x, expected 0x40\n", note->bVelocity);
|
||||
ok(note->mtDuration == 1, "got mtDuration %ld, expected 1\n", note->mtDuration);
|
||||
ok(note->dwPChannel == 1, "got pchannel %lu, expected 1\n", note->dwPChannel);
|
||||
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");
|
||||
if (!ret)
|
||||
|
|
Loading…
Add table
Reference in a new issue