Playing MP3 Background Music In MonoGame Windows

The process of porting ‘Attack Of Giant Jumping Man‘ to Windows Desktop has been generally painless. One of the things that has given me the most issues though has been getting MP3 background music to play correctly. For some reason the WindowsGL version of MonoGame doesn’t support MP3 files as XNA Song objects to play via MediaPlayer.Play().The solution, as usual with these kind of issues, is to go native. Unfortunately just doing something as simple as playing an MP3 file on Windows is much more convoluted than would seem necessary if you want to avoid including additional dependencies (DirectX, Windows Media Player etc) into your project.

So, here’s some code that will play MP3 files without the need for additional dependencies by hooking into the winmm.dll. Import your MP3 resources using the MonoGame pipeline tool and just set to ‘copy’ with no pre-processing. Code could probably do with tidying up a bit but it works!

#region Using Statements
using System;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Input;
#endregion

namespace com.bitbull.meat.platform.windows
{
    public class WinmmMp3MediaType
    {
        [DllImport("winmm.dll")]
        private static extern long mciSendString(string lpstrCommand, StringBuilder lpstrReturnString, int uReturnLength, int hwndCallback);
        private string filename;
        private string command;
// Expects a name like 'yourfile' WITHOUT an extension (just for consistency with Content.Load)
// Expects files to be stored at root of Content directory with no pre-processing 
        internal WinmmMp3MediaType(string name)
        {
            filename = "Content/" + name + ".mp3";
        }

        internal override void Play(int loopcount, float volume)
        {
            StringBuilder retvalue = new StringBuilder();
// You need to stop and close and currently playing files otherwise it doesn't work properly
            command = "stop Mp3File";
            mciSendString(command, null, 0, 0);
            command = "close Mp3File";
            mciSendString(command, null, 0, 0);
            command = "open " + "\"" + filename + "\"" + " type MPEGVideo alias Mp3File";
            mciSendString(command, retvalue, 0, 0);
// I've commented out the code for setting the volume as it's specific to the way I do things but basically this command expects an integer between 0 (min volume) and 1000 (max volume) 
            // float master_volume = MEAT.Platform.MediaInterface.MusicVolume / 100.0f;
            // mciSendString(string.Concat("setaudio Mp3File left volume to ", (int)volume*master_volume*1000), null, 0, 0);
            // mciSendString(string.Concat("setaudio Mp3File right volume to ", (int)volume*master_volume * 1000), null, 0, 0);
            command = "play Mp3File";
            if ( loopcount<=0 )
            {
                command += " REPEAT";
            }
            mciSendString(command, retvalue, 0, 0);
        }

        internal override void Stop()
        {
            command = "stop Mp3File";
            mciSendString(command, null, 0, 0);
            command = "close Mp3File";
            mciSendString(command, null, 0, 0);
        }
    }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: