Как реализовать многоканальный звуковой предварительный микшер в .net - PullRequest
3 голосов
/ 26 октября 2009

Я хотел бы использовать C # для реализации приложения, которое может воспроизводить несколько аудиопотоков одновременно. Арахис - теперь интересная часть: предполагая, что каждый поток одноканальный (моно), я хочу отрегулировать громкость для каждого динамика (5.1 или даже 7.1) для каждого потока отдельно. Я могу использовать микшер Windows, чтобы сделать это, но проблема в том, что есть только один микшер, и я хочу настроить это для каждого потока отдельно. Есть идеи, как это реализовать?

Моим первым предположением было мультиплексирование потока восемь раз (7.1), применение уровня громкости для каждого «канала», а затем отправка его на микшер Windows, который, например, выравнивается для всех каналов на уровне 80%. Знаете ли вы какие-либо библиотеки, которые могли бы поддерживать такой вариант использования?

AFAIK bass и fmod не могут этого сделать, но поправьте меня, если я ошибаюсь. В качестве альтернативы я подумал о том, чтобы взломать XNA для этого: использовать вектор, который описывает положение потока, относящегося к слушателю, и использовать его для применения компенсации громкости ... просто шум.

(и, пожалуйста, не указывайте мне некоторые идеи C ++ / WinAPI по этому вопросу, этот проект не стоит изучать другой язык сейчас.)

1 Ответ

1 голос
/ 31 октября 2009

Наконец-то все получилось: 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);
    }
}
...