Recently made midi files created with MS tools are
sometimes (often? always?) in the RMID format, which
embeds an ordinary midi file structure inside a
RIFF chunk. SDL_mixer cannot play RMID files, though
the other midi players I have on my system do play
them: pmidi, playmidi, Timidity++.
One reason SDL_mixer can’t play RMID files is that
Mix_LoadMUS() misidentifies them as WAVE files.
It sees the magic RIFF at the beginning of the
file and decides because of that to pass the
file on to WAVStream_LoadSong(), which then
realizes it’s not a WAVE file and rejects it.
This happens even if the filename extension is
".mid".
What Mix_LoadMUS() should do is read on past
the RIFF magic to see whether the next magic
is WAVE, in which case it should be passed on
to WAVStream_LoadSong(), or RMID, in which case
it should be passed on to a midi player.
Here is example replacement code for music.c.
At the beginning of Mix_LoadMUS():
…
Uint8 magic[5], moremagic[9];
Mix_Music *music;
/* Figure out what kind of file this is */
fp = fopen(file, "rb");
if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
if ( fp != NULL ) {
fclose(fp);
}
Mix_SetError("Couldn't read from '%s'", file);
return(NULL);
}
if (!fread(moremagic, 8, 1, fp)) {
Mix_SetError("Couldn't read from '%s'", file);
return(NULL);
}
magic[4] = '\0';
moremagic[8] = '\0';
fclose(fp);
…
Then to call WAVStream_LoadSong():
…
/* WAVE files have the magic four bytes "RIFF"
AIFF files have the magic 12 bytes “FORM” XXXX “AIFF”
*/
if ( (ext && MIX_string_equals(ext, “WAV”)) ||
((strcmp((char *)magic, “RIFF”) == 0) &&
(strcmp((char *)(moremagic+4), “WAVE”) == 0)) ||
(strcmp((char *)magic, “FORM”) == 0) ) {
music->type = MUS_WAV;
music->data.wave = WAVStream_LoadSong(file,
(char )magic);
…
and to call a midi player:
…
/ MIDI files have the magic four bytes “MThd” */
if ( (ext && MIX_string_equals(ext, “MID”)) ||
(ext && MIX_string_equals(ext, “MIDI”)) ||
strcmp((char *)magic, “MThd”) == 0 ||
( strcmp((char *)magic, “RIFF”) == 0 &&
strcmp((char *)(moremagic+4), “RMID”) == 0 ) ) {
music->type = MUS_MID;
…
And now RMID files get routed to the right players. Since
Nathan Laredo’s playmidi already knows about RMID files,
there is no change necessary to the code in
native_midi_gpl/. I don’t know about native_midi/. Timidity
needs a small change in readmidi.c, near the beginning
of read_midi_file():
…
past_riff:
if ((fread(tmp,1,4,fp) != 4) || (fread(&len,4,1,fp) != 1))
{
if (ferror(fp))
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, “%s: %s”,current_filename,
strerror(errno));
}
else
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: Not a MIDI file!", current_filename);
return 0;
}
len=BE_LONG(len);
if (!memcmp(tmp, “RIFF”, 4))
{
fread(tmp,1,12,fp);
goto past_riff;
}
…
will do it.
I’ve verified these changes by using playmus to play WAVE files with
and without the .wav extension, RMID files with and without the .mid
extension, and ordinary midi files, with and without the .mid
extension.
Patches for these changes, as well as for the bugs in native_midi_gpl
and in SDL_audiocvt.c which I’ve mentioned previously, are in
the archive file ftp://ling.lll.hawaii.edu/pub/greg/Surround-SDL.tgz,
along with, of course, the surround sound patches.
Greg