Sound & Music Library in MOGRE [DONE]

MouseTaylor

15-11-2011 08:49:59

Does anyone have a good solution for this ?

I'm working on something, but I didn't want to get into it yet before I had you guys' opinion.

T.

McDonte

15-11-2011 14:22:58

Hey MouseTaylor,
I suggest IrrKlang. There is a C# binding and it can be used within Mogre without problems. Check out this wiki page for more information.
I hope this helps you to start your project! :D

MouseTaylor

15-11-2011 14:26:02

Hey,
thanks for the reply, but I don't want to use another third party dll where I need to pay for.

I want to make one myself, and I'm pretty good on the way, well I think I am :?

I was just wandering what "other" ways to do music and sound the community uses

T.

McDonte

15-11-2011 17:45:45

another third party dll where I need to pay for
As there is no Ogre internal sound libraray you will definitely need to use a third-party addon. irrKlang is free for non-commercial projects, but if you intend to earn money with your game/application this could be annoying, I understand.
As an alternative you could use MogreFreeSL (see here). It is completely free as far as I know.

I want to make one myself, and I'm pretty good on the way, well I think I am
I have never done something like this but most likely it will turn out to be a wrapper of an existing library... this is a bit too much work (for me) if there is already good work done avaiable :D

Pyritie

15-11-2011 17:46:50

I use irrklang too, since it's free for noncommercial things

though there's also this: http://www.ogre3d.org/tikiwiki/MogreFreeSL

MouseTaylor

16-11-2011 08:26:00

Well, thanks guys, for now, I did the sound myself, I'll try to explain when I come up with this, test it and find it ok to use.

so first think I did ( it is all C# ) I figured, since MOGRE needs DirectX, I probable use that for sound. As I do not need to add these libraries to my solution (to the output directory), I just reference them and add it to the using list:


using Microsoft.DirectX.DirectSound;


First step i did was check what audio devices were available on the local machine, and return a list with these devices. Once the user selects the device, I can use it as the main audio device.


public class AudioDevice
{
public Guid Id;
public string ModuleName;
public string Description;
}


The guid is important , cause that is what you pass to the actual DirectSound Device object.


public static List<AudioDevice> ListOfDevicesInstalled()
{
DevicesCollection deviceCollection = new DevicesCollection();
List<AudioDevice> audioDevices = new List<AudioDevice>();

for (int i = 0; i < deviceCollection.Count; i++)
{
AudioDevice ad = new AudioDevice();
ad.Id = deviceCollection[i].DriverGuid;
ad.ModuleName = deviceCollection[i].ModuleName;
ad.Description = deviceCollection[i].Description;
audioDevices.Add(ad);
}

return audioDevices;

}


So this peace of code can already serve for the Audio Option in the game.

Now to keep the selected audio device, I created a static property using a singleton pattern.


private static AudioDevice _SelectedAudioDevice;

public static AudioDevice SelectedAudioDevice
{
get { return _SelectedAudioDevice; }
set { _SelectedAudioDevice = value; }
}


This allows me to ask the user, whenever and wherever for the Audio Device, and keep track of it anywhere in the game.

Since we deal with 2D sounds and 3D sounds, I created an interface to work with one object in stead of 2


public interface ISound : IDisposable
{
string SoundName();
void Stop();
void Update(float passedTime);
void Pause();
void Loop();
void Play();
}


I added the sound name because, somewhere in the game I would like to tell my sound manager, play this sound, without me having to know the name of the file.

The update is, to my knowledge, for now :) only required for the Sound3D, but at this time I'm not there yet.

MouseTaylor

16-11-2011 09:06:59

To follow up on my post earlier:

I made a Sound class and a Sound3D class, first I'll discuss the Sound Class:


public class Sound : ISound
{
private SecondaryBuffer _someSound;
private string _soundFile;
private string _soundName;

public Device SoundDevice;

// everything what comes next, comes here.
}


and implement the interface.

Note, if anywhere in my code you see GameEngine.[Something], I reference to an partial static class which contains the singletons on that object. You should replace it with you own piece of code.

So now for the constructor:


public Sound(string soundFile, string soundName)
{
_soundName = soundName;
_soundFile = Path.Combine(GameEngine.ApplicationPath + "\\Data\\Sound", soundFile);
if (!File.Exists(_soundFile)) return;

BufferDescription description = new BufferDescription();
description.ControlEffects = true;
description.ControlVolume = true;
_someSound = new SecondaryBuffer(_soundFile, description, SoundDevice);
}




Change the \\Data\\Sound as you like, since that is where I keep all the sounds.

Sounds should be wav format.

Now some interesting implementation:

The length of the wave:


public int TotalSeconds
{
get { return _someSound.Caps.BufferBytes / _someSound.Format.AverageBytesPerSecond; }
}


The current position of the playing sound:

public int CurrentPosition
{
get { return _someSound.PlayPosition / _someSound.Format.AverageBytesPerSecond; }
}


The format:


public WaveFormat Format()
{
return _someSound.Format;
}




And the status:


public string Status
{
get
{
if (_someSound.Status.Looping) return "LOOPING";
if (_someSound.Status.Playing) return "PLAYING";
if (_someSound.Status.Terminated) return "TERMINATED";
if (_someSound.Status.BufferLost) return "BUFFERLOST";
return "UNKOWN";
}
}



And then the implementation of the interface ISound:


public void Play()
{
_someSound.Play(0, BufferPlayFlags.Default);
}
public void Loop()
{
_someSound.Play(0, BufferPlayFlags.Looping);
}
public void Pause()
{
_someSound.Stop();
}
public void Stop()
{
_someSound.Stop();
_someSound.SetCurrentPosition(0);
}
public void SetVolume(int volume)
{
_someSound.Volume = volume;
}
public void Dispose()
{
if (_someSound != null)
_someSound.Dispose();

}


The difference between pause and stop is that the stop does not rewind the sound position, so it is actually a pause :)
So I implemented both.

Up till now, you can still not play a sound :) which is normal, I only implement 1 device in the Sound manager ( which I still need to code ) and give it the selected Audio Device

T.

MouseTaylor

16-11-2011 12:00:29

If you get the LoaderLock exception, turn it off in

Debug>Exceptions>Managed Debugging Assitants>LoaderLock.


If you get the 4.0 error, run your app in .NET 3.5 or add in app.Config file :


<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
</startup>


T.

McDonte

16-11-2011 13:55:55

So basically you are just using Managed DirectX and create your own interface, right? I think in Mogre (which can be used Windows only anyway) this is a good approach. Better than calling single methods from a native library via "static extern" calls.

Can you post the classes you wrote when you are finished? This is an interesting and easy alternative to existing sound libraries!

MouseTaylor

17-11-2011 11:22:09

Yes I will,

yesterday I finished my 2D Sound implementation.
I also added the Speakers class, so it can be used in game so the user can select between Head Phones, 5.1 Surround, Stereo, 7.1 Surround... etc.

Now I need to implement the 3D Sound with a listener, pan left, right, back front, etc..

Thnx for the motivation

T.

McDonte

17-11-2011 12:29:07

I am especially interested in the 3d sound. Personally I have no idea how this can be implemented if I would write my own sound engine. So please keep us up-to-date! :D

MouseTaylor

18-11-2011 06:09:36

Added Sound Effects to the code, so I guess the normal Sound is ready and tested.

Changed some code in the code above so you can play multiple sound files at the same time with different sound effects etc..

Up to 3D Sound :)

Once the code is completed, I'll post the .cs file here



T.

Pyritie

18-11-2011 14:14:35


public string Status
{
get
{
if (_someSound.Status.Looping) return "LOOPING";
if (_someSound.Status.Playing) return "PLAYING";
if (_someSound.Status.Terminated) return "TERMINATED";
if (_someSound.Status.BufferLost) return "BUFFERLOST";
return "UNKOWN";
}
}


that might work better as an enum instead of strings

MouseTaylor

18-11-2011 17:18:58

It won't work "better", it would work the same,
but no worries, I had that covered already :D

T.

MouseTaylor

22-11-2011 11:35:23

Ok, first try, well actually I am using this now instead of any other Sound library


You can use it, and do anything you want with it.

It is a VS2008 solution, so normally everyone should be able to use it

I did NOT implement all the Sound Effects, that is up to you guys, since I'm working on a client app in WinForms to test the effects first.

There is no use of the real 3D sound that comes with DirectX since it did not work well enough for me, but I implemented a 3D sound myself :)

Feedback is always welcome
Have fun

Download here: http://users.telenet.be/u122561/Downloads/GriffonStudios.Sound.rar

Cheers
T.

McDonte

25-11-2011 10:49:00

Hey MouseTaylor,
thanks for the code, I already downloaded it. With a first look at the code it appears to be pretty compact. Can you post a piece of code how to use your sound lib? So how to initialize it, load a sound file and play it. Thank you in advance!

Pyritie

25-11-2011 15:31:42

would it be possible for you to upload that as a forum attachment, so the link won't break in the future?

MouseTaylor

06-12-2011 09:16:03

To check what devices are available on a machine -> goes in the game on Options

SoundManager.ListOfDevicesInstalled() and it returns a List of AudioDevices to select from --> use this to add to the SoundManager

SoundManager.ListOfSurroundSystems() and it returns the possible surround systems to select from --> use it to add to the SoundManager

Normal sound example


// initiate the sound manager
SoundManager _soundManager = new SoundManager();

// create a sound
ISound mySound = _soundManager.AddSound("someSound.wav");

// play the sound
mySound.Play();

// or loop the sound
mySound.Loop();

// pause the sound
mySound.Pause();

// stop the sound
mySound.Stop();

// set volume
// -2500 => mute
// 0 => max sound volume
mySound.Volume(-500);


3D Sound example

One extra requirement:

call the _soundManager.Update( listenerPosition)

for the listenerPosition, which is a Vector3, pass the position of your character.

ISound my3DSound = _soundManager.AddSound3D( "someSound.wav", "someName", new Vector3( 0,0,0));

the last parameter is where the sound should be emmitting.

just set the min and max Distance

my3DSound.SetMinDistance( 2);
my3DSound.SetMaxDistance( 20);


never use a min distance of zero, this is a weird effect
after your character's distance from the sound passes the max distance, the sound is no longer heard.

This should do it :)

T.

Tubulii

12-01-2012 10:13:39

What about an Wiki page for this? I could do it.