diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index ba98ce4776..eb43a104a6 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -63,10 +63,6 @@ False ..\Ijw.DirectX\Ijw.Framework\IjwFramework\bin\Debug\IjwFramework.dll - - False - ..\thirdparty\irrKlang.NET2.0.dll - 3.5 @@ -135,6 +131,7 @@ + diff --git a/OpenRa.Game/Sound.cs b/OpenRa.Game/Sound.cs index 25d3cf0e0f..1543f16239 100644 --- a/OpenRa.Game/Sound.cs +++ b/OpenRa.Game/Sound.cs @@ -1,7 +1,9 @@ -using IjwFramework.Collections; -using IrrKlang; +using System; +using IjwFramework.Collections; using OpenRa.FileFormats; using OpenRa.Traits; +using OpenRa.Support; +using System.Runtime.InteropServices; namespace OpenRa { @@ -14,49 +16,42 @@ namespace OpenRa //TODO: read these from somewhere? static float soundVolume; static float musicVolume; - static bool paused; + // static bool paused; static ISoundSource LoadSound(string filename) { var data = AudLoader.LoadSound(FileSystem.Open(filename)); - return soundEngine.AddSoundSourceFromPCMData(data, filename, - new AudioFormat() - { - ChannelCount = 1, - FrameCount = data.Length / 2, - Format = SampleFormat.Signed16Bit, - SampleRate = 22050 - }); + return soundEngine.AddSoundSourceFromMemory(data, 1, 16, 22050); } public static void Initialize() { - soundEngine = new ISoundEngine(); + soundEngine = new OpenAlSoundEngine(); sounds = new Cache(LoadSound); music = null; - soundVolume = soundEngine.SoundVolume; - musicVolume = soundEngine.SoundVolume; + soundVolume = soundEngine.Volume; + musicVolume = soundEngine.Volume; } public static void Play(string name) { var sound = sounds[name]; // todo: positioning - soundEngine.Play2D(sound, false /* loop */, false, false); + soundEngine.Play2D(sound, false); } - + public static void PlayMusic(string name) { var sound = sounds[name]; - music = soundEngine.Play2D(sound, true /* loop */, false, false); + music = soundEngine.Play2D(sound, true); music.Volume = musicVolume; } - public static bool Paused - { - get { return paused; } - set { paused = value; soundEngine.SetAllSoundsPaused(paused); } - } + //public static bool Paused + //{ + // get { return paused; } + // set { paused = value; soundEngine.SetAllSoundsPaused(paused); } + //} public static float Volume { @@ -64,29 +59,30 @@ namespace OpenRa set { soundVolume = value; - soundEngine.SoundVolume = value; + soundEngine.Volume = value; } } - + public static float MusicVolume { get { return musicVolume; } - set { + set + { musicVolume = value; if (music != null) music.Volume = value; } } - public static void SeekMusic(uint delta) - { - if (music != null) - { - music.PlayPosition += delta; - if (music.PlayPosition < 0 || music.PlayPosition > music.PlayLength) - music.PlayPosition = 0; - } - } + //public static void SeekMusic(uint delta) + //{ + // if (music != null) + // { + // music.PlayPosition += delta; + // if (music.PlayPosition < 0 || music.PlayPosition > music.PlayLength) + // music.PlayPosition = 0; + // } + //} public static void PlayVoice(string phrase, Actor voicedUnit) { @@ -115,4 +111,91 @@ namespace OpenRa Play(clip + variant); } } + + interface ISoundEngine + { + ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate); + ISound Play2D(ISoundSource sound, bool loop); + float Volume { get; set; } + } + + interface ISoundSource {} + interface ISound + { + float Volume { get; set; } + } + + class OpenAlSoundEngine : ISoundEngine + { + float volume = 1f; + + public OpenAlSoundEngine() + { + //var str = Alc.alcGetString(IntPtr.Zero, Alc.ALC_DEFAULT_DEVICE_SPECIFIER); + var dev = OpenAlInterop.alcOpenDevice(IntPtr.Zero); + if (dev == IntPtr.Zero) + throw new InvalidOperationException("Can't create OpenAL device"); + var ctx = OpenAlInterop.alcCreateContext(dev, IntPtr.Zero); + OpenAlInterop.alcMakeContextCurrent(ctx); + } + + public ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate) + { + return new OpenAlSoundSource(data, channels, sampleBits, sampleRate); + } + + public ISound Play2D(ISoundSource sound, bool loop) + { + return new OpenAlSound((sound as OpenAlSoundSource).buffer, loop); + } + + public float Volume + { + get { return volume; } + set { OpenAlInterop.alListenerf(OpenAlInterop.AL_GAIN, volume = value); } + } + } + + class OpenAlSoundSource : ISoundSource + { + public readonly int buffer; + + static int MakeALFormat(int channels, int bits) + { + if (channels == 1) + return bits == 16 ? OpenAlInterop.AL_FORMAT_MONO16 : OpenAlInterop.AL_FORMAT_MONO8; + else + return bits == 16 ? OpenAlInterop.AL_FORMAT_STEREO16 : OpenAlInterop.AL_FORMAT_STEREO8; + } + + public OpenAlSoundSource(byte[] data, int channels, int sampleBits, int sampleRate) + { + OpenAlInterop.alGenBuffers(1, out buffer); + OpenAlInterop.alBufferData(buffer, MakeALFormat(channels, sampleBits), data, data.Length, sampleRate); + } + } + + class OpenAlSound : ISound + { + public readonly int source; + float volume = 1f; + + public OpenAlSound(int buffer, bool looping) + { + OpenAlInterop.alGenSources(1, out source); + OpenAlInterop.alSourcef(source, OpenAlInterop.AL_PITCH, 1f); + OpenAlInterop.alSourcef(source, OpenAlInterop.AL_GAIN, 1f); + OpenAlInterop.alSource3f(source, OpenAlInterop.AL_POSITION, 0f, 0f, 0f); + OpenAlInterop.alSource3f(source, OpenAlInterop.AL_VELOCITY, 0f, 0f, 0f); + OpenAlInterop.alSourcei(source, OpenAlInterop.AL_BUFFER, buffer); + OpenAlInterop.alSourcei(source, OpenAlInterop.AL_LOOPING, looping ? OpenAlInterop.AL_TRUE : OpenAlInterop.AL_FALSE); + OpenAlInterop.alSourcePlay(source); + } + + public float Volume + { + get { return volume; } + set { OpenAlInterop.alSourcef(source, OpenAlInterop.AL_GAIN, volume = value); } + } + } } diff --git a/OpenRa.Game/Support/OpenAlInterop.cs b/OpenRa.Game/Support/OpenAlInterop.cs new file mode 100644 index 0000000000..73e4025425 --- /dev/null +++ b/OpenRa.Game/Support/OpenAlInterop.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace OpenRa.Support +{ + public static class OpenAlInterop + { + public static readonly int AL_GAIN = 0x100A; + + public static readonly int AL_FORMAT_MONO8 = 0x1100; + public static readonly int AL_FORMAT_MONO16 = 0x1101; + public static readonly int AL_FORMAT_STEREO8 = 0x1102; + public static readonly int AL_FORMAT_STEREO16 = 0x1103; + + public static readonly int AL_PITCH = 0x1003; + + public static readonly int AL_POSITION = 0x1004; + public static readonly int AL_DIRECTION = 0x1005; + public static readonly int AL_VELOCITY = 0x1006; + + public static readonly int AL_LOOPING = 0x1007; + public static readonly int AL_BUFFER = 0x1009; + + public static readonly int AL_TRUE = 1; + public static readonly int AL_FALSE = 0; + + + [DllImport("OpenAL32.dll")] + public static extern IntPtr alcOpenDevice(IntPtr deviceName); + + [DllImport("OpenAL32.dll")] + public static extern IntPtr alcCreateContext(IntPtr device, IntPtr attrList); + + [DllImport("OpenAL32.dll")] + public static extern bool alcMakeContextCurrent(IntPtr context); + + [DllImport("OpenAL32.dll")] + public static extern void alListenerf(int param, float value); + + [DllImport("OpenAL32.dll")] + public static extern void alGenBuffers(int n, out int buffers); + + [DllImport("OpenAL32.dll")] + public static extern void alBufferData(int buffer, int format, + [MarshalAs(UnmanagedType.LPArray)] byte[] data, int size, int freq); + + [DllImport("OpenAL32.dll")] + public static extern void alGenSources(int n, out int sources); + + [DllImport("OpenAL32.dll")] + public static extern void alSourcef(int source, int param, float value); + + [DllImport("OpenAL32.dll")] + public static extern void alSource3f(int source, int param, float v1, float v2, float v3); + + [DllImport("OpenAL32.dll")] + public static extern void alSourcei(int source, int param, int value); + + [DllImport("OpenAL32.dll")] + public static extern void alSourcePlay(int source); + } +} diff --git a/thirdparty/irrKlang.NET2.0.dll b/thirdparty/irrKlang.NET2.0.dll deleted file mode 100644 index a558e4fb00..0000000000 Binary files a/thirdparty/irrKlang.NET2.0.dll and /dev/null differ diff --git a/thirdparty/irrKlang.txt b/thirdparty/irrKlang.txt deleted file mode 100644 index 92648dec0d..0000000000 --- a/thirdparty/irrKlang.txt +++ /dev/null @@ -1 +0,0 @@ -irrKlang library is from http://www.ambiera.com/irrklang/ \ No newline at end of file