Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
05347b97
Commit
05347b97
authored
Feb 27, 2024
by
Yuxuan Shui
Committed by
Alexandre Julliard
Feb 28, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dmime: Parse MIDI program change events and generate a bandtrack.
parent
aebcb1a9
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
236 additions
and
23 deletions
+236
-23
Makefile.in
dlls/dmime/Makefile.in
+1
-0
midi.c
dlls/dmime/midi.c
+93
-19
dmime.c
dlls/dmime/tests/dmime.c
+126
-4
band.c
dlls/dmusic/band.c
+14
-0
dmusic_band.h
dlls/dmusic/dmusic_band.h
+2
-0
No files found.
dlls/dmime/Makefile.in
View file @
05347b97
...
@@ -4,6 +4,7 @@ PARENTSRC = ../dmusic
...
@@ -4,6 +4,7 @@ PARENTSRC = ../dmusic
SOURCES
=
\
SOURCES
=
\
audiopath.c
\
audiopath.c
\
band.c
\
dmime.idl
\
dmime.idl
\
dmime_main.c
\
dmime_main.c
\
dmobject.c
\
dmobject.c
\
...
...
dlls/dmime/midi.c
View file @
05347b97
...
@@ -18,6 +18,7 @@
...
@@ -18,6 +18,7 @@
#include "dmusic_midi.h"
#include "dmusic_midi.h"
#include "dmime_private.h"
#include "dmime_private.h"
#include "dmusic_band.h"
#include "winternl.h"
#include "winternl.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
dmime
);
WINE_DEFAULT_DEBUG_CHANNEL
(
dmime
);
...
@@ -30,9 +31,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime);
...
@@ -30,9 +31,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime);
#define GET_BE_DWORD(x) RtlUlongByteSwap(x)
#define GET_BE_DWORD(x) RtlUlongByteSwap(x)
#endif
#endif
struct
midi_event
{
MUSIC_TIME
delta_time
;
BYTE
status
;
BYTE
data
[
2
];
};
struct
midi_parser
struct
midi_parser
{
{
IDirectMusicTrack
*
bandtrack
;
MUSIC_TIME
time
;
IStream
*
stream
;
IStream
*
stream
;
DWORD
division
;
};
};
static
HRESULT
stream_read_at_most
(
IStream
*
stream
,
void
*
buffer
,
ULONG
size
,
ULONG
*
bytes_left
)
static
HRESULT
stream_read_at_most
(
IStream
*
stream
,
void
*
buffer
,
ULONG
size
,
ULONG
*
bytes_left
)
...
@@ -62,26 +73,27 @@ static HRESULT read_variable_length_number(IStream *stream, DWORD *out, ULONG *b
...
@@ -62,26 +73,27 @@ static HRESULT read_variable_length_number(IStream *stream, DWORD *out, ULONG *b
return
S_OK
;
return
S_OK
;
}
}
static
HRESULT
read_midi_event
(
IStream
*
stream
,
BYTE
*
last_status
,
ULONG
*
bytes_left
)
static
HRESULT
read_midi_event
(
IStream
*
stream
,
struct
midi_event
*
event
,
BYTE
*
last_status
,
ULONG
*
bytes_left
)
{
{
BYTE
byte
,
status
,
meta_type
;
BYTE
byte
,
status
_type
,
meta_type
;
DWORD
length
;
DWORD
length
;
LARGE_INTEGER
offset
;
LARGE_INTEGER
offset
;
HRESULT
hr
=
S_OK
;
HRESULT
hr
=
S_OK
;
DWORD
delta_time
;
DWORD
delta_time
;
if
((
hr
=
read_variable_length_number
(
stream
,
&
delta_time
,
bytes_left
))
!=
S_OK
)
return
hr
;
if
((
hr
=
read_variable_length_number
(
stream
,
&
delta_time
,
bytes_left
))
!=
S_OK
)
return
hr
;
event
->
delta_time
=
delta_time
;
if
((
hr
=
stream_read_at_most
(
stream
,
&
byte
,
1
,
bytes_left
))
!=
S_OK
)
return
hr
;
if
((
hr
=
stream_read_at_most
(
stream
,
&
byte
,
1
,
bytes_left
))
!=
S_OK
)
return
hr
;
if
(
byte
&
0x80
)
if
(
byte
&
0x80
)
{
{
status
=
*
last_status
=
byte
;
event
->
status
=
*
last_status
=
byte
;
if
((
hr
=
stream_read_at_most
(
stream
,
&
byte
,
1
,
bytes_left
))
!=
S_OK
)
return
hr
;
if
((
hr
=
stream_read_at_most
(
stream
,
&
byte
,
1
,
bytes_left
))
!=
S_OK
)
return
hr
;
}
}
else
status
=
*
last_status
;
else
event
->
status
=
*
last_status
;
if
(
status
==
MIDI_META
)
if
(
event
->
status
==
MIDI_META
)
{
{
meta_type
=
byte
;
meta_type
=
byte
;
...
@@ -98,8 +110,9 @@ static HRESULT read_midi_event(IStream *stream, BYTE *last_status, ULONG *bytes_
...
@@ -98,8 +110,9 @@ static HRESULT read_midi_event(IStream *stream, BYTE *last_status, ULONG *bytes_
*
bytes_left
-=
length
;
*
bytes_left
-=
length
;
}
}
TRACE
(
"MIDI meta event type %#02x, length %lu, time +%lu
\n
"
,
meta_type
,
length
,
delta_time
);
TRACE
(
"MIDI meta event type %#02x, length %lu, time +%lu
\n
"
,
meta_type
,
length
,
delta_time
);
return
S_OK
;
}
}
else
if
(
status
==
MIDI_SYSEX1
||
status
==
MIDI_SYSEX2
)
else
if
(
event
->
status
==
MIDI_SYSEX1
||
event
->
status
==
MIDI_SYSEX2
)
{
{
if
(
byte
&
0x80
)
if
(
byte
&
0x80
)
{
{
...
@@ -112,33 +125,74 @@ static HRESULT read_midi_event(IStream *stream, BYTE *last_status, ULONG *bytes_
...
@@ -112,33 +125,74 @@ static HRESULT read_midi_event(IStream *stream, BYTE *last_status, ULONG *bytes_
offset
.
QuadPart
=
length
;
offset
.
QuadPart
=
length
;
if
(
FAILED
(
hr
=
IStream_Seek
(
stream
,
offset
,
STREAM_SEEK_CUR
,
NULL
)))
return
hr
;
if
(
FAILED
(
hr
=
IStream_Seek
(
stream
,
offset
,
STREAM_SEEK_CUR
,
NULL
)))
return
hr
;
*
bytes_left
-=
length
;
*
bytes_left
-=
length
;
FIXME
(
"MIDI sysex event type %#02x, length %lu, time +%lu. not supported
\n
"
,
status
,
length
,
delta_time
);
FIXME
(
"MIDI sysex event type %#02x, length %lu, time +%lu. not supported
\n
"
,
event
->
status
,
length
,
delta_time
);
return
S_OK
;
}
status_type
=
event
->
status
&
0xf0
;
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
);
}
}
else
else
{
{
if
((
status
&
0xf0
)
!=
MIDI_PROGRAM_CHANGE
&&
(
status
&
0xf0
)
!=
MIDI_CHANNEL_PRESSURE
&&
if
(
status_type
!=
MIDI_CHANNEL_PRESSURE
&&
(
hr
=
stream_read_at_most
(
stream
,
&
byte
,
1
,
bytes_left
))
!=
S_OK
)
(
hr
=
stream_read_at_most
(
stream
,
&
byte
,
1
,
bytes_left
))
!=
S_OK
)
return
hr
;
return
hr
;
FIXME
(
"MIDI event status %#02x, time +%lu, not supported
\n
"
,
status
,
delta_time
);
FIXME
(
"MIDI event status %#02x, time +%lu, not supported
\n
"
,
event
->
status
,
delta_time
);
}
}
return
S_OK
;
return
S_OK
;
}
}
static
HRESULT
midi_parser_handle_program_change
(
struct
midi_parser
*
parser
,
struct
midi_event
*
event
)
{
HRESULT
hr
;
DMUS_IO_INSTRUMENT
instrument
;
IDirectMusicBand
*
band
;
DMUS_BAND_PARAM
band_param
;
MUSIC_TIME
dmusic_time
=
(
ULONGLONG
)
parser
->
time
*
DMUS_PPQ
/
parser
->
division
;
instrument
.
dwPChannel
=
event
->
status
&
0xf
;
instrument
.
dwFlags
=
DMUS_IO_INST_PATCH
;
instrument
.
dwPatch
=
event
->
data
[
0
];
if
(
FAILED
(
hr
=
CoCreateInstance
(
&
CLSID_DirectMusicBand
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IDirectMusicBand
,
(
void
**
)
&
band
)))
return
hr
;
hr
=
band_add_instrument
(
band
,
&
instrument
);
if
(
SUCCEEDED
(
hr
))
{
TRACE
(
"Adding band at time %lu
\n
"
,
dmusic_time
);
band_param
.
pBand
=
band
;
band_param
.
mtTimePhysical
=
dmusic_time
;
hr
=
IDirectMusicTrack_SetParam
(
parser
->
bandtrack
,
&
GUID_BandParam
,
dmusic_time
,
&
band_param
);
}
else
WARN
(
"Failed to add instrument to band
\n
"
);
IDirectMusicBand_Release
(
band
);
return
hr
;
}
static
HRESULT
midi_parser_parse
(
struct
midi_parser
*
parser
,
IDirectMusicSegment8
*
segment
)
static
HRESULT
midi_parser_parse
(
struct
midi_parser
*
parser
,
IDirectMusicSegment8
*
segment
)
{
{
WORD
i
=
0
;
WORD
i
=
0
;
TRACE
(
"(%p, %p): stub
\n
"
,
parser
,
segment
);
HRESULT
hr
;
MUSIC_TIME
music_length
=
0
;
TRACE
(
"(%p, %p): semi-stub
\n
"
,
parser
,
segment
);
for
(
i
=
0
;;
i
++
)
for
(
i
=
0
;;
i
++
)
{
{
HRESULT
hr
;
BYTE
magic
[
4
]
=
{
0
},
last_status
=
0
;
BYTE
magic
[
4
]
=
{
0
},
last_status
=
0
;
DWORD
length_be
;
DWORD
length_be
;
ULONG
length
;
ULONG
length
;
ULONG
read
=
0
;
ULONG
read
=
0
;
struct
midi_event
event
=
{
0
};
TRACE
(
"Start parsing track %u
\n
"
,
i
);
TRACE
(
"Start parsing track %u
\n
"
,
i
);
if
((
hr
=
IStream_Read
(
parser
->
stream
,
magic
,
sizeof
(
magic
),
&
read
))
!=
S_OK
)
return
hr
;
if
((
hr
=
IStream_Read
(
parser
->
stream
,
magic
,
sizeof
(
magic
),
&
read
))
!=
S_OK
)
break
;
if
(
read
<
sizeof
(
magic
))
break
;
if
(
read
<
sizeof
(
magic
))
break
;
if
(
memcmp
(
magic
,
"MTrk"
,
4
)
!=
0
)
break
;
if
(
memcmp
(
magic
,
"MTrk"
,
4
)
!=
0
)
break
;
...
@@ -148,20 +202,32 @@ static HRESULT midi_parser_parse(struct midi_parser *parser, IDirectMusicSegment
...
@@ -148,20 +202,32 @@ static HRESULT midi_parser_parse(struct midi_parser *parser, IDirectMusicSegment
length
=
GET_BE_DWORD
(
length_be
);
length
=
GET_BE_DWORD
(
length_be
);
TRACE
(
"Track %u, length %lu bytes
\n
"
,
i
,
length
);
TRACE
(
"Track %u, length %lu bytes
\n
"
,
i
,
length
);
while
((
hr
=
read_midi_event
(
parser
->
stream
,
&
last_status
,
&
length
))
==
S_OK
)
while
((
hr
=
read_midi_event
(
parser
->
stream
,
&
event
,
&
last_status
,
&
length
))
==
S_OK
)
;
{
parser
->
time
+=
event
.
delta_time
;
if
((
event
.
status
&
0xf0
)
==
MIDI_PROGRAM_CHANGE
)
hr
=
midi_parser_handle_program_change
(
parser
,
&
event
);
if
(
FAILED
(
hr
))
break
;
}
if
(
FAILED
(
hr
))
return
hr
;
if
(
FAILED
(
hr
))
break
;
TRACE
(
"End of track %u
\n
"
,
i
);
TRACE
(
"End of track %u
\n
"
,
i
);
if
(
parser
->
time
>
music_length
)
music_length
=
parser
->
time
;
parser
->
time
=
0
;
}
}
TRACE
(
"End of file
\n
"
);
TRACE
(
"End of file
\n
"
);
return
S_FALSE
;
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
);
return
hr
;
}
}
static
void
midi_parser_destroy
(
struct
midi_parser
*
parser
)
static
void
midi_parser_destroy
(
struct
midi_parser
*
parser
)
{
{
IStream_Release
(
parser
->
stream
);
IStream_Release
(
parser
->
stream
);
IDirectMusicTrack_Release
(
parser
->
bandtrack
);
free
(
parser
);
free
(
parser
);
}
}
...
@@ -202,9 +268,17 @@ static HRESULT midi_parser_new(IStream *stream, struct midi_parser **out_parser)
...
@@ -202,9 +268,17 @@ static HRESULT midi_parser_new(IStream *stream, struct midi_parser **out_parser)
parser
=
calloc
(
1
,
sizeof
(
struct
midi_parser
));
parser
=
calloc
(
1
,
sizeof
(
struct
midi_parser
));
if
(
!
parser
)
return
E_OUTOFMEMORY
;
if
(
!
parser
)
return
E_OUTOFMEMORY
;
parser
->
stream
=
stream
;
parser
->
stream
=
stream
;
IStream_AddRef
(
stream
);
parser
->
division
=
division
;
*
out_parser
=
parser
;
hr
=
CoCreateInstance
(
&
CLSID_DirectMusicBandTrack
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IDirectMusicTrack
,
(
void
**
)
&
parser
->
bandtrack
);
if
(
FAILED
(
hr
))
{
free
(
parser
);
return
hr
;
}
*
out_parser
=
parser
;
IStream_AddRef
(
stream
);
return
hr
;
return
hr
;
}
}
...
...
dlls/dmime/tests/dmime.c
View file @
05347b97
...
@@ -1600,6 +1600,25 @@ static void _expect_track(IDirectMusicSegment8 *seg, REFCLSID expect, const char
...
@@ -1600,6 +1600,25 @@ static void _expect_track(IDirectMusicSegment8 *seg, REFCLSID expect, const char
static
void
test_midi
(
void
)
static
void
test_midi
(
void
)
{
{
static
const
DWORD
message_types
[]
=
{
DMUS_PMSGT_MIDI
,
DMUS_PMSGT_NOTE
,
DMUS_PMSGT_SYSEX
,
DMUS_PMSGT_NOTIFICATION
,
DMUS_PMSGT_TEMPO
,
DMUS_PMSGT_CURVE
,
DMUS_PMSGT_TIMESIG
,
DMUS_PMSGT_PATCH
,
DMUS_PMSGT_TRANSPOSE
,
DMUS_PMSGT_CHANNEL_PRIORITY
,
DMUS_PMSGT_STOP
,
DMUS_PMSGT_DIRTY
,
DMUS_PMSGT_WAVE
,
DMUS_PMSGT_LYRIC
,
DMUS_PMSGT_SCRIPTLYRIC
,
DMUS_PMSGT_USER
,
};
static
const
char
midi_meta_set_tempo
[]
=
static
const
char
midi_meta_set_tempo
[]
=
{
{
0x04
,
/* delta time = 4 */
0x04
,
/* delta time = 4 */
...
@@ -1608,15 +1627,27 @@ static void test_midi(void)
...
@@ -1608,15 +1627,27 @@ static void test_midi(void)
0x03
,
/* event data lenght, 3 bytes */
0x03
,
/* event data lenght, 3 bytes */
0x03
,
0x0d
,
0x40
/* tempo, 200000 us per quarter-note, i.e. 300 bpm */
0x03
,
0x0d
,
0x40
/* tempo, 200000 us per quarter-note, i.e. 300 bpm */
};
};
static
const
char
midi_program_change
[]
=
{
0x04
,
/* delta time = 4 */
0xc1
,
/* event type, program change, channel 1 */
0x30
,
/* event data, patch 48 */
};
IDirectMusicSegment8
*
segment
=
NULL
;
IDirectMusicSegment8
*
segment
=
NULL
;
IDirectMusicTrack
*
track
=
NULL
;
IDirectMusicTrack
*
track
=
NULL
;
IDirectMusicLoader8
*
loader
;
IDirectMusicLoader8
*
loader
;
IDirectMusicTool
*
tool
;
IDirectMusicPerformance
*
performance
;
IDirectMusicGraph
*
graph
;
IPersistStream
*
persist
;
IPersistStream
*
persist
;
IStream
*
stream
;
IStream
*
stream
;
LARGE_INTEGER
zero
=
{
.
QuadPart
=
0
};
LARGE_INTEGER
zero
=
{
.
QuadPart
=
0
};
ULARGE_INTEGER
position
=
{
.
QuadPart
=
0
};
ULARGE_INTEGER
position
=
{
.
QuadPart
=
0
};
WCHAR
test_mid
[
MAX_PATH
],
bogus_mid
[
MAX_PATH
];
WCHAR
test_mid
[
MAX_PATH
],
bogus_mid
[
MAX_PATH
];
HRESULT
hr
;
HRESULT
hr
;
ULONG
ret
;
DMUS_PMSG
*
msg
;
DMUS_PATCH_PMSG
*
patch
;
#include <pshpack1.h>
#include <pshpack1.h>
struct
struct
{
{
...
@@ -1649,7 +1680,7 @@ static void test_midi(void)
...
@@ -1649,7 +1680,7 @@ static void test_midi(void)
&
IID_IDirectMusicSegment
,
test_mid
,
(
void
**
)
&
segment
);
&
IID_IDirectMusicSegment
,
test_mid
,
(
void
**
)
&
segment
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
todo_wine
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
todo_wine
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
expect_track
(
segment
,
TempoTrack
,
-
1
,
2
);
todo_wine
expect_track
(
segment
,
TempoTrack
,
-
1
,
2
);
todo_wine
expect_track
(
segment
,
TimeSigTrack
,
-
1
,
3
);
todo_wine
expect_track
(
segment
,
TimeSigTrack
,
-
1
,
3
);
...
@@ -1691,7 +1722,7 @@ static void test_midi(void)
...
@@ -1691,7 +1722,7 @@ static void test_midi(void)
IPersistStream_Release
(
persist
);
IPersistStream_Release
(
persist
);
IStream_Release
(
stream
);
IStream_Release
(
stream
);
/* TempoTrack and TimeSigTrack seems to be optional. */
/* TempoTrack and TimeSigTrack seems to be optional. */
todo_wine
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
todo_wine
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
expect_track
(
segment
,
SeqTrack
,
-
1
,
2
);
todo_wine
expect_track
(
segment
,
SeqTrack
,
-
1
,
2
);
IDirectMusicSegment_Release
(
segment
);
IDirectMusicSegment_Release
(
segment
);
...
@@ -1727,7 +1758,7 @@ static void test_midi(void)
...
@@ -1727,7 +1758,7 @@ static void test_midi(void)
"got %lld
\n
"
,
position
.
QuadPart
);
"got %lld
\n
"
,
position
.
QuadPart
);
IPersistStream_Release
(
persist
);
IPersistStream_Release
(
persist
);
IStream_Release
(
stream
);
IStream_Release
(
stream
);
todo_wine
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
todo_wine
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
expect_track
(
segment
,
TempoTrack
,
-
1
,
2
);
todo_wine
expect_track
(
segment
,
TempoTrack
,
-
1
,
2
);
todo_wine
expect_track
(
segment
,
SeqTrack
,
-
1
,
3
);
todo_wine
expect_track
(
segment
,
SeqTrack
,
-
1
,
3
);
...
@@ -1763,11 +1794,102 @@ static void test_midi(void)
...
@@ -1763,11 +1794,102 @@ static void test_midi(void)
ok
(
position
.
QuadPart
==
sizeof
(
header
)
+
sizeof
(
track_header
)
+
4
,
"got %lld
\n
"
,
position
.
QuadPart
);
ok
(
position
.
QuadPart
==
sizeof
(
header
)
+
sizeof
(
track_header
)
+
4
,
"got %lld
\n
"
,
position
.
QuadPart
);
IPersistStream_Release
(
persist
);
IPersistStream_Release
(
persist
);
IStream_Release
(
stream
);
IStream_Release
(
stream
);
todo_wine
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
todo_wine
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
/* there is no tempo track. */
/* there is no tempo track. */
todo_wine
expect_track
(
segment
,
SeqTrack
,
-
1
,
2
);
todo_wine
expect_track
(
segment
,
SeqTrack
,
-
1
,
2
);
IDirectMusicSegment_Release
(
segment
);
IDirectMusicSegment_Release
(
segment
);
/* parse MIDI file with program change event. */
hr
=
CoCreateInstance
(
&
CLSID_DirectMusicSegment
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IDirectMusicSegment
,
(
void
**
)
&
segment
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
hr
=
IDirectMusicSegment_QueryInterface
(
segment
,
&
IID_IPersistStream
,
(
void
**
)
&
persist
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
hr
=
CreateStreamOnHGlobal
(
0
,
TRUE
,
&
stream
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
header
.
format
=
GET_BE_WORD
(
123
);
header
.
count
=
GET_BE_WORD
(
123
);
header
.
ppqn
=
GET_BE_WORD
(
123
);
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
));
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
);
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
),
"got %lld
\n
"
,
position
.
QuadPart
);
IPersistStream_Release
(
persist
);
IStream_Release
(
stream
);
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
todo_wine
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
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
);
hr
=
CoCreateInstance
(
&
CLSID_DirectMusicPerformance
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IDirectMusicPerformance
,
(
void
**
)
&
performance
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
hr
=
CoCreateInstance
(
&
CLSID_DirectMusicGraph
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IDirectMusicGraph
,
(
void
**
)
&
graph
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
hr
=
IDirectMusicGraph_InsertTool
(
graph
,
(
IDirectMusicTool
*
)
tool
,
NULL
,
0
,
-
1
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
hr
=
IDirectMusicPerformance_SetGraph
(
performance
,
graph
);
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
*/
hr
=
IDirectMusicPerformance_Init
(
performance
,
NULL
,
0
,
0
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
hr
=
IDirectMusicPerformance_PlaySegment
(
performance
,
(
IDirectMusicSegment
*
)
segment
,
0x800
,
0
,
NULL
);
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_DIRTY
,
"got %#lx, expected DIRTY
\n
"
,
msg
->
dwType
);
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_PATCH
,
"got msg type %#lx, expected PATCH
\n
"
,
msg
->
dwType
);
ok
(
msg
->
dwPChannel
==
1
,
"got pchannel %lu, expected 1
\n
"
,
msg
->
dwPChannel
);
todo_wine
ok
(
msg
->
mtTime
==
23
,
"got mtTime %lu, expected 23
\n
"
,
msg
->
mtTime
);
patch
=
(
DMUS_PATCH_PMSG
*
)
msg
;
ok
(
patch
->
byInstrument
==
0x30
,
"got instrument %#x, expected 0x30
\n
"
,
patch
->
byInstrument
);
hr
=
IDirectMusicPerformance_FreePMsg
(
performance
,
msg
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
ret
=
test_tool_wait_message
(
tool
,
500
,
(
DMUS_PMSG
**
)
&
msg
);
todo_wine
ok
(
ret
==
WAIT_TIMEOUT
,
"unexpected message
\n
"
);
if
(
!
ret
)
{
hr
=
IDirectMusicPerformance_FreePMsg
(
performance
,
msg
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
}
hr
=
IDirectMusicPerformance_CloseDown
(
performance
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
IDirectMusicPerformance_Release
(
performance
);
IDirectMusicTool_Release
(
tool
);
IDirectMusicSegment_Release
(
segment
);
IDirectMusicLoader8_Release
(
loader
);
IDirectMusicLoader8_Release
(
loader
);
}
}
...
...
dlls/dmusic/band.c
View file @
05347b97
...
@@ -527,3 +527,17 @@ HRESULT band_send_messages(IDirectMusicBand *iface, IDirectMusicPerformance *per
...
@@ -527,3 +527,17 @@ HRESULT band_send_messages(IDirectMusicBand *iface, IDirectMusicPerformance *per
return
hr
;
return
hr
;
}
}
HRESULT
band_add_instrument
(
IDirectMusicBand
*
iface
,
DMUS_IO_INSTRUMENT
*
instrument
)
{
struct
band
*
This
=
impl_from_IDirectMusicBand
(
iface
);
struct
instrument_entry
*
entry
;
TRACE
(
"%p, %p
\n
"
,
iface
,
instrument
);
if
(
!
(
entry
=
calloc
(
1
,
sizeof
(
*
entry
))))
return
E_OUTOFMEMORY
;
entry
->
instrument
=
*
instrument
;
list_add_tail
(
&
This
->
instruments
,
&
entry
->
entry
);
return
S_OK
;
}
dlls/dmusic/dmusic_band.h
View file @
05347b97
...
@@ -18,8 +18,10 @@
...
@@ -18,8 +18,10 @@
*/
*/
#include "dmusici.h"
#include "dmusici.h"
#include "dmusicf.h"
extern
HRESULT
create_dmband
(
REFIID
riid
,
void
**
ret_iface
);
extern
HRESULT
create_dmband
(
REFIID
riid
,
void
**
ret_iface
);
extern
HRESULT
band_connect_to_collection
(
IDirectMusicBand
*
iface
,
IDirectMusicCollection
*
collection
);
extern
HRESULT
band_connect_to_collection
(
IDirectMusicBand
*
iface
,
IDirectMusicCollection
*
collection
);
extern
HRESULT
band_send_messages
(
IDirectMusicBand
*
iface
,
IDirectMusicPerformance
*
performance
,
extern
HRESULT
band_send_messages
(
IDirectMusicBand
*
iface
,
IDirectMusicPerformance
*
performance
,
IDirectMusicGraph
*
graph
,
MUSIC_TIME
time
,
DWORD
track_id
);
IDirectMusicGraph
*
graph
,
MUSIC_TIME
time
,
DWORD
track_id
);
HRESULT
band_add_instrument
(
IDirectMusicBand
*
iface
,
DMUS_IO_INSTRUMENT
*
instrument
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment