#region License
#endregion
#region VERBOSE_AL_DEBUGGING Option
#endregion
#region Using Statements
using
System;
using
System.Collections.Generic;
using
System.Collections.ObjectModel;
using
System.Runtime.InteropServices;
using
OpenAL;
#endregion
namespace
Microsoft.Xna.Framework.Audio
{
internal
class
OpenALDevice : IALDevice
{
#region OpenAL Buffer Container Class
private
class
OpenALBuffer : IALBuffer
{
public
uint
Handle
{
get
;
private
set
;
}
public
TimeSpan Duration
{
get
;
private
set
;
}
public
OpenALBuffer(
uint
handle, TimeSpan duration)
{
Handle = handle;
Duration = duration;
}
}
#endregion
#region OpenAL Source Container Class
private
class
OpenALSource : IALSource
{
public
uint
Handle
{
get
;
private
set
;
}
public
OpenALSource(
uint
handle)
{
Handle = handle;
}
}
#endregion
#region OpenAL Reverb Effect Container Class
private
class
OpenALReverb : IALReverb
{
public
uint
SlotHandle
{
get
;
private
set
;
}
public
uint
EffectHandle
{
get
;
private
set
;
}
public
OpenALReverb(
uint
slot,
uint
effect)
{
SlotHandle = slot;
EffectHandle = effect;
}
}
#endregion
#region Private ALC Variables
private
IntPtr alDevice;
private
IntPtr alContext;
#endregion
#region Private EFX Variables
private
uint
INTERNAL_alFilter;
#endregion
#region Public Constructor
public
OpenALDevice()
{
string
envDevice = Environment.GetEnvironmentVariable(
"FNA_AUDIO_DEVICE_NAME"
);
if
(String.IsNullOrEmpty(envDevice))
{
envDevice = String.Empty;
}
alDevice = ALC10.alcOpenDevice(envDevice);
if
(CheckALCError() || alDevice == IntPtr.Zero)
{
throw
new
InvalidOperationException(
"Could not open audio device!"
);
}
int
[] attribute =
new
int
[0];
alContext = ALC10.alcCreateContext(alDevice, attribute);
if
(CheckALCError() || alContext == IntPtr.Zero)
{
Dispose();
throw
new
InvalidOperationException(
"Could not create OpenAL context"
);
}
ALC10.alcMakeContextCurrent(alContext);
if
(CheckALCError())
{
Dispose();
throw
new
InvalidOperationException(
"Could not make OpenAL context current"
);
}
float
[] ori =
new
float
[]
{
0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f
};
AL10.alListenerfv(AL10.AL_ORIENTATION, ori);
AL10.alListener3f(AL10.AL_POSITION, 0.0f, 0.0f, 0.0f);
AL10.alListener3f(AL10.AL_VELOCITY, 0.0f, 0.0f, 0.0f);
AL10.alListenerf(AL10.AL_GAIN, 1.0f);
AL10.alDistanceModel(AL10.AL_NONE);
EFX.alGenFilters((IntPtr) 1,
out
INTERNAL_alFilter);
}
#endregion
#region Public Dispose Method
public
void
Dispose()
{
EFX.alDeleteFilters((IntPtr) 1,
ref
INTERNAL_alFilter);
ALC10.alcMakeContextCurrent(IntPtr.Zero);
if
(alContext != IntPtr.Zero)
{
ALC10.alcDestroyContext(alContext);
alContext = IntPtr.Zero;
}
if
(alDevice != IntPtr.Zero)
{
ALC10.alcCloseDevice(alDevice);
alDevice = IntPtr.Zero;
}
}
#endregion
#region Public Update Method
public
void
Update()
{
#if DEBUG
CheckALError();
#endif
}
#endregion
#region OpenAL Buffer Methods
public
IALBuffer GenBuffer()
{
uint
result;
AL10.alGenBuffers((IntPtr) 1,
out
result);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
return
new
OpenALBuffer(result, TimeSpan.Zero);
}
public
IALBuffer GenBuffer(
byte
[] data,
uint
sampleRate,
uint
channels,
uint
loopStart,
uint
loopEnd,
bool
isADPCM,
uint
formatParameter
) {
uint
result;
AL10.alGenBuffers((IntPtr) 1,
out
result);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
int
format;
if
(isADPCM)
{
format = (channels == 2) ?
ALEXT.AL_FORMAT_STEREO_MSADPCM_SOFT :
ALEXT.AL_FORMAT_MONO_MSADPCM_SOFT;
AL10.alBufferi(
result,
ALEXT.AL_UNPACK_BLOCK_ALIGNMENT_SOFT,
(
int
) formatParameter
);
}
else
{
if
(formatParameter == 1)
{
format = (channels == 2) ?
AL10.AL_FORMAT_STEREO16:
AL10.AL_FORMAT_MONO16;
}
else
{
format = (channels == 2) ?
AL10.AL_FORMAT_STEREO8:
AL10.AL_FORMAT_MONO8;
}
}
AL10.alBufferData(
result,
format,
data,
(IntPtr) data.Length,
(IntPtr) sampleRate
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
int
bufLen, bits;
AL10.alGetBufferi(
result,
AL10.AL_SIZE,
out
bufLen
);
AL10.alGetBufferi(
result,
AL10.AL_BITS,
out
bits
);
if
(bufLen == 0 || bits == 0)
{
throw
new
InvalidOperationException(
"OpenAL buffer allocation failed!"
);
}
TimeSpan resultDur = TimeSpan.FromSeconds(
bufLen /
(bits / 8) /
channels /
((
double
) sampleRate)
);
if
(loopStart > 0 || loopEnd > 0)
{
AL10.alBufferiv(
result,
ALEXT.AL_LOOP_POINTS_SOFT,
new
int
[]
{
(
int
) loopStart,
(
int
) loopEnd
}
);
}
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
return
new
OpenALBuffer(result, resultDur);
}
public
void
DeleteBuffer(IALBuffer buffer)
{
uint
handle = (buffer
as
OpenALBuffer).Handle;
AL10.alDeleteBuffers((IntPtr) 1,
ref
handle);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetBufferData(
IALBuffer buffer,
AudioChannels channels,
byte
[] data,
int
offset,
int
count,
int
sampleRate
) {
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
AL10.alBufferData(
(buffer
as
OpenALBuffer).Handle,
XNAToShort[(
int
) channels],
handle.AddrOfPinnedObject() + offset,
(IntPtr) count,
(IntPtr) sampleRate
);
handle.Free();
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetBufferData(
IALBuffer buffer,
AudioChannels channels,
float
[] data,
int
offset,
int
count,
int
sampleRate
) {
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
AL10.alBufferData(
(buffer
as
OpenALBuffer).Handle,
XNAToFloat[(
int
) channels],
handle.AddrOfPinnedObject() + (offset * 4),
(IntPtr) (count * 4),
(IntPtr) sampleRate
);
handle.Free();
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
#endregion
#region OpenAL Source Methods
public
IALSource GenSource()
{
uint
result;
AL10.alGenSources((IntPtr) 1,
out
result);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
if
(result == 0)
{
return
null
;
}
return
new
OpenALSource(result);
}
public
IALSource GenSource(IALBuffer buffer)
{
uint
result;
AL10.alGenSources((IntPtr) 1,
out
result);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
if
(result == 0)
{
return
null
;
}
AL10.alSourcei(
result,
AL10.AL_BUFFER,
(
int
) (buffer
as
OpenALBuffer).Handle
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
return
new
OpenALSource(result);
}
public
void
StopAndDisposeSource(IALSource source)
{
uint
handle = (source
as
OpenALSource).Handle;
AL10.alSourceStop(handle);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
AL10.alDeleteSources((IntPtr) 1,
ref
handle);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
PlaySource(IALSource source)
{
AL10.alSourcePlay((source
as
OpenALSource).Handle);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
PauseSource(IALSource source)
{
AL10.alSourcePause((source
as
OpenALSource).Handle);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
ResumeSource(IALSource source)
{
AL10.alSourcePlay((source
as
OpenALSource).Handle);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
SoundState GetSourceState(IALSource source)
{
int
state;
AL10.alGetSourcei(
(source
as
OpenALSource).Handle,
AL10.AL_SOURCE_STATE,
out
state
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
if
(state == AL10.AL_PLAYING)
{
return
SoundState.Playing;
}
else
if
(state == AL10.AL_PAUSED)
{
return
SoundState.Paused;
}
return
SoundState.Stopped;
}
public
void
SetSourceVolume(IALSource source,
float
volume)
{
AL10.alSourcef(
(source
as
OpenALSource).Handle,
AL10.AL_GAIN,
volume * SoundEffect.MasterVolume
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetSourceLooped(IALSource source,
bool
looped)
{
AL10.alSourcei(
(source
as
OpenALSource).Handle,
AL10.AL_LOOPING,
looped ? 1 : 0
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetSourcePan(IALSource source,
float
pan)
{
AL10.alSource3f(
(source
as
OpenALSource).Handle,
AL10.AL_POSITION,
pan,
0.0f,
(
float
) Math.Sqrt(1 - Math.Pow(pan, 2))
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetSourcePosition(IALSource source, Vector3 pos)
{
AL10.alSource3f(
(source
as
OpenALSource).Handle,
AL10.AL_POSITION,
pos.X,
pos.Y,
pos.Z
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetSourcePitch(IALSource source,
float
pitch,
bool
clamp)
{
if
(clamp && (pitch < -1.0f || pitch > 1.0f))
{
throw
new
IndexOutOfRangeException(
"XNA PITCH MUST BE WITHIN [-1.0f, 1.0f]!"
);
}
AL10.alSourcef(
(source
as
OpenALSource).Handle,
AL10.AL_PITCH,
(
float
) Math.Pow(2, pitch)
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetSourceReverb(IALSource source, IALReverb reverb)
{
AL10.alSource3i(
(source
as
OpenALSource).Handle,
EFX.AL_AUXILIARY_SEND_FILTER,
(
int
) (reverb
as
OpenALReverb).SlotHandle,
0,
0
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetSourceLowPassFilter(IALSource source,
float
hfGain)
{
EFX.alFilteri(INTERNAL_alFilter, EFX.AL_FILTER_TYPE, EFX.AL_FILTER_LOWPASS);
EFX.alFilterf(INTERNAL_alFilter, EFX.AL_LOWPASS_GAINHF, hfGain);
AL10.alSourcei(
(source
as
OpenALSource).Handle,
EFX.AL_DIRECT_FILTER,
(
int
) INTERNAL_alFilter
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetSourceHighPassFilter(IALSource source,
float
lfGain)
{
EFX.alFilteri(INTERNAL_alFilter, EFX.AL_FILTER_TYPE, EFX.AL_FILTER_HIGHPASS);
EFX.alFilterf(INTERNAL_alFilter, EFX.AL_HIGHPASS_GAINLF, lfGain);
AL10.alSourcei(
(source
as
OpenALSource).Handle,
EFX.AL_DIRECT_FILTER,
(
int
) INTERNAL_alFilter
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetSourceBandPassFilter(IALSource source,
float
hfGain,
float
lfGain)
{
EFX.alFilteri(INTERNAL_alFilter, EFX.AL_FILTER_TYPE, EFX.AL_FILTER_BANDPASS);
EFX.alFilterf(INTERNAL_alFilter, EFX.AL_BANDPASS_GAINHF, hfGain);
EFX.alFilterf(INTERNAL_alFilter, EFX.AL_BANDPASS_GAINLF, lfGain);
AL10.alSourcei(
(source
as
OpenALSource).Handle,
EFX.AL_DIRECT_FILTER,
(
int
) INTERNAL_alFilter
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
QueueSourceBuffer(IALSource source, IALBuffer buffer)
{
uint
buf = (buffer
as
OpenALBuffer).Handle;
AL10.alSourceQueueBuffers(
(source
as
OpenALSource).Handle,
(IntPtr) 1,
ref
buf
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
DequeueSourceBuffers(
IALSource source,
int
buffersToDequeue,
Queue<IALBuffer> errorCheck
) {
uint
[] bufs =
new
uint
[buffersToDequeue];
AL10.alSourceUnqueueBuffers(
(source
as
OpenALSource).Handle,
(IntPtr) buffersToDequeue,
bufs
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
#if DEBUG
IALBuffer[] sync = errorCheck.ToArray();
for
(
int
i = 0; i < buffersToDequeue; i += 1)
{
if
(bufs[i] != (sync[i]
as
OpenALBuffer).Handle)
{
throw
new
InvalidOperationException(
"Buffer desync!"
);
}
}
#endif
}
public
int
CheckProcessedBuffers(IALSource source)
{
int
result;
AL10.alGetSourcei(
(source
as
OpenALSource).Handle,
AL10.AL_BUFFERS_PROCESSED,
out
result
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
return
result;
}
public
void
GetBufferData(
IALSource source,
IALBuffer[] buffer,
float
[] samples,
AudioChannels channels
) {
int
copySize1 = samples.Length / (
int
) channels;
int
copySize2 = 0;
int
offset;
AL10.alGetSourcei(
(source
as
OpenALSource).Handle,
AL11.AL_SAMPLE_OFFSET,
out
offset
);
uint
buf = (buffer[0]
as
OpenALBuffer).Handle;
int
len;
AL10.alGetBufferi(
buf,
AL10.AL_SIZE,
out
len
);
len /= 2;
len /= (
int
) channels;
if
(offset > len)
{
copySize2 = copySize1;
copySize1 = 0;
offset -= len;
}
else
if
(offset + copySize1 > len)
{
copySize2 = copySize1 - (len - offset);
copySize1 = (len - offset);
}
GCHandle handle = GCHandle.Alloc(samples, GCHandleType.Pinned);
if
(copySize1 > 0)
{
ALEXT.alGetBufferSamplesSOFT(
buf,
offset,
copySize1,
channels == AudioChannels.Stereo ?
ALEXT.AL_STEREO_SOFT :
ALEXT.AL_MONO_SOFT,
ALEXT.AL_FLOAT_SOFT,
handle.AddrOfPinnedObject()
);
offset = 0;
}
if
(buffer.Length > 1 && copySize2 > 0)
{
ALEXT.alGetBufferSamplesSOFT(
(buffer[1]
as
OpenALBuffer).Handle,
0,
copySize2,
channels == AudioChannels.Stereo ?
ALEXT.AL_STEREO_SOFT :
ALEXT.AL_MONO_SOFT,
ALEXT.AL_FLOAT_SOFT,
handle.AddrOfPinnedObject() + (copySize1 * (
int
) channels)
);
}
handle.Free();
}
#endregion
#region OpenAL Reverb Effect Methods
public
IALReverb GenReverb(DSPParameter[] parameters)
{
uint
slot, effect;
EFX.alGenAuxiliaryEffectSlots((IntPtr) 1,
out
slot);
EFX.alGenEffects((IntPtr) 1,
out
effect);
EFX.alEffecti(
effect,
EFX.AL_EFFECT_TYPE,
EFX.AL_EFFECT_EAXREVERB
);
IALReverb result =
new
OpenALReverb(slot, effect);
SetReverbReflectionsDelay(result, parameters[0].Value);
SetReverbDelay(result, parameters[1].Value);
SetReverbPositionLeft(result, parameters[2].Value);
SetReverbPositionRight(result, parameters[3].Value);
SetReverbPositionLeftMatrix(result, parameters[4].Value);
SetReverbPositionRightMatrix(result, parameters[5].Value);
SetReverbEarlyDiffusion(result, parameters[6].Value);
SetReverbLateDiffusion(result, parameters[7].Value);
SetReverbLowEQGain(result, parameters[8].Value);
SetReverbLowEQCutoff(result, parameters[9].Value);
SetReverbHighEQGain(result, parameters[10].Value);
SetReverbHighEQCutoff(result, parameters[11].Value);
SetReverbRearDelay(result, parameters[12].Value);
SetReverbRoomFilterFrequency(result, parameters[13].Value);
SetReverbRoomFilterMain(result, parameters[14].Value);
SetReverbRoomFilterHighFrequency(result, parameters[15].Value);
SetReverbReflectionsGain(result, parameters[16].Value);
SetReverbGain(result, parameters[17].Value);
SetReverbDecayTime(result, parameters[18].Value);
SetReverbDensity(result, parameters[19].Value);
SetReverbRoomSize(result, parameters[20].Value);
SetReverbWetDryMix(result, parameters[21].Value);
EFX.alAuxiliaryEffectSloti(
slot,
EFX.AL_EFFECTSLOT_EFFECT,
(
int
) effect
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
return
result;
}
public
void
DeleteReverb(IALReverb reverb)
{
OpenALReverb rv = (reverb
as
OpenALReverb);
uint
slot = rv.SlotHandle;
uint
effect = rv.EffectHandle;
EFX.alDeleteAuxiliaryEffectSlots((IntPtr) 1,
ref
slot);
EFX.alDeleteEffects((IntPtr) 1,
ref
effect);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
CommitReverbChanges(IALReverb reverb)
{
OpenALReverb rv = (reverb
as
OpenALReverb);
EFX.alAuxiliaryEffectSloti(
rv.SlotHandle,
EFX.AL_EFFECTSLOT_EFFECT,
(
int
) rv.EffectHandle
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbReflectionsDelay(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_REFLECTIONS_DELAY,
value / 1000.0f
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbDelay(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_LATE_REVERB_DELAY,
value / 1000.0f
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbPositionLeft(IALReverb reverb,
float
value)
{
}
public
void
SetReverbPositionRight(IALReverb reverb,
float
value)
{
}
public
void
SetReverbPositionLeftMatrix(IALReverb reverb,
float
value)
{
}
public
void
SetReverbPositionRightMatrix(IALReverb reverb,
float
value)
{
}
public
void
SetReverbEarlyDiffusion(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_DIFFUSION,
value / 15.0f
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbLateDiffusion(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_DIFFUSION,
value / 15.0f
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbLowEQGain(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_GAINLF,
Math.Min(
XACTCalculator.CalculateAmplitudeRatio(
value - 8.0f
),
1.0f
)
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbLowEQCutoff(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_LFREFERENCE,
(value * 50.0f) + 50.0f
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbHighEQGain(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_GAINHF,
XACTCalculator.CalculateAmplitudeRatio(
value - 8.0f
)
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbHighEQCutoff(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_HFREFERENCE,
(value * 500.0f) + 1000.0f
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbRearDelay(IALReverb reverb,
float
value)
{
}
public
void
SetReverbRoomFilterFrequency(IALReverb reverb,
float
value)
{
}
public
void
SetReverbRoomFilterMain(IALReverb reverb,
float
value)
{
}
public
void
SetReverbRoomFilterHighFrequency(IALReverb reverb,
float
value)
{
}
public
void
SetReverbReflectionsGain(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_REFLECTIONS_GAIN,
Math.Min(
XACTCalculator.CalculateAmplitudeRatio(value),
3.16f
)
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbGain(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_GAIN,
Math.Min(
XACTCalculator.CalculateAmplitudeRatio(value),
1.0f
)
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbDecayTime(IALReverb reverb,
float
value)
{
}
public
void
SetReverbDensity(IALReverb reverb,
float
value)
{
EFX.alEffectf(
(reverb
as
OpenALReverb).EffectHandle,
EFX.AL_EAXREVERB_DENSITY,
value / 100.0f
);
#if VERBOSE_AL_DEBUGGING
CheckALError();
#endif
}
public
void
SetReverbRoomSize(IALReverb reverb,
float
value)
{
}
public
void
SetReverbWetDryMix(IALReverb reverb,
float
value)
{
EFX.alAuxiliaryEffectSlotf(
(reverb
as
OpenALReverb).SlotHandle,
EFX.AL_EFFECTSLOT_GAIN,
value / 200.0f
);
}
#endregion
#region OpenAL Capture Methods
public
IntPtr StartDeviceCapture(
string
name,
int
sampleRate,
int
bufSize)
{
IntPtr result = ALC11.alcCaptureOpenDevice(
name,
(
uint
) sampleRate,
AL10.AL_FORMAT_MONO16,
(IntPtr) bufSize
);
ALC11.alcCaptureStart(result);
#if VERBOSE_AL_DEBUGGING
if
(CheckALCError())
{
throw
new
InvalidOperationException(
"AL device error!"
);
}
#endif
return
result;
}
public
void
StopDeviceCapture(IntPtr handle)
{
ALC11.alcCaptureStop(handle);
ALC11.alcCaptureCloseDevice(handle);
#if VERBOSE_AL_DEBUGGING
if
(CheckALCError())
{
throw
new
InvalidOperationException(
"AL device error!"
);
}
#endif
}
public
int
CaptureSamples(IntPtr handle, IntPtr buffer,
int
count)
{
int
[] samples =
new
int
[1] { 0 };
ALC10.alcGetIntegerv(
handle,
ALC11.ALC_CAPTURE_SAMPLES,
(IntPtr) 1,
samples
);
samples[0] = Math.Min(samples[0], count / 2);
if
(samples[0] > 0)
{
ALC11.alcCaptureSamples(handle, buffer, (IntPtr) samples[0]);
}
#if VERBOSE_AL_DEBUGGING
if
(CheckALCError())
{
throw
new
InvalidOperationException(
"AL device error!"
);
}
#endif
return
samples[0] * 2;
}
public
bool
CaptureHasSamples(IntPtr handle)
{
int
[] samples =
new
int
[1] { 0 };
ALC10.alcGetIntegerv(
handle,
ALC11.ALC_CAPTURE_SAMPLES,
(IntPtr) 1,
samples
);
return
samples[0] > 0;
}
#endregion
#region Private OpenAL Error Check Methods
private
void
CheckALError()
{
int
err = AL10.alGetError();
if
(err == AL10.AL_NO_ERROR)
{
return
;
}
FNAPlatform.Log(
"OpenAL Error: "
+ err.ToString(
"X4"
));
#if VERBOSE_AL_DEBUGGING
throw
new
InvalidOperationException(
"OpenAL Error!"
);
#endif
}
private
bool
CheckALCError()
{
int
err = ALC10.alcGetError(alDevice);
if
(err == ALC10.ALC_NO_ERROR)
{
return
false
;
}
FNAPlatform.Log(
"OpenAL Device Error: "
+ err.ToString(
"X4"
));
return
true
;
}
#endregion
#region Private Static XNA->AL Dictionaries
private
static
readonly
int
[] XNAToShort =
new
int
[]
{
AL10.AL_NONE,
AL10.AL_FORMAT_MONO16,
AL10.AL_FORMAT_STEREO16,
};
private
static
readonly
int
[] XNAToFloat =
new
int
[]
{
AL10.AL_NONE,
ALEXT.AL_FORMAT_MONO_FLOAT32,
ALEXT.AL_FORMAT_STEREO_FLOAT32
};
#endregion
#region OpenAL Device Enumerators
public
ReadOnlyCollection<RendererDetail> GetDevices()
{
IntPtr deviceList = ALC10.alcGetString(IntPtr.Zero, ALC11.ALC_ALL_DEVICES_SPECIFIER);
List<RendererDetail> renderers =
new
List<RendererDetail>();
int
i = 0;
string
curString = Marshal.PtrToStringAnsi(deviceList);
while
(!String.IsNullOrEmpty(curString))
{
renderers.Add(
new
RendererDetail(
curString,
i.ToString()
));
i += 1;
deviceList += curString.Length + 1;
curString = Marshal.PtrToStringAnsi(deviceList);
}
return
new
ReadOnlyCollection<RendererDetail>(renderers);
}
public
ReadOnlyCollection<Microphone> GetCaptureDevices()
{
IntPtr deviceList = ALC10.alcGetString(IntPtr.Zero, ALC11.ALC_CAPTURE_DEVICE_SPECIFIER);
List<Microphone> microphones =
new
List<Microphone>();
string
curString = Marshal.PtrToStringAnsi(deviceList);
while
(!String.IsNullOrEmpty(curString))
{
microphones.Add(
new
Microphone(curString));
deviceList += curString.Length + 1;
curString = Marshal.PtrToStringAnsi(deviceList);
}
return
new
ReadOnlyCollection<Microphone>(microphones);
}
#endregion
}
}