How to add Mix_SetMusicCMD (Could this be added to main branch?)

See MPE's post (his patch) for an external program to render midi (and bypass sdl_mixer's broken internal midi (timidity and fluidsynth) in Linux).

Rest if this first post is old but hope Quasar can add portmidi or sdl's Mix_MusicCMD for proper midi rendering; when he doesn't care about his life :P

Could you please please, pretty please add portmidi to eternity? Would fix every midi problem on all three platforms (Mac OS, Windows and Linux)... Eternity already has the most unique and awesome sound engine (low pass filter and equalizer is true sweetness!). Thought zdoom was good but Eternity is really where it's at (at least for me). But sdl_mixer really kills the midi playback...

http://portmedia.sourceforge.net/portmidi/

EDIT
Here's an example of the epic awfulness that is sdl_mixer. Also included portmidi examples so you can see the huge difference (each file's around 500-700 kilobytes). Portmidi and sdl_mixer are using the exact same patchset.

http://speedy.sh/gYrVd/e1m1-portmidi.ogg
http://speedy.sh/ja3dE/e1m1-sdlmixer.ogg
http://speedy.sh/bTDEM/map02-portmidi.ogg
http://speedy.sh/GsvMH/map02-sdlmixer.ogg
Notice how some drums in map02-sdlmixer.ogg sound almost Atari like... Man it is awful. Not to mention the lead instrument is really loud and imbalanced. E1M1-sdlmixer has serious flaws in all respects (overdriven guitar flops out completely or is way too quiet?).

Sdl_mixer is really messed up. They even added soundfont support to their latest sdl_mixer version which has very similar flaws despite using a totally different backend (fluidsynth). Sdl_mixer for midi should be avoided like the plague in all doom source ports! There's never been such a flaw in dos source ports that used allegro and that was over a decade ago... Sdl_mixer is way too flawed and inappropriately developed for midi playback.

Share this post


Link to post

Just so the public knows, I am considering and investigating this currently.

Share this post


Link to post

That's really freakin' cool that you're even considering it. I'm not joking. Really hope eternity ends up with it; can't wait!

Portmidi is so much better for midi it's not even funny. Dependencies seem pretty minimal too.

Tried making a thread about these issues on sdl's forums before, but I get a "super grant access required" error message (and still do). Really strange forum...

Please let us know when eternity get's this! Seriously; Eternity is the best modern source port that's come to doomers! Cardboard + portmidi=Th3PWnzzZ1!1one!

Share this post


Link to post

Noticed sdl_mixer has Mix_SetMusicCMD. Tried adding it to Eternity but I know nothing about SDL_RWops. My problem is telling the mus to midi code to output a temporary file somewhere so Mix_SetMusicCMD and Mix_LoadMUS can read that (Mix_LoadMUS_RW can't read a 'const char *file' AFAIK; correct me if I'm wrong).

Was able to add this in chocolate-doom and got way better midi playback on linux; could use Timidity++, hardware midi, or anything really. Mix_SetMusicCMD basically calls an external program defined in i_sdlmusic.cpp or an environment variable (environment variable is the best way IMO; Eduke32 uses this function and does it this way actually). If there's no program specified it falls back to sdl_mixer's awful built-in midi playback or the bad general midi in windows (don't know about Mac OSX).

When you're not busy and feel like doing nothing, maybe you can help me add Mix_SetMusicCMD; especially if you decide to not add portmidi or other midi functions to linux.

Best regards

Share this post


Link to post
Holering said:

Noticed sdl_mixer has Mix_SetMusicCMD. Tried adding it to Eternity but I know nothing about SDL_RWops. My problem is telling the mus to midi code to output a temporary file somewhere so Mix_SetMusicCMD and Mix_LoadMUS can read that (Mix_LoadMUS_RW can't read a 'const char *file' AFAIK; correct me if I'm wrong).

A quick look at the SDL header file SDL_RWops.h gave me this:

SDL_RWFromFile(const char *file, const char *mode);
Just use this function with a char * to /tmp/doom.mid (or whatever) and another to "w" to set the mode to write after SDL_RWops loads the midi data and you should be able to load the path of your first parameter as a file.

EDIT: I just realized that this only initializes the file, it doesn't write any data to it. AFAIK function SDL_RWwrite will write the stream to a file.

Share this post


Link to post
Holering said:

or the bad general midi in windows

Just for the record I find that entirely subjective. Windows MIDI may not be realistic enough, but it renders all instruments acceptably. I prefer programs to fall back to it if a third-party sound font is missing.

Share this post


Link to post

SDL_RWwrite seems the only way to append data once an empty file is created from SDL_RWFromFile AFAIK. All that's left is telling SDL_RWwrite where to get the data length and size of the midi file. This is what I have so far:

#define MIDIFILE "/tmp/doom.mid"
static SDL_RWops *filename = NULL;
//static SDL_RWops *midifile = NULL;
   rw    = SDL_RWFromMem(data, size);
   filename    = SDL_RWFromFile(MIDIFILE,"w");
int   midifile = SDL_RWwrite(filename,&rw,size,1);
   Mix_SetMusicCMD(getenv("MIDI"));
   music = Mix_LoadMUS(MIDIFILE);
//   music = Mix_LoadMUS_RW(rw);
As for falling back to Windows general midi, I agree with you and think it's better than sdl_mixer's internal timidity backend plus it's not broken. I don't think however that Windows users should be restricted to only use that built-in soundfont, but have the option to choose whatever midi processor they want; there are numerous hardware and software options. Would also fix the issue of having the same midi-sfx volume locked.

When using midi yoke with timidity++ under Windows for example, or a real hardware midi module, you can't choose to use either one. Sdl_mixer doesn't let users choose a default midi device. Only source ports that use portmidi library, zdoom, and I think doomsday let you (think fmod is in charge of it). Don't really think everyone would want to use windows' default midi if they have a real roland sound canvas or something else available (hardware midi or timidity++ is way better and those who've never tried may be impressed); plus you save hard drive space without resorting to pre-recorded music tracks and you can get much better quality (Final Fantasy VII lets me use midi yoke with timidity++ using my large pat sets and beats the snot out of playstation version's psf music; graphics blow it away too). This is what I think chocolate-doom really needs (especially being around so long) since users don't have an option to choose a default midi device like you could in Dos. Hope Eternity gets this.

Share this post


Link to post

I love Windows MIDI, personally. I actually ripped the patchset from my Windows installation, converted it into an SF2 file and now I use it with timidity in Linux. :P

I decided to hack out a patch myself, because I'm tired of dealing with subpar audio too. For the moment, most of the code is in #ifndef _WIN32 blocks, because I figured that BSD and Mac OS X could benefit from this as well. I'm not sure that my ifndefs protect from Windows 64-bit compiles. To use an external sequencer, set the command you want use to the MIDI environment variable. It's a solution I saw Holering use in the Chocolate Doom thread. From my testing, various backends on Linux all sounded better than the ancient version of timidity that SDL_mixer is using by default.

Please let me know if you find any problems or have any concerns and I will fix them as best as I can.

Here it is, anyone is free to use it
(updated patch can now be found below, pastebin was causing issues)

EDIT: Based off Eternity Engine SVN latest trunk

Share this post


Link to post

That's a really great patch! Great work. Maybe you can change it a bit because it's not working on my end using linux. Used latest revision 2585 and some earlier sources to no avail. Here's the output:

patching file source/sdl/i_sdlmusic.cpp
Hunk #1 FAILED at 174.
Hunk #2 FAILED at 400.
patch unexpectedly ends in middle of line
Hunk #3 FAILED at 546.
3 out of 3 hunks FAILED -- saving rejects to file source/sdl/i_sdlmusic.cpp.rej
For reference here's the code for getting midi playback without sdl_rwwrite and using an external program. Thanks to Quasar I was able to generate a midi file without sdl; was a very simple line from older versions. Thanks to MP2E for providing his patch! Here's the code:
   // Try SDL_mixer locally
//   rw    = SDL_RWFromMem(data, size);
   M_WriteFile("/tmp/doom.mid", data, size);
   char *filename = NULL;
   Mix_SetMusicCMD(getenv("MIDI"));
   filename = "/tmp/doom.mid";
   music = Mix_LoadMUS(filename);
//   music = Mix_LoadMUS_RW(rw);
Also, here's some songs from Ultimate Doom episode 5 (Lost Episode). These are in game so people don't think I cheated, using Eternity revision 2570 and a large pat set with timidity++ rendering the midi (MIDI="timidity -A20,100"). These tracks were unused in Ultimate Doom but added to pwad "Lost Episode of Doom"; with the exception of e5m3:
e5m1 http://speedy.sh/euJca/e5m1-external-timidity.ogg
e5m2 http://speedy.sh/XQ28T/e5m2-external-timidity.ogg
e5m3 http://speedy.sh/cyeqs/e5m3-external-timidity.ogg
e5m8 http://speedy.sh/8BXFJ/e5m8-external-timidity.ogg
You'll notice eternity (and chocolate-doom) has to wait when changing songs (don't know if it happens with MP2E's code); this doesn't happen when songs loop however but only when the program generates a new midi file (this could probably be avoided without losing sync). Everything stays in sync, loops work, and no problems anyway.

@MP2E: What did you use to turn a pat set into an sf2? Really curious since I have Swami right now but it's unfriendly to me. Also, where is the pat set (thought it was a sound font?) on Windows; I'm using Windows 7 and don't know where it's at.

Regards

Share this post


Link to post

Try the patch again. Updated it, and I used your code instead of my SDL code. Yours seems to work better, TBH :P

Holering said:

You'll notice eternity (and chocolate-doom) has to wait when changing songs (don't know if it happens with MP2E's code); this doesn't happen when songs loop however but only when the program generates a new midi file (this could probably be avoided without losing sync). Everything stays in sync, loops work, and no problems anyway.

There does seem to be a noticeable pause between levels when a new MIDI is loaded.

Holering said:

@MP2E: What did you use to turn a pat set into an sf2? Really curious since I have Swami right now but it's unfriendly to me. Also, where is the pat set (thought it was a sound font?) on Windows; I'm using Windows 7 and don't know where it's at.

Whoops! You're completely right, it's some proprietary soundfont format. I actually can't recall the program I used, as it was some years ago and then I just uploaded the sf2 file to my mediafire for future use.

Share this post


Link to post

In production you'd want to do:

qstring midPath;
midPath = usergamepath;
midPath.pathConcatenate("tmp.mid");
M_WriteFile(midPath.constPtr(), data, size);

Share this post


Link to post

Thanks for the advise, that is a much better solution. The external sequencer code may work with Windows now, but since I haven't tested it yet the #ifndefs are still in place. I updated the patch to use midPath, and I swapped the #ifndefs to use _Windows instead of _WIN32 to catch 64-bit compiles as well.

Share this post


Link to post

Still having problems with patch:

bash-4.2# patch -p1 --verbose < *diff
Hmm...  Looks like a unified diff to me...
The text leading up to this was:
--------------------------
|diff --git a/source/sdl/i_sdlmusic.cpp b/source/sdl/i_sdlmusic.cpp
|index cf48393..ba9d295 100644
|--- a/source/sdl/i_sdlmusic.cpp
|+++ b/source/sdl/i_sdlmusic.cpp
--------------------------
patching file source/sdl/i_sdlmusic.cpp
Using Plan A...
Hunk #1 FAILED at 174.
Hunk #2 FAILED at 258.
Hunk #3 FAILED at 400.
patch unexpectedly ends in middle of line
Hunk #4 FAILED at 546.
4 out of 4 hunks FAILED -- saving rejects to file source/sdl/i_sdlmusic.cpp.rej
done

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now