SharpDX XAudio2: 6 SourceVoice предел
Я играю с SharpDX.XAudio2 уже несколько дней, и хотя в целом все было положительно (странные программные чудеса здесь и там), я полностью застрял в следующей проблеме:
Я работаю в C# .NET, используя VS2015.
Я пытаюсь играть несколько звуков одновременно.
Для этого я сделал:
- Test.cs: содержит основной метод
- cSoundEngine.cs: содержит 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;
}
Test.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 + @"\Assets\Planet.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 не имеет значения.
- Установка громкости для исходных голосов и / или мастера не имеет значения.
Из документации API XAudio2 я нашел следующую цитату: "XAudio2 снимает 6-канальное ограничение на многоканальные звуки и поддерживает многоканальный звук на любой многоканальной звуковой плате. Карта не нуждается в аппаратном ускорении., Это самое близкое к тому, что я нашел, чтобы упомянуть эту проблему.
Я не очень хорошо разбираюсь в программировании на sfx, и многое из этого является для меня совсем новым, поэтому не стесняйтесь называть меня идиотом, когда это уместно, но, пожалуйста, попробуйте объяснить это с точки зрения неспециалистов.
Пожалуйста, если у вас есть идеи или ответы, они будут очень благодарны!
-Josh
1 ответ
Как предложил Чак, я создал банк данных, в котором хранятся данные.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 + @"\Assets\Planet.wav"));
bank.Add(eSFX.base1, NativeFile.ReadAllBytes(curdir + @"\Assets\Base.wav"));
}
public Byte[] GetSoundData(eSFX sfx)
{
byte[] output = bank[sfx];
return output;
}
}
В SoundEngine мы создаем объект SoundBank (инициализируется в конструкторе SoundEngine):
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.
Это улучшилось до 20, потому что мы сделали NativeFile.ReadAllBytes(curdir + @"\Assets\Base.wav") в конструкторе для SoundBank.
Я подозреваю, что NativeFile содержит хранилище данных загруженных файлов, поэтому вы независимо от того, запускаете ли вы оригинальный SoundEngine.AddAndPlaySFX() или SoundEngine.AddAndPlaySFXFromStore(), они оба запускаются из памяти?
В любом случае, этот предел увеличился в четыре раза, так что это было невероятно полезно, но требует дальнейшей работы.