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
f0fc4a0d
Commit
f0fc4a0d
authored
Feb 15, 2024
by
Yuxuan Shui
Committed by
Alexandre Julliard
Mar 01, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dmime: Parse MIDI Set Tempo meta events and generate a tempotrack.
parent
1b1f2162
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
87 additions
and
10 deletions
+87
-10
midi.c
dlls/dmime/midi.c
+71
-8
dmime.c
dlls/dmime/tests/dmime.c
+16
-2
No files found.
dlls/dmime/midi.c
View file @
f0fc4a0d
...
...
@@ -35,18 +35,49 @@ struct midi_event
{
MUSIC_TIME
delta_time
;
BYTE
status
;
BYTE
data
[
2
];
union
{
struct
{
BYTE
data
[
2
];
};
struct
{
BYTE
meta_type
;
ULONG
tempo
;
};
};
};
struct
midi_parser
{
IDirectMusicTrack
*
chordtrack
;
IDirectMusicTrack
*
bandtrack
;
IDirectMusicTrack
*
tempotrack
;
MUSIC_TIME
time
;
IStream
*
stream
;
DWORD
division
;
};
enum
meta_event_type
{
MIDI_META_SEQUENCE_NUMBER
=
0x00
,
MIDI_META_TEXT_EVENT
=
0x01
,
MIDI_META_COPYRIGHT_NOTICE
=
0x02
,
MIDI_META_TRACK_NAME
=
0x03
,
MIDI_META_INSTRUMENT_NAME
=
0x04
,
MIDI_META_LYRIC
=
0x05
,
MIDI_META_MARKER
=
0x06
,
MIDI_META_CUE_POINT
=
0x07
,
MIDI_META_CHANNEL_PREFIX_ASSIGNMENT
=
0x20
,
MIDI_META_END_OF_TRACK
=
0x2f
,
MIDI_META_SET_TEMPO
=
0x51
,
MIDI_META_SMPTE_OFFSET
=
0x54
,
MIDI_META_TIME_SIGNATURE
=
0x58
,
MIDI_META_KEY_SIGNATURE
=
0x59
,
MIDI_META_SEQUENCER_SPECIFIC
=
0x7f
,
};
static
HRESULT
stream_read_at_most
(
IStream
*
stream
,
void
*
buffer
,
ULONG
size
,
ULONG
*
bytes_left
)
{
HRESULT
hr
;
...
...
@@ -76,8 +107,9 @@ static HRESULT read_variable_length_number(IStream *stream, DWORD *out, ULONG *b
static
HRESULT
read_midi_event
(
IStream
*
stream
,
struct
midi_event
*
event
,
BYTE
*
last_status
,
ULONG
*
bytes_left
)
{
BYTE
byte
,
status_type
,
meta_type
;
BYTE
byte
,
status_type
;
DWORD
length
;
BYTE
data
[
3
];
LARGE_INTEGER
offset
;
HRESULT
hr
=
S_OK
;
DWORD
delta_time
;
...
...
@@ -96,21 +128,31 @@ static HRESULT read_midi_event(IStream *stream, struct midi_event *event, BYTE *
if
(
event
->
status
==
MIDI_META
)
{
meta_type
=
byte
;
event
->
meta_type
=
byte
;
if
((
hr
=
read_variable_length_number
(
stream
,
&
length
,
bytes_left
))
!=
S_OK
)
return
hr
;
switch
(
meta_type
)
switch
(
event
->
meta_type
)
{
case
MIDI_META_SET_TEMPO
:
if
(
length
!=
3
)
{
ERR
(
"Invalid MIDI meta event length %lu for set tempo event.
\n
"
,
length
);
return
E_FAIL
;
}
if
(
FAILED
(
hr
=
stream_read_at_most
(
stream
,
data
,
3
,
bytes_left
)))
return
hr
;
event
->
tempo
=
(
data
[
0
]
<<
16
)
|
(
data
[
1
]
<<
8
)
|
data
[
2
];
break
;
default:
if
(
*
bytes_left
<
length
)
return
S_FALSE
;
offset
.
QuadPart
=
length
;
if
(
FAILED
(
hr
=
IStream_Seek
(
stream
,
offset
,
STREAM_SEEK_CUR
,
NULL
)))
return
hr
;
FIXME
(
"MIDI meta event type %#02x, length %lu, time +%lu. not supported
\n
"
,
meta_type
,
length
,
delta_time
);
FIXME
(
"MIDI meta event type %#02x, length %lu, time +%lu. not supported
\n
"
,
event
->
meta_type
,
length
,
delta_time
);
*
bytes_left
-=
length
;
event
->
tempo
=
0
;
}
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
"
,
event
->
meta_type
,
length
,
delta_time
);
return
S_OK
;
}
else
if
(
event
->
status
==
MIDI_SYSEX1
||
event
->
status
==
MIDI_SYSEX2
)
...
...
@@ -148,6 +190,22 @@ static HRESULT read_midi_event(IStream *stream, struct midi_event *event, BYTE *
return
S_OK
;
}
static
HRESULT
midi_parser_handle_set_tempo
(
struct
midi_parser
*
parser
,
struct
midi_event
*
event
)
{
DMUS_TEMPO_PARAM
tempo
;
MUSIC_TIME
dmusic_time
=
(
ULONGLONG
)
parser
->
time
*
DMUS_PPQ
/
parser
->
division
;
HRESULT
hr
;
if
(
!
parser
->
tempotrack
&&
FAILED
(
hr
=
CoCreateInstance
(
&
CLSID_DirectMusicTempoTrack
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IDirectMusicTrack
,
(
void
**
)
&
parser
->
tempotrack
)))
return
hr
;
tempo
.
mtTime
=
dmusic_time
;
tempo
.
dblTempo
=
60
*
1000000
.
0
/
event
->
tempo
;
TRACE
(
"Adding tempo at time %lu, tempo %f
\n
"
,
dmusic_time
,
tempo
.
dblTempo
);
return
IDirectMusicTrack_SetParam
(
parser
->
tempotrack
,
&
GUID_TempoParam
,
dmusic_time
,
&
tempo
);
}
static
HRESULT
midi_parser_handle_program_change
(
struct
midi_parser
*
parser
,
struct
midi_event
*
event
)
{
HRESULT
hr
;
...
...
@@ -206,7 +264,9 @@ static HRESULT midi_parser_parse(struct midi_parser *parser, IDirectMusicSegment
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
)
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
);
if
(
FAILED
(
hr
))
break
;
}
...
...
@@ -223,6 +283,8 @@ static HRESULT midi_parser_parse(struct midi_parser *parser, IDirectMusicSegment
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
);
return
hr
;
}
...
...
@@ -232,6 +294,7 @@ static void midi_parser_destroy(struct midi_parser *parser)
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
);
free
(
parser
);
}
...
...
dlls/dmime/tests/dmime.c
View file @
f0fc4a0d
...
...
@@ -1646,8 +1646,10 @@ static void test_midi(void)
WCHAR
test_mid
[
MAX_PATH
],
bogus_mid
[
MAX_PATH
];
HRESULT
hr
;
ULONG
ret
;
MUSIC_TIME
next
;
DMUS_PMSG
*
msg
;
DMUS_PATCH_PMSG
*
patch
;
DMUS_TEMPO_PARAM
tempo_param
;
#include <pshpack1.h>
struct
{
...
...
@@ -1682,7 +1684,7 @@ static void test_midi(void)
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
expect_track
(
segment
,
TempoTrack
,
-
1
,
2
);
expect_track
(
segment
,
TempoTrack
,
-
1
,
2
);
todo_wine
expect_track
(
segment
,
TimeSigTrack
,
-
1
,
3
);
todo_wine
expect_track
(
segment
,
SeqTrack
,
-
1
,
4
);
/* no more tracks */
...
...
@@ -1760,8 +1762,20 @@ static void test_midi(void)
IStream_Release
(
stream
);
expect_track
(
segment
,
BandTrack
,
-
1
,
0
);
expect_track
(
segment
,
ChordTrack
,
-
1
,
1
);
todo_wine
expect_track
(
segment
,
TempoTrack
,
-
1
,
2
);
expect_track
(
segment
,
TempoTrack
,
-
1
,
2
);
todo_wine
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
);
ok
(
next
==
24
,
"got %ld, expected 24
\n
"
,
next
);
ok
(
tempo_param
.
mtTime
==
24
,
"got %ld, expected 24
\n
"
,
tempo_param
.
mtTime
);
ok
(
tempo_param
.
dblTempo
==
300
.
0
,
"got %f, expected 300.0
\n
"
,
tempo_param
.
dblTempo
);
hr
=
IDirectMusicSegment_GetParam
(
segment
,
&
GUID_TempoParam
,
-
1
,
DMUS_SEG_ALLTRACKS
,
26
,
&
next
,
&
tempo_param
);
ok
(
hr
==
S_OK
,
"got %#lx
\n
"
,
hr
);
ok
(
next
==
0
,
"got %ld, expected 24
\n
"
,
next
);
ok
(
tempo_param
.
mtTime
==
-
2
,
"got %ld, expected -6
\n
"
,
tempo_param
.
mtTime
);
ok
(
tempo_param
.
dblTempo
==
300
.
0
,
"got %f, expected 300.0
\n
"
,
tempo_param
.
dblTempo
);
IDirectMusicSegment_Release
(
segment
);
/* parse MIDI file with a track with 0 length, but has an event. */
...
...
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