using Amphora;
using Azimuth;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace Susurrus.XAudio2.Testbed
{
///
/// Plays sounds through for a person to listen to, and prints what the engine reports.
/// Files named on the command line play first, and each stage after that shows one behavior of the module.
///
class Program
{
const int SampleRate = 48000;
static void Pump(XAudio2Module module, int milliseconds)
{
DateTime end = DateTime.UtcNow.AddMilliseconds(milliseconds);
while (DateTime.UtcNow < end)
{
module.Update();
Thread.Sleep(16);
}
}
static void PumpUntilFinished(XAudio2Module module, Voice voice)
{
while (module.IsPlaying(voice))
{
module.Update();
Thread.Sleep(16);
}
}
static float Envelope(int frame, int frameCount)
{
// A short fade at each end, so a sound doesn't click when it starts and stops.
int fade = SampleRate / 100;
return Math.Min(1f, Math.Min(frame, frameCount - 1 - frame) / (float)fade);
}
static DecodedSound Tone(double leftHertz, double rightHertz, double seconds, int sampleRate, int channelCount)
{
int frameCount = (int)(seconds * sampleRate);
short[] samples = new short[frameCount * channelCount];
for (int frame = 0; frame < frameCount; ++frame)
{
double time = frame / (double)sampleRate;
float level = 0.3f * Envelope(frame, frameCount) * short.MaxValue;
samples[frame * channelCount] = (short)(level * Math.Sin(2 * Math.PI * leftHertz * time));
if (channelCount == 2)
{
samples[frame * channelCount + 1] = (short)(level * Math.Sin(2 * Math.PI * rightHertz * time));
}
}
byte[] bytes = new byte[samples.Length * 2];
Buffer.BlockCopy(samples, 0, bytes, 0, bytes.Length);
return new DecodedSound(new ByteView(bytes), sampleRate, channelCount, SampleFormat.Pcm16);
}
static DecodedSound RisingSweepOfFloats(double seconds)
{
int frameCount = (int)(seconds * SampleRate);
float[] samples = new float[frameCount];
double phase = 0;
for (int frame = 0; frame < frameCount; ++frame)
{
double hertz = 300 + 900 * frame / (double)frameCount;
phase += 2 * Math.PI * hertz / SampleRate;
samples[frame] = 0.3f * Envelope(frame, frameCount) * (float)Math.Sin(phase);
}
byte[] bytes = new byte[samples.Length * 4];
Buffer.BlockCopy(samples, 0, bytes, 0, bytes.Length);
return new DecodedSound(new ByteView(bytes), SampleRate, channelCount: 1, SampleFormat.Float32);
}
static void PrintPerformance(XAudio2Module module, string when)
{
XAudio2PerformanceData data = module.GetPerformanceData();
Console.WriteLine($" [{when}] active voices {data.ActiveSourceVoiceCount} of " +
$"{data.TotalSourceVoiceCount}, glitches {data.GlitchesSinceEngineStarted}, " +
$"latency {data.CurrentLatencyInSamples} samples, memory {data.MemoryUsageInBytes} bytes");
}
static void PlayAndWait(XAudio2Module module, string name, Sound sound, float volume)
{
Console.WriteLine($" {name}: {sound.ChannelCount} channel(s), {sound.Duration.TotalSeconds:0.00} s");
Voice voice = module.Play(sound, volume);
if (voice.IsNone)
{
Console.WriteLine(" didn't start: " + module.LastFailure.Kind);
return;
}
Pump(module, milliseconds: 50);
PrintPerformance(module, "playing");
PumpUntilFinished(module, voice);
Pump(module, milliseconds: 250);
}
static void PlayFiles(XAudio2Module module, string[] paths)
{
Console.WriteLine("Files:");
foreach (string path in paths)
{
StatusOr decoded = SoundDecoder.Decode(new ByteView(File.ReadAllBytes(path)));
if (!decoded.IsOk)
{
Console.WriteLine($" {path}: {decoded.Status.Describe()}");
continue;
}
PlayAndWait(module, Path.GetFileName(path), module.LoadSound(decoded.Value), volume: 0.5f);
}
}
static void PlayKinds(XAudio2Module module)
{
Console.WriteLine("Mono, stereo (440 Hz left, 660 Hz right) and 32-bit float (a rising sweep):");
PlayAndWait(module, "mono 440 Hz", module.LoadSound(Tone(440, 440, 1, SampleRate, 1)), volume: 1f);
PlayAndWait(module, "stereo", module.LoadSound(Tone(440, 660, 1, SampleRate, 2)), volume: 1f);
PlayAndWait(module, "float sweep", module.LoadSound(RisingSweepOfFloats(1.5)), volume: 1f);
}
static void PlayAtOtherRates(XAudio2Module module)
{
Console.WriteLine("The same 440 Hz tone made at three sample rates, which should all sound alike:");
foreach (int rate in new[] { 22050, 48000, 96000 })
{
PlayAndWait(module, $"{rate} Hz", module.LoadSound(Tone(440, 440, 0.7, rate, 1)), volume: 1f);
}
}
static void FadeOut(XAudio2Module module)
{
Console.WriteLine("A tone fading out over two seconds, then stopped:");
Voice voice = module.Play(module.LoadSound(Tone(330, 330, 5, SampleRate, 1)), volume: 1f);
for (int step = 0; step <= 40; ++step)
{
module.SetVolume(voice, 1f - step / 40f);
Pump(module, milliseconds: 50);
}
module.Stop(voice);
Console.WriteLine($" still playing after Stop: {module.IsPlaying(voice)}");
Pump(module, milliseconds: 250);
}
static void PanDemo(XAudio2Module module)
{
Console.WriteLine($"Panning on a device with {module.DeviceChannelCount} channels.");
Console.WriteLine("A mono tone panned from the left to the right, at constant loudness:");
SweepPan(module, module.LoadSound(Tone(330, 330, 4, SampleRate, 1)));
Console.WriteLine("A stereo sound, 440 Hz left and 660 Hz right, panned the same way.");
Console.WriteLine("Each side folds into the other as it nears the edge, so none of it is lost:");
SweepPan(module, module.LoadSound(Tone(440, 660, 4, SampleRate, 2)));
}
static void SweepPan(XAudio2Module module, Sound sound)
{
Voice voice = module.Play(sound, volume: 1f, pan: -1f);
for (int step = 0; step <= 60; ++step)
{
module.SetPan(voice, -1f + step / 30f);
Pump(module, milliseconds: 50);
}
module.Stop(voice);
Pump(module, milliseconds: 250);
}
static void PitchDemo(XAudio2Module module)
{
Console.WriteLine("A 220 Hz tone swept from two octaves down to two octaves up, then stopped:");
Voice voice = module.Play(module.LoadSound(Tone(220, 220, 8, SampleRate, 1)), volume: 1f,
pitch: Pitch.FromSemitones(-24f));
for (int step = 0; step <= 80; ++step)
{
module.SetPitch(voice, Pitch.FromSemitones(-24f + step * 0.6f));
Pump(module, milliseconds: 50);
}
module.Stop(voice);
Pump(module, milliseconds: 250);
}
static void Burst(XAudio2Module module)
{
Console.WriteLine("A burst of 100 blips at once, in rising pitches:");
List blips = new List();
for (int i = 0; i < 100; ++i)
{
blips.Add(module.LoadSound(Tone(300 + 6 * i, 300 + 6 * i, 0.4, SampleRate, 1)));
}
int started = 0;
foreach (Sound blip in blips)
{
if (!module.Play(blip, volume: 0.1f).IsNone)
{
++started;
}
}
Console.WriteLine($" {started} of 100 started, and the rest found every mono voice busy");
Pump(module, milliseconds: 100);
PrintPerformance(module, "burst playing");
Pump(module, milliseconds: 600);
PrintPerformance(module, "burst over");
}
static void Run(Mixer mixer, int milliseconds)
{
Stopwatch watch = Stopwatch.StartNew();
double last = 0;
while (watch.ElapsedMilliseconds < milliseconds)
{
double now = watch.Elapsed.TotalSeconds;
mixer.Update((float)(now - last));
last = now;
Thread.Sleep(16);
}
}
static void MixerDemo(XAudio2Module module)
{
Console.WriteLine("The mixer: caps, retrigger intervals, clip variants and buses.");
Mixer mixer = new Mixer(
module, new Xoshiro256PlusPlus(seed: 1));
Bus effects = mixer.AddBus("Effects");
Bus music = mixer.AddBus("Music");
Sound[] pops =
{
module.LoadSound(Tone(400, 400, 0.4, SampleRate, 1)),
module.LoadSound(Tone(500, 500, 0.4, SampleRate, 1)),
module.LoadSound(Tone(600, 600, 0.4, SampleRate, 1)),
};
SoundId capped = mixer.Define(new SoundDefinition(pops, effects, maxInstances: 3, neverRepeatClip: true));
SoundId rattle = mixer.Define(new SoundDefinition(pops[0], effects, minRetriggerSeconds: 0.1f));
SoundId variants = mixer.Define(new SoundDefinition(pops, effects, neverRepeatClip: true));
SoundId drone = mixer.Define(new SoundDefinition(
module.LoadSound(Tone(220, 220, 6, SampleRate, 1)), music, baseVolume: 0.6f));
int started = 0;
for (int i = 0; i < 12; ++i)
{
if (!mixer.Play(capped).IsNone)
{
++started;
}
}
Console.WriteLine($" a dozen plays in one frame of a sound capped at 3: {started} started");
Run(mixer, milliseconds: 800);
started = 0;
for (int frame = 0; frame < 60; ++frame)
{
if (!mixer.Play(rattle).IsNone)
{
++started;
}
Run(mixer, milliseconds: 20);
}
Console.WriteLine($" a play every 20 ms for a second, with a 100 ms interval: {started} started");
Run(mixer, milliseconds: 500);
Console.WriteLine(" six plays of three clips, never the same clip twice in a row:");
for (int i = 0; i < 6; ++i)
{
mixer.Play(variants);
Run(mixer, milliseconds: 500);
}
Console.WriteLine(" a drone on the Music bus, with pops on Effects over it.");
Console.WriteLine(" Music slides down in decibels over two seconds, is muted, then comes back:");
mixer.Play(drone);
for (int step = 0; step <= 20; ++step)
{
music.Volume = Volume.FromSlider(1f - step / 20f, floorDecibels: -40f);
mixer.Play(variants);
Run(mixer, milliseconds: 100);
}
music.Volume = 1f;
music.IsMuted = true;
Run(mixer, milliseconds: 700);
music.IsMuted = false;
Run(mixer, milliseconds: 700);
Console.WriteLine($" voices in use: {mixer.ActiveCount}");
Run(mixer, milliseconds: 3000);
}
static void StealDemo(XAudio2Module module)
{
Console.WriteLine("Stealing: a mixer with 4 voices, all taken by quiet drones of priority 0.");
Mixer mixer = new Mixer(
module, new Xoshiro256PlusPlus(seed: 2), maxVoices: 4);
Bus effects = mixer.AddBus("Effects");
SoundId[] drones = new SoundId[4];
double[] pitches = { 220, 277, 330, 415 };
for (int i = 0; i < drones.Length; ++i)
{
drones[i] = mixer.Define(new SoundDefinition(
module.LoadSound(Tone(pitches[i], pitches[i], 6, SampleRate, 1)), effects, baseVolume: 0.5f));
}
SoundId pop = mixer.Define(new SoundDefinition(
module.LoadSound(Tone(800, 800, 0.3, SampleRate, 1)), effects, priority: 1));
foreach (SoundId drone in drones)
{
mixer.Play(drone);
}
Run(mixer, milliseconds: 800);
Console.WriteLine(" four high-priority pops 100 ms apart, each fading out the oldest drone, no click:");
for (int i = 0; i < 4; ++i)
{
mixer.Play(pop);
Console.WriteLine($" playing {mixer.ActiveCount}, fading {mixer.FadingCount}");
Run(mixer, milliseconds: 100);
}
Run(mixer, milliseconds: 1500);
Run(mixer, milliseconds: 1000);
Console.WriteLine(" a 300 Hz tone stopped mid-cycle, which should end without a click:");
Voice tone = mixer.Play(mixer.Define(new SoundDefinition(
module.LoadSound(Tone(300, 300, 3, SampleRate, 1)), effects)));
Run(mixer, milliseconds: 1013);
mixer.Stop(tone);
Run(mixer, milliseconds: 500);
}
static void VariationDemo(XAudio2Module module)
{
Console.WriteLine("Variation: one 440 Hz blip, each play drawing 3 semitones either way and -9 to 0 dB.");
Mixer mixer = new Mixer(module, new Xoshiro256PlusPlus(seed: 3));
Bus effects = mixer.AddBus("Effects");
SoundId blip = mixer.Define(new SoundDefinition(
module.LoadSound(Tone(440, 440, 0.25, SampleRate, 1)), effects,
volumeDecibels: new Variation(-9, 0), pitchSemitones: Variation.PlusOrMinus(3)));
for (int i = 0; i < 12; ++i)
{
Voice voice = mixer.Play(blip);
Console.WriteLine($" play {i + 1}: pitch {module.PitchOf(voice):0.000}");
Run(mixer, milliseconds: 350);
}
Console.WriteLine(" the same blip with the pan set per play, left to right:");
for (int i = 0; i <= 8; ++i)
{
mixer.Play(blip, pan: -1f + i / 4f);
Run(mixer, milliseconds: 350);
}
Console.WriteLine(" a longer tone that starts two octaves up, then SetPitch takes it two octaves down:");
SoundId held = mixer.Define(new SoundDefinition(
module.LoadSound(Tone(440, 440, 3, SampleRate, 1)), effects, baseVolume: 0.5f));
Voice sweeping = mixer.Play(held, pitch: 4f);
for (int step = 0; step <= 40; ++step)
{
mixer.SetPitch(sweeping, Pitch.FromSemitones(24f - step * 1.2f));
Run(mixer, milliseconds: 50);
}
mixer.Stop(sweeping);
Run(mixer, milliseconds: 300);
}
static void PlacementDemo(XAudio2Module module)
{
Console.WriteLine("Placement: a tone moves from far left to far right across a view 10 units each way.");
Mixer mixer = new Mixer(module, new Xoshiro256PlusPlus(seed: 4));
Bus effects = mixer.AddBus("Effects");
mixer.View = new View(Vector.Zero, 10);
SoundId passing = mixer.Define(new SoundDefinition(
module.LoadSound(Tone(440, 440, 3.2, SampleRate, 1)), effects, baseVolume: 0.5f,
falloff: new Falloff(fullVolumeDistance: 10, silentDistance: 30)));
Console.WriteLine($" a play 40 units away is dropped: {mixer.Play(passing, new Vector(-40, 0)).IsNone}");
Voice tone = mixer.Play(passing, new Vector(-29, 0));
for (int step = 0; step <= 58; ++step)
{
mixer.SetPosition(tone, new Vector(-29 + step, 0));
Run(mixer, milliseconds: 50);
}
Console.WriteLine(" the same tone standing still while the view pans past it:");
Voice standing = mixer.Play(passing, new Vector(0, 0));
for (int step = 0; step <= 58; ++step)
{
mixer.View = new View(new Vector(-29 + step, 0), 10);
Run(mixer, milliseconds: 50);
}
mixer.Stop(standing);
Run(mixer, milliseconds: 300);
}
static void LoopDemo(XAudio2Module module)
{
Console.WriteLine("Loop: a 1.5 s rising sweep that then repeats 0.3 s to 0.9 s of itself, stopped at 4 s.");
Mixer mixer = new Mixer(module, new Xoshiro256PlusPlus(seed: 5));
Bus effects = mixer.AddBus("Effects");
SoundId looping = mixer.Define(new SoundDefinition(
module.LoadSound(RisingSweepOfFloats(1.5)), effects,
loop: new Loop(TimeSpan.FromSeconds(0.3), TimeSpan.FromSeconds(0.9))));
Voice voice = mixer.Play(looping);
Run(mixer, milliseconds: 4000);
Console.WriteLine($" still playing after the sweep's own 1.5 s: {mixer.IsPlaying(voice)}");
mixer.Stop(voice);
Run(mixer, milliseconds: 300);
}
static byte[] WavFileOf(DecodedSound sound)
{
int bytesPerSample = DecodedSound.GetBytesPerSample(sound.Format);
int blockAlign = sound.ChannelCount * bytesPerSample;
byte[] samples = new byte[sound.Samples.Length];
sound.Samples.CopyTo(samples, 0);
using (MemoryStream file = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(file))
{
writer.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));
writer.Write(36 + samples.Length);
writer.Write(System.Text.Encoding.ASCII.GetBytes("WAVEfmt "));
writer.Write(16);
writer.Write((short)(sound.Format == SampleFormat.Float32 ? 3 : 1));
writer.Write((short)sound.ChannelCount);
writer.Write(sound.SampleRate);
writer.Write(sound.SampleRate * blockAlign);
writer.Write((short)blockAlign);
writer.Write((short)(bytesPerSample * 8));
writer.Write(System.Text.Encoding.ASCII.GetBytes("data"));
writer.Write(samples.Length);
writer.Write(samples);
return file.ToArray();
}
}
static void StreamDemo(XAudio2Module module)
{
Console.WriteLine("Stream: a 1.5 s rising sweep decoded as it plays, then the same sweep repeating " +
"0.3 s to 0.9 s of itself until 4 s.");
byte[] file = WavFileOf(RisingSweepOfFloats(1.5));
StreamedSound sound = (StreamedSound)module.LoadStream(new ByteChunks(new ByteView(file))).Result.Value;
PumpUntilFinished(module, module.Play(sound, volume: 1f));
Voice looping = module.Play(
sound, volume: 1f, loop: new Loop(TimeSpan.FromSeconds(0.3), TimeSpan.FromSeconds(0.9)));
Pump(module, milliseconds: 4000);
Console.WriteLine($" still playing after the sweep's own 1.5 s: {module.IsPlaying(looping)}");
module.Stop(looping);
Pump(module, milliseconds: 300);
sound.Dispose();
}
static SoundId DefineStreamedTrack(XAudio2Module module, Mixer mixer, Bus music, DecodedSound track)
{
StreamedSound sound = (StreamedSound)module.LoadStream(
new ByteChunks(new ByteView(WavFileOf(track)))).Result.Value;
return mixer.Define(new SoundDefinition(sound, music, loop: Loop.Whole, fadeInSeconds: 1.5f,
fadeOutSeconds: 1.5f));
}
static void CrossfadeDemo(XAudio2Module module)
{
Console.WriteLine("Crossfade: two streamed tracks, a chord at 220 and 277 Hz then one at 330 and 415 Hz, " +
"crossfading over 1.5 s every 3 s.");
Mixer mixer = new Mixer(module, new Xoshiro256PlusPlus(seed: 6));
Bus music = mixer.AddBus("Music");
SoundId first = DefineStreamedTrack(module, mixer, music,
Tone(220, 277, seconds: 2, SampleRate, channelCount: 2));
SoundId second = DefineStreamedTrack(module, mixer, music,
Tone(330, 415, seconds: 2, SampleRate, channelCount: 2));
Voice current = mixer.Play(first);
for (int round = 0; round < 3; ++round)
{
Run(mixer, milliseconds: 3000);
mixer.Stop(current);
current = mixer.Play(round % 2 == 0 ? second : first);
Console.WriteLine($" crossfading, playing {mixer.ActiveCount}, fading {mixer.FadingCount}");
}
Run(mixer, milliseconds: 3000);
mixer.Stop(current);
Run(mixer, milliseconds: 1800);
}
static void PauseDemo(XAudio2Module module)
{
Console.WriteLine("Pause: a looping sweep on the music bus, paused for 1.5 s while a blip on the effects " +
"bus keeps sounding, then resumed from where it stopped.");
Mixer mixer = new Mixer(module, new Xoshiro256PlusPlus(seed: 7));
Bus music = mixer.AddBus("Music");
Bus effects = mixer.AddBus("Effects");
SoundId sweep = mixer.Define(new SoundDefinition(
module.LoadSound(RisingSweepOfFloats(2)), music, loop: Loop.Whole));
SoundId blip = mixer.Define(new SoundDefinition(
module.LoadSound(Tone(660, 660, seconds: 0.2, SampleRate, channelCount: 1)), effects));
Voice voice = mixer.Play(sweep);
Run(mixer, milliseconds: 1000);
music.IsPaused = true;
for (int i = 0; i < 3; ++i)
{
Run(mixer, milliseconds: 500);
mixer.Play(blip);
}
music.IsPaused = false;
Run(mixer, milliseconds: 1500);
mixer.Stop(voice);
Run(mixer, milliseconds: 300);
}
static void BackgroundDemo(XAudio2Module module)
{
Console.WriteLine("Background: a looping sweep, then the game goes to the background for 1.5 s under " +
"each policy in turn: mute, duck to a quarter and pause. Each time it comes back for a second.");
Mixer mixer = new Mixer(module, new Xoshiro256PlusPlus(seed: 8));
Bus music = mixer.AddBus("Music");
SoundId sweep = mixer.Define(new SoundDefinition(
module.LoadSound(RisingSweepOfFloats(2)), music, loop: Loop.Whole));
Voice voice = mixer.Play(sweep);
Run(mixer, milliseconds: 1000);
foreach (BackgroundPolicy policy in new[] { BackgroundPolicy.Mute, BackgroundPolicy.Duck,
BackgroundPolicy.Pause })
{
Console.WriteLine($" background, {policy}");
mixer.BackgroundPolicy = policy;
mixer.IsInBackground = true;
Run(mixer, milliseconds: 1500);
mixer.IsInBackground = false;
Console.WriteLine(" foreground");
Run(mixer, milliseconds: 1000);
}
mixer.Stop(voice);
Run(mixer, milliseconds: 300);
}
// A whole number of cycles in a second, so the loop joins without a click.
static DecodedSound HumOfFloats(double hertz)
{
float[] samples = new float[SampleRate];
for (int frame = 0; frame < samples.Length; ++frame)
{
samples[frame] = 0.3f * (float)Math.Sin(2 * Math.PI * hertz * frame / SampleRate);
}
byte[] bytes = new byte[samples.Length * 4];
Buffer.BlockCopy(samples, 0, bytes, 0, bytes.Length);
return new DecodedSound(new ByteView(bytes), SampleRate, channelCount: 1, SampleFormat.Float32);
}
static void FactoryDemo(XAudio2Module module)
{
Console.WriteLine("Factories: three at the left, middle and right of the view share one hum. They " +
"switch on at 0, 1.5 and 3 s and off at 6, 7.5 and 9 s, each reporting every frame while it is on.");
Mixer mixer = new Mixer(module, new Xoshiro256PlusPlus(seed: 9));
Bus effects = mixer.AddBus("Effects");
mixer.View = new View(Vector.Zero, 10);
SoundId hum = mixer.Define(new SoundDefinition(module.LoadSound(HumOfFloats(110)), effects,
loop: Loop.Whole, fadeInSeconds: 0.5f, fadeOutSeconds: 0.5f,
falloff: new Falloff(fullVolumeDistance: 10, silentDistance: 30)));
double[] positions = { -8, 0, 8 };
double[] onAt = { 0, 1.5, 3 };
double[] offAt = { 6, 7.5, 9 };
Stopwatch watch = Stopwatch.StartNew();
double last = 0;
int lastCount = -1;
while (watch.Elapsed.TotalSeconds < 10.5)
{
double now = watch.Elapsed.TotalSeconds;
int on = 0;
for (int i = 0; i < positions.Length; ++i)
{
if (now >= onAt[i] && now < offAt[i])
{
mixer.Sustain(hum, new Vector(positions[i], 0), volume: 0.7f);
++on;
}
}
if (on != lastCount)
{
lastCount = on;
Console.WriteLine($" {on} factories on, {mixer.ActiveCount} voice playing");
}
mixer.Update((float)(now - last));
last = now;
Thread.Sleep(16);
}
}
static void LimiterDemo(XAudio2Module module)
{
Console.WriteLine("Limiter: twelve tones at once, a harmonic series from 220 Hz, three times: " +
"limited, unlimited, limited. The unlimited one should sound harsh.");
bool before = module.LimiterEnabled;
Sound[] tones = new Sound[12];
for (int i = 0; i < tones.Length; ++i)
{
tones[i] = module.LoadSound(Tone(220 * (i + 1), 220 * (i + 1), seconds: 1.2, SampleRate,
channelCount: 1));
}
foreach (bool limited in new[] { true, false, true })
{
module.LimiterEnabled = limited;
Console.WriteLine($" {(limited ? "limited" : "unlimited")}");
foreach (Sound tone in tones)
{
module.Play(tone, volume: 1f);
}
Pump(module, milliseconds: 1800);
}
module.LimiterEnabled = before;
}
static int Main(string[] args)
{
XAudio2Module module = new XAudio2Module();
if (!module.IsSupported)
{
Console.WriteLine("XAudio2 or an audio device isn't available on this machine.");
return 1;
}
module.Load();
try
{
PrintPerformance(module, "loaded");
PlayFiles(module, args);
PlayKinds(module);
PlayAtOtherRates(module);
FadeOut(module);
PanDemo(module);
PitchDemo(module);
Burst(module);
MixerDemo(module);
StealDemo(module);
VariationDemo(module);
PlacementDemo(module);
LoopDemo(module);
StreamDemo(module);
CrossfadeDemo(module);
PauseDemo(module);
BackgroundDemo(module);
FactoryDemo(module);
LimiterDemo(module);
}
finally
{
module.Unload();
}
Console.WriteLine("Done.");
return 0;
}
}
}