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>
<HintPath>..\Ijw.DirectX\Ijw.Framework\IjwFramework\bin\Debug\IjwFramework.dll</HintPath>
</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.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
@@ -135,6 +131,7 @@
<Compile Include="SupportPowers\IronCurtainPower.cs" />
<Compile Include="SupportPowers\ISupportPowerImpl.cs" />
<Compile Include="SupportPowers\NullPower.cs" />
<Compile Include="Support\OpenAlInterop.cs" />
<Compile Include="Support\Stopwatch.cs" />
<Compile Include="Support\PerfHistory.cs" />
<Compile Include="Sync.cs" />

View File

@@ -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<string, ISoundSource>(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); }
}
}
}

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/