Как реализовать многоканальный звуковой предварительный микшер в .net
Вопрос
Я хотел бы использовать C # для реализации приложения, которое может воспроизводить несколько аудиопотоков одновременно. Арахис - теперь интересная часть: предполагая, что каждый поток одноканальный (моно), я хочу отрегулировать громкость для каждого динамика (5.1 или даже 7.1) для каждого потока отдельно. Я могу использовать микшер Windows, чтобы сделать это, но проблема в том, что есть только один микшер, и я хочу настроить это для каждого потока отдельно. Есть идеи, как это реализовать?
Моим первым предположением было мультиплексирование потока восемь раз (7.1), применение уровня громкости для каждого " канала " и затем отправьте его в микшер Windows, который выравнивается для всех каналов, например, на 80%. Знаете ли вы какие-либо библиотеки, которые могли бы поддерживать такой вариант использования? Р>
AFAIK bass и fmod не могут этого сделать, но поправьте меня, если я ошибаюсь. В качестве альтернативы я подумал о том, чтобы взломать XNA для этого: использовать вектор, который описывает положение потока, относящегося к слушателю, и использовать его для применения компенсации громкости ... просто шум.
(и, пожалуйста, не указывайте мне некоторые идеи C ++ / WinAPI по этому вопросу, этот проект не стоит изучать другой язык сейчас.)
Решение
Наконец-то все получилось: bass.dll позволяет применять матрицу в качестве настроек громкости для каждого динамика отдельно, используя метод BassMix.BASS_Mixer_ChannelSetMatrix (int streamHandle, float [,] volumeMatrix)
. Вы можете посмотреть образец здесь , они используют его для микшировать стереопоток до четырех колонок. Ниже полный класс, который я создал, чтобы решить мою проблему.
public class SeparateVolumeLevelPlayer : IDisposable
{
private readonly int outputMixerStream;
private readonly int inputStream;
private readonly int numberOfSpeakers;
public SeparateVolumeLevelPlayer(string fileName, int numberOfSpeakers)
{
this.numberOfSpeakers = numberOfSpeakers;
outputMixerStream = BassMix.BASS_Mixer_StreamCreate(44100, numberOfSpeakers, BASSFlag.BASS_MIXER_MATRIX);
ThrowOnError();
// create a stream from the media file
inputStream = Bass.BASS_StreamCreateFile(fileName, 0L, 0L, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_MATRIX | BASSFlag.BASS_SAMPLE_MONO);
ThrowOnError();
// add the stream to the mixer
BassMix.BASS_Mixer_StreamAddChannel(outputMixerStream, inputStream, BASSFlag.BASS_MIXER_MATRIX);
ThrowOnError();
}
public void Play()
{
// start playback of the mixed streams
Bass.BASS_ChannelPlay(outputMixerStream, false);
ThrowOnError();
}
public void SetVolume(float[] volumeValues)
{
if (volumeValues == null)
{
throw new ArgumentNullException("volumeValues");
}
if (volumeValues.Length != numberOfSpeakers)
{
string message =
string.Format("You must pass a volume level for every speaker. You provided {0} values for {1} speakers",
volumeValues.Length, numberOfSpeakers);
throw new ArgumentException(message);
}
var volumeMatrix = new float[numberOfSpeakers, 1];
for (int i = 0; i < numberOfSpeakers; i++)
{
volumeMatrix[i, 0] = volumeValues[i];
}
// adjust the volume using the matrix
BassMix.BASS_Mixer_ChannelSetMatrix(inputStream, volumeMatrix);
ThrowOnError();
}
private static void ThrowOnError()
{
BASSError err = Bass.BASS_ErrorGetCode();
if (err != BASSError.BASS_OK)
{
throw new ApplicationException(string.Format("bass.dll reported {0}.", err));
}
}
public void Dispose()
{
Bass.BASS_StreamFree(inputStream);
Bass.BASS_StreamFree(outputMixerStream);
}
}