我已经用SharpDX.XAudio2玩了几天了,虽然事情基本上是积极的(奇怪的软件怪癖(,但以下问题让我完全陷入了困境:
我正在使用VS2015在C#.NET中工作。
我正在尝试同时播放多个声音。
为此,我制作了:
-Test.cs:Contains main method
-cSoundEngine.cs:Holds XAudio2、MasteringVoice和声音管理方法
-VoiceChannel.cs:保存SourceVoice,以及将来的任何sfx/相关数据。
cSoundEngine:
List<VoiceChannel> sourceVoices;
XAudio2 engine;
MasteringVoice master;
public cSoundEngine()
{
engine = new XAudio2();
master = new MasteringVoice(engine);
sourceVoices = new List<VoiceChannel>();
}
public VoiceChannel AddAndPlaySFX(string filepath, double vol, float pan)
{
/**
* Set up and start SourceVoice
*/
NativeFileStream fileStream = new NativeFileStream(filepath, NativeFileMode.Open, NativeFileAccess.Read);
SoundStream soundStream = new SoundStream(fileStream);
SourceVoice source = new SourceVoice(engine, soundStream.Format);
AudioBuffer audioBuffer = new AudioBuffer()
{
Stream = soundStream.ToDataStream(),
AudioBytes = (int)soundStream.Length,
Flags = SharpDX.XAudio2.BufferFlags.EndOfStream
};
//Make voice wrapper
VoiceChannel voice = new VoiceChannel(source);
sourceVoices.Add(voice);
//Volume
source.SetVolume((float)vol);
//Play sound
source.SubmitSourceBuffer(audioBuffer, soundStream.DecodedPacketsInfo);
source.Start();
return voice;
}
测试.cs:
cSoundEngine engine = new cSoundEngine();
total = 6;
for (int i = 0; i < total; i++)
{
string filepath = System.IO.Directory.GetParent(System.IO.Directory.GetCurrentDirectory()).Parent.FullName + @"AssetsPlanet.wav";
VoiceChannel sfx = engine.AddAndPlaySFX(filepath, 0.1, 0);
}
Console.Read(); //Input anything to end play.
VoiceChannel.cs中目前没有任何值得显示的内容——它包含"SourceVoice source",这是构造函数中发送的一个参数!
一切都很好,运行良好,最多有5个声音(总数=5(。你所听到的只是Planet.wav的幸福嗡嗡声。然而,任何高于5的声音都会导致控制台冻结约5秒,然后关闭(可能是调试器无法处理的c++错误(。遗憾的是,我们没有看到任何错误信息
来自测试:
-只要运行的源语音不超过5个,就不会崩溃
-改变采样率似乎没有帮助
-将主对象的inputChannels设置为不同的数字没有区别
-MasteringVoice似乎说输入语音的最大数量是64。
-让每个sfx从不同的wav文件播放没有什么区别
-设置sourcevoices和/或master的音量没有区别。
从XAudio2 API文档中,我找到了这样一句话:XAudio2取消了多声道声音的6声道限制,并支持任何多声道音频卡上的多声道音频。该卡不需要硬件加速。这是我发现的最接近提到这个问题的东西。
我对sfx编程没有很好的经验,很多这对我来说都是全新的,所以在适当的时候可以随意称我为白痴,但请尝试用外行的语言解释。
如果你有任何想法或答案,我们将不胜感激
-Josh
正如Chuck所建议的,我创建了一个保存.wav数据的数据库,我只引用每个缓冲区的单个数据存储。这将声音限制提高到了20,但这并没有解决整个问题,可能是因为我没有正确地实现这一点。实施:
class SoundDataBank
{
/**
* Holds a single byte array for each sound
*/
Dictionary<eSFX, Byte[]> bank;
string curdir => Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
public SoundDataBank()
{
bank = new Dictionary<eSFX, byte[]>();
bank.Add(eSFX.planet, NativeFile.ReadAllBytes(curdir + @"AssetsPlanet.wav"));
bank.Add(eSFX.base1, NativeFile.ReadAllBytes(curdir + @"AssetsBase.wav"));
}
public Byte[] GetSoundData(eSFX sfx)
{
byte[] output = bank[sfx];
return output;
}
}
在SoundEngine中,我们创建了一个SoundBank对象(在SoundEngineconstructor中初始化(:
SoundDataBank soundBank;
public VoiceChannel AddAndPlaySFXFromStore(eSFX sfx, double vol)
{
/**
* sourcevoice will be automatically added to MasteringVoice and engine in the constructor.
*/
byte[] buffer = soundBank.GetSoundData(sfx);
MemoryStream memoryStream = new MemoryStream(buffer);
SoundStream soundStream = new SoundStream(memoryStream);
SourceVoice source = new SourceVoice(engine, soundStream.Format);
AudioBuffer audioBuffer = new AudioBuffer()
{
Stream = soundStream.ToDataStream(),
AudioBytes = (int)soundStream.Length,
Flags = SharpDX.XAudio2.BufferFlags.EndOfStream
};
//Make voice wrapper
VoiceChannel voice = new VoiceChannel(source, engine, MakeOutputMatrix());
//Volume
source.SetVolume((float)vol);
//Play sound
source.SubmitSourceBuffer(audioBuffer, soundStream.DecodedPacketsInfo);
source.Start();
sourceVoices.Add(voice);
return voice;
}
根据这个实现,现在我可以播放多达20个音效,但这并不是因为我们是从声音库中播放的。事实上,即使运行旧的音效方法,现在也可以获得多达20个sfx实例。
由于我们在SoundBank的构造函数中完成了NativeFile.ReadAllBytes(curdir+@"\Assets\Base.wav"(,这一点已经提高到了20。
我怀疑NativeFile保存了一个加载的文件数据存储区,所以无论你运行的是原始的SoundEngine.AddAndPlaySFX((还是SoundEngine.addAndPlaySF FromStore((,它们都是从内存中运行的?
不管怎样,这比以前的限制增加了两倍,所以这非常有用,但还需要进一步的工作。