Opentk/Source/Examples/OpenAL/Test/OpenALDiagnostics.cs

632 lines
21 KiB
C#
Raw Normal View History

#region License
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
using OpenTK;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
namespace Examples
{
/// <summary>
/// A text-based diagnosis program for OpenAL.
/// The constructors will call the OpenAL commands, the Print() methods just show the information.
/// </summary>
[Example("OpenAL diagnostics", ExampleCategory.OpenAL, "Test", 0, true)]
class OpenALDiagnostics
{
public static void checkForErrors()
{
{
IntPtr device = Alc.GetContextsDevice(Alc.GetCurrentContext());
AlcError error = Alc.GetError(device);
if (error != AlcError.NoError)
Trace.WriteLine("ALC ERROR: (" + error + ") " + Alc.GetString(device, (AlcGetString)error));
}
{
ALError error = AL.GetError();
if (error != ALError.NoError)
Trace.WriteLine("AL ERROR: (" + error + ") " + AL.GetErrorString(error));
}
}
[STAThread]
static void Main()
{
Trace.Listeners.RemoveAt(0);
Trace.Listeners.Add(new ConsoleTraceListener());
Trace.WriteLine("This application is currently running as " + (IntPtr.Size == 4 ? "x86" : "x64"));
DeviceDiagnostic DevDiag = new DeviceDiagnostic();
DevDiag.Print();
DevDiag = null;
using (AudioContext A = new AudioContext())
{
AlcDiagnostic AlcDiag = new AlcDiagnostic(Alc.GetContextsDevice(Alc.GetCurrentContext()));
checkForErrors();
AlcDiag.Print();
AlcDiag = null;
ALDiagnostic ALdiag = new ALDiagnostic(A);
checkForErrors();
ALdiag.Print();
ALdiag = null;
EfxDiagnostic EfxDiag = new EfxDiagnostic();
checkForErrors();
EfxDiag.Print();
EfxDiag = null;
XRamDiagnostic XRamDiag = new XRamDiagnostic();
checkForErrors();
XRamDiag.Print();
XRamDiag = null;
RecorderDiagnostic rec = new RecorderDiagnostic();
rec.Print();
rec = null;
}
// Trace.WriteLine("All done. Press Enter to exit.");
// Console.ReadLine();
}
}
class DeviceDiagnostic
{
#region Fields
public readonly IList<string> AllPlaybackDevices;
public readonly IList<string> AllRecordingDevices;
public readonly string DefaultPlaybackDevice;
public readonly string DefaultRecordingDevice;
#endregion Fields
public DeviceDiagnostic()
{
Trace.WriteLine("--- Device related errors ---");
AllPlaybackDevices = AudioContext.AvailableDevices;
AllRecordingDevices = AudioCapture.AvailableDevices;
DefaultPlaybackDevice = AudioContext.DefaultDevice;
DefaultRecordingDevice = AudioCapture.DefaultDevice;
}
public void Print()
{
Trace.WriteLine("--- Device related analysis ---");
Trace.Indent();
{
Trace.WriteLine("Default playback device: " + DefaultPlaybackDevice);
Trace.WriteLine("All known playback devices:");
Trace.Indent();
{
foreach (string s in AllPlaybackDevices)
Trace.WriteLine(s);
}
Trace.Unindent();
Trace.WriteLine("Default recording device: " + DefaultRecordingDevice);
Trace.WriteLine("All known recording devices:");
Trace.Indent();
{
foreach (string s in AllRecordingDevices)
Trace.WriteLine(s);
}
Trace.Unindent();
}
Trace.Unindent();
}
}
class AlcDiagnostic
{
#region Fields
private string[] Alc_Extension_C_Names = new string[]
{
"ALC_ENUMERATE_ALL_EXT",
"ALC_ENUMERATION_EXT",
"ALC_EXT_ASA",
"ALC_EXT_ASA_DISTORTION",
"ALC_EXT_ASA_ROGER_BEEP",
"ALC_EXT_BRS_GAME_LICENSE_REQUIRED",
"ALC_EXT_capture",
"ALC_EXT_DEDICATED",
"ALC_EXT_EFX",
};
public readonly int MajorVersion;
public readonly int MinorVersion;
public readonly int EfxMajorVersion;
public readonly int EfxMinorVersion;
public readonly int EfxMaxAuxiliarySends;
public readonly string ExtensionString;
public readonly Dictionary<string, bool> Extensions = new Dictionary<string, bool>();
#endregion Fields
public AlcDiagnostic(IntPtr dev)
{
Trace.WriteLine("--- Alc related errors ---");
Alc.GetInteger(dev, AlcGetInteger.MajorVersion, 1, out MajorVersion);
Alc.GetInteger(dev, AlcGetInteger.MinorVersion, 1, out MinorVersion);
Alc.GetInteger(dev, AlcGetInteger.EfxMajorVersion, 1, out EfxMajorVersion);
Alc.GetInteger(dev, AlcGetInteger.EfxMinorVersion, 1, out EfxMinorVersion);
Alc.GetInteger(dev, AlcGetInteger.EfxMaxAuxiliarySends, 1, out EfxMaxAuxiliarySends);
ExtensionString = Alc.GetString(dev, AlcGetString.Extensions);
foreach (string s in Alc_Extension_C_Names)
Extensions.Add(s, Alc.IsExtensionPresent(dev, s));
}
public void Print()
{
Trace.WriteLine("--- Alc related analysis ---");
Trace.Indent();
{
Trace.WriteLine("Alc Version: " + MajorVersion + "." + MinorVersion);
Trace.WriteLine("Efx Version: " + EfxMajorVersion + "." + EfxMinorVersion);
Trace.WriteLine("Efx max. Auxiliary sends: " + EfxMaxAuxiliarySends);
Trace.WriteLine("Alc Extension string: " + ExtensionString);
Trace.WriteLine("Confirmed Alc Extensions:");
Trace.Indent();
{
foreach (KeyValuePair<string, bool> pair in Extensions)
Trace.WriteLine(pair.Key + ": " + pair.Value);
}
Trace.Unindent();
}
Trace.Unindent();
}
}
class ALDiagnostic
{
#region Fields
private string[] AL_Extension_Names = new string[]
{
"AL_EXT_ALAW",
"AL_EXT_BFORMAT",
"AL_EXT_double",
"AL_EXT_EXPONENT_DISTANCE",
"AL_EXT_float32",
"AL_EXT_FOLDBACK",
"AL_EXT_IMA4",
"AL_EXT_LINEAR_DISTANCE",
"AL_EXT_MCFORMATS",
"AL_EXT_mp3",
"AL_EXT_MULAW",
"AL_EXT_OFFSET",
"AL_EXT_vorbis",
"AL_LOKI_quadriphonic",
"EAX-RAM",
"EAX",
"EAX1.0",
"EAX2.0",
"EAX3.0",
"EAX3.0EMULATED",
"EAX4.0",
"EAX4.0EMULATED",
"EAX5.0"
};
public readonly Dictionary<string, bool> Extensions = new Dictionary<string, bool>();
public readonly string DeviceName;
public readonly float SpeedOfSound;
public readonly string ExtensionString;
public readonly string Renderer;
public readonly string Vendor;
public readonly string Version;
public readonly ALDistanceModel DistanceModel;
const uint MaxSourcesLimit = 128;
public readonly uint MaxSources;
#endregion Fields
public ALDiagnostic(AudioContext ac)
{
Trace.WriteLine("--- AL related errors ---");
DeviceName = ac.CurrentDevice;
ExtensionString = AL.Get(ALGetString.Extensions);
Renderer = AL.Get(ALGetString.Renderer);
Vendor = AL.Get(ALGetString.Vendor);
Version = AL.Get(ALGetString.Version);
SpeedOfSound = AL.Get(ALGetFloat.SpeedOfSound);
DistanceModel = AL.GetDistanceModel();
foreach (string s in AL_Extension_Names)
Extensions.Add(s, AL.IsExtensionPresent(s));
AL.GetError(); // clear it, need this for the source counting to work properly
uint[] dummy_sources = new uint[MaxSourcesLimit];
for (MaxSources = 0; MaxSources < MaxSourcesLimit; MaxSources++)
{
AL.GenSource(out dummy_sources[MaxSources]);
if (AL.GetError() != ALError.NoError)
break;
}
for (int i = 0; i < MaxSources; i++)
AL.DeleteSource(ref dummy_sources[i]);
}
public void Print()
{
Trace.WriteLine("--- AL related analysis ---");
Trace.Indent();
{
Trace.WriteLine("Used Device: "+DeviceName);
Trace.WriteLine("AL Renderer: " + Renderer);
Trace.WriteLine("AL Vendor: " + Vendor);
Trace.WriteLine("AL Version: " + Version);
Trace.WriteLine("AL Speed of sound: " + SpeedOfSound);
Trace.WriteLine("AL Distance Model: " + DistanceModel.ToString());
Trace.WriteLine("AL Maximum simultanous Sources: " + MaxSources);
Trace.WriteLine("AL Extension string: " + ExtensionString);
Trace.WriteLine("Confirmed AL Extensions:");
Trace.Indent();
{
foreach (KeyValuePair<string, bool> pair in Extensions)
Trace.WriteLine(pair.Key + ": " + pair.Value);
}
Trace.Unindent();
}
Trace.Unindent();
}
}
class EfxDiagnostic
{
#region Fields
private EfxEffectType[] EffectNames = new EfxEffectType[]
{
EfxEffectType.Autowah,
EfxEffectType.Chorus,
EfxEffectType.Compressor,
EfxEffectType.Distortion,
EfxEffectType.EaxReverb,
EfxEffectType.Echo,
EfxEffectType.Equalizer,
EfxEffectType.Flanger,
EfxEffectType.FrequencyShifter,
EfxEffectType.PitchShifter,
EfxEffectType.Reverb,
EfxEffectType.RingModulator,
EfxEffectType.VocalMorpher,
};
private EfxFilterType[] FilterNames = new EfxFilterType[]
{
EfxFilterType.Bandpass,
EfxFilterType.Highpass,
EfxFilterType.Lowpass,
};
public readonly Dictionary<string, bool> Effects = new Dictionary<string, bool>();
public readonly Dictionary<string, bool> Filters = new Dictionary<string, bool>();
const uint MaxAuxiliaryEffectSlotsLimit = 4;
public readonly uint MaxAuxiliaryEffectSlots;
#endregion Fields
public EfxDiagnostic()
{
Trace.WriteLine("--- Efx related errors ---");
EffectsExtension Efx = new EffectsExtension();
Trace.Assert(Efx.IsInitialized);
#region Test for available Effects
uint effect;
Efx.GenEffect(out effect);
AL.GetError();
foreach (EfxEffectType e in EffectNames)
{
Efx.BindEffect(effect, e);
Effects.Add(e.ToString(), AL.GetError() == ALError.NoError);
}
Efx.DeleteEffect(ref effect);
#endregion Test for available Effects
#region Test for available Filters
uint filter;
Efx.GenFilter(out filter);
AL.GetError();
foreach (EfxFilterType f in FilterNames)
{
Efx.Filter(filter, EfxFilteri.FilterType, (int)f);
Filters.Add(f.ToString(), AL.GetError() == ALError.NoError);
}
Efx.DeleteFilter(ref filter);
#endregion Test for available Filters
AL.GetError();
uint[] dummy_slots = new uint[MaxAuxiliaryEffectSlotsLimit];
for (MaxAuxiliaryEffectSlots = 0; MaxAuxiliaryEffectSlots < MaxAuxiliaryEffectSlotsLimit; MaxAuxiliaryEffectSlots++)
{
Efx.GenAuxiliaryEffectSlot(out dummy_slots[MaxAuxiliaryEffectSlots]);
if (AL.GetError() != ALError.NoError)
break;
}
for (uint i = 0; i < MaxAuxiliaryEffectSlots; i++)
Efx.DeleteAuxiliaryEffectSlot(ref dummy_slots[i]);
}
public void Print()
{
Trace.WriteLine("--- Efx related analysis ---");
Trace.Indent();
{
Trace.WriteLine("Efx Effects supported:");
Trace.Indent();
{
foreach (KeyValuePair<string, bool> pair in Effects)
Trace.WriteLine(pair.Key + ": " + pair.Value);
}
Trace.Unindent();
Trace.WriteLine("Efx Filters supported:");
Trace.Indent();
{
foreach (KeyValuePair<string, bool> pair in Filters)
Trace.WriteLine(pair.Key + ": " + pair.Value);
}
Trace.Unindent();
Trace.WriteLine("Efx max. Auxiliary Effect Slots: " + MaxAuxiliaryEffectSlots);
}
Trace.Unindent();
}
}
class XRamDiagnostic
{
#region Fields
private XRamExtension.XRamStorage[] storagemodes = new XRamExtension.XRamStorage[]
{
XRamExtension.XRamStorage.Hardware,
XRamExtension.XRamStorage.Accessible,
XRamExtension.XRamStorage.Automatic,
};
public readonly bool XRamFound;
public readonly int RamTotal;
public readonly int RamFree;
public readonly Dictionary<string, bool> BufferModes = new Dictionary<string, bool>();
#endregion Fields
public XRamDiagnostic()
{
Trace.WriteLine("--- X-RAM related errors ---");
XRamExtension XRam = new XRamExtension();
if (XRam.IsInitialized)
{
XRamFound = true;
RamTotal = XRam.GetRamSize;
RamFree = XRam.GetRamFree;
uint buffer;
AL.GenBuffer(out buffer);
foreach (XRamExtension.XRamStorage m in storagemodes)
{
bool result = XRam.SetBufferMode(1, ref buffer, m);
BufferModes.Add(m.ToString(), m == XRam.GetBufferMode(ref buffer));
}
AL.DeleteBuffer(ref buffer);
}
else
XRamFound = false;
}
public void Print()
{
Trace.WriteLine("--- X-RAM related analysis ---");
if (XRamFound)
{
Trace.Indent(); // *
Trace.WriteLine("X-RAM extension found.");
}
else
{
Trace.Indent();
{
Trace.WriteLine("X-RAM extension is not available, skipping test.");
}
Trace.Unindent();
return;
}
Trace.WriteLine("Ram status (free/total) in bytes: " + RamFree + "/" + RamTotal);
Trace.WriteLine("Available buffer modes:");
Trace.Indent();
{
foreach (KeyValuePair<string, bool> pair in BufferModes)
Trace.WriteLine(pair.Key + ": " + pair.Value);
}
Trace.Unindent();
Trace.Unindent(); // *
}
}
class RecorderDiagnostic
{
#region Fields
bool IsDeviceAvailable;
bool BufferContentsAllZero;
short MaxSample = short.MinValue;
short MinSample = short.MaxValue;
private AudioCapture r;
Dictionary<string, AlcError> Errorlist = new Dictionary<string, AlcError>();
string DeviceName;
#endregion Fields
private void CheckRecorderError(string location)
{
AlcError err = r.CurrentError;
if (err != AlcError.NoError)
Errorlist.Add(location, err);
}
public RecorderDiagnostic()
{
Trace.WriteLine("--- AudioCapture related errors ---");
IsDeviceAvailable = false;
try
{
r = new AudioCapture(AudioCapture.DefaultDevice, 16000, ALFormat.Mono16, 4096);
}
catch (AudioDeviceException ade)
{
Trace.WriteLine("AudioCapture Exception caught: " + ade.Message);
return;
}
IsDeviceAvailable = true;
DeviceName = r.CurrentDevice;
CheckRecorderError("Alc.CaptureOpenDevice");
r.Start();
CheckRecorderError("Alc.CaptureStart");
Thread.Sleep(100);
r.Stop();
CheckRecorderError("Alc.CaptureStop");
byte[] Buffer = new byte[8192];
Thread.Sleep(10); // Wait for a few samples to become available.
int SamplesBefore = r.AvailableSamples;
CheckRecorderError("Alc.GetInteger(...CaptureSamples...)");
r.ReadSamples(Buffer, (SamplesBefore > 4096 ? 4096 : SamplesBefore));
CheckRecorderError("Alc.CaptureSamples");
int SamplesCaptured = SamplesBefore - r.AvailableSamples;
uint ZeroCounter = 0;
for (int i = 0; i < SamplesCaptured * 2; i++)
{
if (Buffer[i] == 0)
ZeroCounter++;
}
for (int i = 0; i < SamplesCaptured; i++)
{
short sample = BitConverter.ToInt16(Buffer, i * 2);
if (sample > MaxSample)
MaxSample = sample;
if (sample < MinSample)
MinSample = sample;
}
if (ZeroCounter < SamplesCaptured * 2 && SamplesCaptured > 0)
BufferContentsAllZero = false;
else
BufferContentsAllZero = true;
r.Dispose();
CheckRecorderError("Alc.CaptureCloseDevice");
// no playback test needed due to Parrot test app.
/*
uint buf;
AL.GenBuffer(out buf);
AL.BufferData(buf, ALFormat.Mono16, BufferPtr, SamplesCaptured * 2, 16000);
uint src;
AL.GenSource(out src);
AL.BindBufferToSource(src, buf);
AL.Listener(ALListenerf.Gain, 16.0f);
AL.SourcePlay(src);
while (AL.GetSourceState(src) == ALSourceState.Playing)
{
Thread.Sleep(0);
}
AL.SourceStop(src);
AL.DeleteSource(ref src);
AL.DeleteBuffer(ref buf);
*/
}
public void Print()
{
Trace.WriteLine("--- AudioCapture related analysis ---");
if (!IsDeviceAvailable)
{
Trace.WriteLine("Capture Device could not be initlialized (no microphone plugged into the jack?). Skipping test.");
return;
}
Trace.Indent();
{
Trace.WriteLine("Using capture device: " + DeviceName);
if (Errorlist.Count > 0)
{
Trace.WriteLine("Found Alc Errors:");
Trace.Indent();
{
foreach (KeyValuePair<string, AlcError> pair in Errorlist)
Trace.WriteLine(pair.Key + ": " + pair.Value);
}
Trace.Unindent();
}
Trace.WriteLine("Buffer contents after capture was all 0's: " + BufferContentsAllZero);
Trace.WriteLine("Sample min/max in recorded data: " + MinSample + " / " + MaxSample);
}
Trace.Unindent();
}
}
}