dmime: Parse MIDI headers.
This commit is contained in:
parent
4434c17c94
commit
d93275c6ca
4 changed files with 128 additions and 1 deletions
|
@ -10,6 +10,7 @@ SOURCES = \
|
|||
graph.c \
|
||||
lyricstrack.c \
|
||||
markertrack.c \
|
||||
midi.c \
|
||||
paramcontroltrack.c \
|
||||
performance.c \
|
||||
segment.c \
|
||||
|
|
|
@ -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
105
dlls/dmime/midi.c
Normal 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);
|
||||
}
|
|
@ -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')):
|
||||
|
|
Loading…
Add table
Reference in a new issue