OpenAL support with pinvoke

This commit is contained in:
Matthew Bowra-Dean
2010-01-20 18:46:25 +13:00
5 changed files with 183 additions and 39 deletions

View File

@@ -63,10 +63,6 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\Ijw.DirectX\Ijw.Framework\IjwFramework\bin\Debug\IjwFramework.dll</HintPath> <HintPath>..\Ijw.DirectX\Ijw.Framework\IjwFramework\bin\Debug\IjwFramework.dll</HintPath>
</Reference> </Reference>
<Reference Include="irrKlang.NET2.0, Version=1.1.3.0, Culture=neutral, PublicKeyToken=a854741bd80517c7, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\thirdparty\irrKlang.NET2.0.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core"> <Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework> <RequiredTargetFramework>3.5</RequiredTargetFramework>
@@ -135,6 +131,7 @@
<Compile Include="SupportPowers\IronCurtainPower.cs" /> <Compile Include="SupportPowers\IronCurtainPower.cs" />
<Compile Include="SupportPowers\ISupportPowerImpl.cs" /> <Compile Include="SupportPowers\ISupportPowerImpl.cs" />
<Compile Include="SupportPowers\NullPower.cs" /> <Compile Include="SupportPowers\NullPower.cs" />
<Compile Include="Support\OpenAlInterop.cs" />
<Compile Include="Support\Stopwatch.cs" /> <Compile Include="Support\Stopwatch.cs" />
<Compile Include="Support\PerfHistory.cs" /> <Compile Include="Support\PerfHistory.cs" />
<Compile Include="Sync.cs" /> <Compile Include="Sync.cs" />

View File

@@ -1,7 +1,9 @@
using IjwFramework.Collections; using System;
using IrrKlang; using IjwFramework.Collections;
using OpenRa.FileFormats; using OpenRa.FileFormats;
using OpenRa.Traits; using OpenRa.Traits;
using OpenRa.Support;
using System.Runtime.InteropServices;
namespace OpenRa namespace OpenRa
{ {
@@ -14,49 +16,42 @@ namespace OpenRa
//TODO: read these from somewhere? //TODO: read these from somewhere?
static float soundVolume; static float soundVolume;
static float musicVolume; static float musicVolume;
static bool paused; // static bool paused;
static ISoundSource LoadSound(string filename) static ISoundSource LoadSound(string filename)
{ {
var data = AudLoader.LoadSound(FileSystem.Open(filename)); var data = AudLoader.LoadSound(FileSystem.Open(filename));
return soundEngine.AddSoundSourceFromPCMData(data, filename, return soundEngine.AddSoundSourceFromMemory(data, 1, 16, 22050);
new AudioFormat()
{
ChannelCount = 1,
FrameCount = data.Length / 2,
Format = SampleFormat.Signed16Bit,
SampleRate = 22050
});
} }
public static void Initialize() public static void Initialize()
{ {
soundEngine = new ISoundEngine(); soundEngine = new OpenAlSoundEngine();
sounds = new Cache<string, ISoundSource>(LoadSound); sounds = new Cache<string, ISoundSource>(LoadSound);
music = null; music = null;
soundVolume = soundEngine.SoundVolume; soundVolume = soundEngine.Volume;
musicVolume = soundEngine.SoundVolume; musicVolume = soundEngine.Volume;
} }
public static void Play(string name) public static void Play(string name)
{ {
var sound = sounds[name]; var sound = sounds[name];
// todo: positioning // todo: positioning
soundEngine.Play2D(sound, false /* loop */, false, false); soundEngine.Play2D(sound, false);
} }
public static void PlayMusic(string name) public static void PlayMusic(string name)
{ {
var sound = sounds[name]; var sound = sounds[name];
music = soundEngine.Play2D(sound, true /* loop */, false, false); music = soundEngine.Play2D(sound, true);
music.Volume = musicVolume; music.Volume = musicVolume;
} }
public static bool Paused //public static bool Paused
{ //{
get { return paused; } // get { return paused; }
set { paused = value; soundEngine.SetAllSoundsPaused(paused); } // set { paused = value; soundEngine.SetAllSoundsPaused(paused); }
} //}
public static float Volume public static float Volume
{ {
@@ -64,29 +59,30 @@ namespace OpenRa
set set
{ {
soundVolume = value; soundVolume = value;
soundEngine.SoundVolume = value; soundEngine.Volume = value;
} }
} }
public static float MusicVolume public static float MusicVolume
{ {
get { return musicVolume; } get { return musicVolume; }
set { set
{
musicVolume = value; musicVolume = value;
if (music != null) if (music != null)
music.Volume = value; music.Volume = value;
} }
} }
public static void SeekMusic(uint delta) //public static void SeekMusic(uint delta)
{ //{
if (music != null) // if (music != null)
{ // {
music.PlayPosition += delta; // music.PlayPosition += delta;
if (music.PlayPosition < 0 || music.PlayPosition > music.PlayLength) // if (music.PlayPosition < 0 || music.PlayPosition > music.PlayLength)
music.PlayPosition = 0; // music.PlayPosition = 0;
} // }
} //}
public static void PlayVoice(string phrase, Actor voicedUnit) public static void PlayVoice(string phrase, Actor voicedUnit)
{ {
@@ -115,4 +111,91 @@ namespace OpenRa
Play(clip + variant); 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); }
}
}
} }

View File

@@ -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);
}
}

Binary file not shown.

View File

@@ -1 +0,0 @@
irrKlang library is from http://www.ambiera.com/irrklang/