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
28b94c4d
Commit
28b94c4d
authored
Feb 22, 2024
by
Yuxuan Shui
Committed by
Alexandre Julliard
Mar 06, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dmime: Handle MIDI control events in MIDI files.
Adding them to the seqtrack, and also implementing playing them from the seqtrack.
parent
5ff94358
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
89 additions
and
30 deletions
+89
-30
midi.c
dlls/dmime/midi.c
+32
-16
seqtrack.c
dlls/dmime/seqtrack.c
+31
-11
dmime.c
dlls/dmime/tests/dmime.c
+26
-3
No files found.
dlls/dmime/midi.c
View file @
28b94c4d
...
...
@@ -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
;
...
...
dlls/dmime/seqtrack.c
View file @
28b94c4d
...
...
@@ -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
**
)
&
note
)))
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
)))
...
...
dlls/dmime/tests/dmime.c
View file @
28b94c4d
...
...
@@ -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 <pshpack1.h>
...
...
@@ -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
"
);
...
...
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