1
0
mirror of https://github.com/wine-mirror/wine synced 2024-06-29 06:14:34 +00:00

dmime: Parse MIDI headers.

This commit is contained in:
Yuxuan Shui 2024-02-07 14:16:27 +00:00 committed by Alexandre Julliard
parent 4434c17c94
commit d93275c6ca
4 changed files with 128 additions and 1 deletions

View File

@ -10,6 +10,7 @@ SOURCES = \
graph.c \
lyricstrack.c \
markertrack.c \
midi.c \
paramcontroltrack.c \
performance.c \
segment.c \

View File

@ -48,6 +48,7 @@
* Interfaces
*/
typedef struct IDirectMusicAudioPathImpl IDirectMusicAudioPathImpl;
struct midi_parser;
/*****************************************************************************
* ClassFactory
@ -69,6 +70,12 @@ extern HRESULT create_dmtempotrack(REFIID riid, void **ret_iface);
extern HRESULT create_dmtimesigtrack(REFIID riid, void **ret_iface);
extern HRESULT create_dmwavetrack(REFIID riid, void **ret_iface);
/* Create a new MIDI file parser. Note the stream might still be modified even
* when this function fails. */
extern HRESULT midi_parser_new(IStream *stream, struct midi_parser **out_parser);
extern HRESULT midi_parser_next_track(struct midi_parser *parser, IDirectMusicTrack **out_track, MUSIC_TIME *out_length);
extern void midi_parser_destroy(struct midi_parser *parser);
extern void set_audiopath_perf_pointer(IDirectMusicAudioPath*,IDirectMusicPerformance8*);
extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*);
extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*);

105
dlls/dmime/midi.c Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2024 Yuxuan Shui for CodeWeavers
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "dmime_private.h"
#include "winternl.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmime);
#ifdef WORDS_BIGENDIAN
#define GET_BE_WORD(x) (x)
#define GET_BE_DWORD(x) (x)
#else
#define GET_BE_WORD(x) RtlUshortByteSwap(x)
#define GET_BE_DWORD(x) RtlUlongByteSwap(x)
#endif
struct midi_parser
{
IStream *stream;
};
HRESULT midi_parser_next_track(struct midi_parser *parser, IDirectMusicTrack **out_track, MUSIC_TIME *out_length)
{
TRACE("(%p, %p, %p): stub\n", parser, out_track, out_length);
return S_FALSE;
}
HRESULT midi_parser_new(IStream *stream, struct midi_parser **out_parser)
{
LARGE_INTEGER offset;
DWORD length;
HRESULT hr;
WORD format, number_of_tracks, division;
struct midi_parser *parser;
*out_parser = NULL;
/* Skip over the 'MThd' magic number. */
offset.QuadPart = 4;
if (FAILED(hr = IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL))) return hr;
if (FAILED(hr = IStream_Read(stream, &length, sizeof(length), NULL))) return hr;
length = GET_BE_DWORD(length);
if (length != 6)
{
WARN("Invalid MIDI header length %lu\n", length);
return DMUS_E_UNSUPPORTED_STREAM;
}
if (FAILED(hr = IStream_Read(stream, &format, sizeof(format), NULL))) return hr;
format = GET_BE_WORD(format);
if (format > 2)
{
WARN("Invalid MIDI format %u\n", format);
return DMUS_E_UNSUPPORTED_STREAM;
}
if (format == 2)
{
FIXME("MIDI format 2 not implemented yet\n");
return DMUS_E_UNSUPPORTED_STREAM;
}
if (FAILED(hr = IStream_Read(stream, &number_of_tracks, sizeof(number_of_tracks), NULL)))
return hr;
number_of_tracks = GET_BE_WORD(number_of_tracks);
if (FAILED(hr = IStream_Read(stream, &division, sizeof(division), NULL))) return hr;
division = GET_BE_WORD(division);
if (division & 0x8000)
{
WARN("SMPTE time division not implemented yet\n");
return DMUS_E_UNSUPPORTED_STREAM;
}
TRACE("MIDI format %u, %u tracks, division %u\n", format, number_of_tracks, division);
parser = calloc(1, sizeof(struct midi_parser));
if (!parser) return E_OUTOFMEMORY;
parser->stream = stream;
IStream_AddRef(stream);
*out_parser = parser;
return hr;
}
void midi_parser_destroy(struct midi_parser *parser)
{
IStream_Release(parser->stream);
free(parser);
}

View File

@ -791,7 +791,10 @@ static inline struct segment *impl_from_IPersistStream(IPersistStream *iface)
static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream *stream)
{
struct segment *This = impl_from_IPersistStream(iface);
IDirectMusicTrack *track;
MUSIC_TIME length;
struct chunk_entry chunk = {0};
struct midi_parser *midi_parser;
HRESULT hr;
TRACE("(%p, %p): Loading\n", This, stream);
@ -807,7 +810,18 @@ static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream
break;
case mmioFOURCC('M','T','h','d'):
FIXME("MIDI file loading not supported\n");
hr = midi_parser_new(stream, &midi_parser);
if (FAILED(hr)) break;
This->header.mtLength = 0;
while ((hr = midi_parser_next_track(midi_parser, &track, &length)) == S_OK)
{
hr = segment_append_track(This, track, 1, 0);
IDirectMusicTrack_Release(track);
if (FAILED(hr)) break;
if (length > This->header.mtLength)
This->header.mtLength = length;
}
midi_parser_destroy(midi_parser);
break;
case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('W','A','V','E')):