【问题标题】:How to realize a multi channel audio pre-mixer in .net如何在.net中实现多声道音频预混器
【发布时间】:2010-12-10 03:30:31
【问题描述】:

我想使用 C# 来实现一个可以同时播放多个音频流的应用程序。花生 - 现在有趣的部分:假设每个流都是单声道(单声道)我想分别为每个流调整每个扬声器(5.1 甚至 7.1)的音量。我可以使用 windows 混音器来做到这一点,但问题是,只有一个混音器,我想分别为每个流调整它。有什么想法可以实现吗?

我的第一个猜测是将流多路复用 8 次 (7.1),为每个“通道”应用音量级别,然后将其发送到 windows 混音器,例如,所有通道的电平为 80%。您知道任何可能支持此类用例的库吗?

AFAIK bass 和 fmod 无法做到这一点,但如果我错了,请纠正我。作为替代方案,我正在考虑为此破解 XNA:使用描述与听者相关的流位置的向量并使用它来应用音量补偿......只是漫无边际。

(请不要在这方面向我指出一些 C++/WinAPI 的想法,这个项目现在不值得学习另一种语言。)

【问题讨论】:

  • 我脑子里突然冒出一个想法:要求将可用的声音文件导入并最初转码到某种声音库中是完全可以的。 vorbis 格式最多支持 255 个通道,并且有一个(可能已废弃)可用的库:vorbisdotnet.sourceforge.net
  • 有点颠簸:我在 Codeplex 上找到了 NAudio 库。好东西……

标签: .net audio mixer bass.dll


【解决方案1】:

终于明白了:bass.dll 允许使用BassMix.BASS_Mixer_ChannelSetMatrix(int streamHandle, float[,] volumeMatrix) 方法分别为每个扬声器应用一个矩阵作为音量设置。你可以看到一个示例here,他们正在使用它来将立体声流上混到四个扬声器。在我为解决问题而创建的完整课程下方。

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);
    }
}

【讨论】:

    猜你喜欢
    • 2011-08-31
    • 2011-03-28
    • 2014-11-03
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 2016-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多