NAudio:正确使用MixingSampleProvider和VolumeSampleProvider

时间:2016-06-11 16:54:20

标签: c# naudio

我一直在使用NAudio "用NAudio"消防和忘记音频播放教程(谢谢你标记这个很棒的实用工具!),如下所示: http://mark-dot-net.blogspot.nl/2014/02/fire-and-forget-audio-playback-with.html

我设法使用MixingSampleProvider作为输入添加了VolumeSampleProvider。然而,当我现在一个接一个地播放两个声音时,第一个声音总是得到第二个声音的音量,即使第一个声音已经播放了。

所以我的问题是:如何在每个声音中添加单个音量的声音?

这就是我使用的:

        mixer = new MixingSampleProvider(waveformat);
        mixer.ReadFully = true;
        volumeProvider = new VolumeSampleProvider(mixer);
        panProvider = new PanningSampleProvider(volumeProvider);
        outputDevice.Init(panProvider);
        outputDevice.Play();

2 个答案:

答案 0 :(得分:1)

我并不是100%肯定你在问什么,我不知道你是否已经解决了这个问题,但我在这里采取了这个措施。

ISampleProvider个对象播放"传递降压"通过ISampleProvider方法将游戏发送到他们的来源Read()。最终,有人会对音频字节进行实际读取。各个ISampleProvider类对字节执行任何操作。

例如,

MixingSampleProvider需要N个音频源......那些混合在一起。调用Read()时,它会迭代音频源并从每个源中读取count个字节。

将其传递给VolumeSampleProvider作为一个组来处理所有字节(来自各种来源)...它说:

buffer[offset+n] *= volume;

这将调整整个电路板的字节...所以每个字节都由volume乘数在缓冲区中调整;

PanningSampleProvider只是提供立体声音频的倍增器并相应地调整字节,与VolumeSampleProvider做同样的事情。

如果要单独处理音频源卷,则需要处理MixingSampleProvider的上游。基本上,传递给MixingSampleProvider的东西需要能够独立调整其音量。

如果您将一堆SampleChannel个对象传递给MixingSampleProvider ...您可以完成独立的音量调整。 Samplechannel类包含VolumeSampleProvider对象,并提供Volume属性,允许用户在VolumeSampleProvider对象上设置音量。

SampleChannel还包含一个MeteringSampleProvider,用于提供给定时间段内最大样本值的报告。它会引发一个事件,为您提供这些值的数组,每个通道一个。

答案 1 :(得分:0)

我意识到(感谢其匹配)使这项工作的唯一方法是在将混合器添加到混合器之前,单独留下混合器并单独调整每个CachedSound的平移和音量。因此,我需要使用pan和volume作为额外的输入参数来重写CachedSoundSampleProvider。

这是新的构造函数:

    public CachedSoundSampleProvider(CachedSound cachedSound, float volume = 1, float pan = 0)
    {
        this.cachedSound = cachedSound;
        LeftVolume = volume * (0.5f - pan / 2);
        RightVolume = volume * (0.5f + pan / 2);
    }

这是新的Read()函数:

    public int Read(float[] buffer, int offset, int count)
    {
        long availableSamples = cachedSound.AudioData.Length - position;
        long samplesToCopy = Math.Min(availableSamples, count);

        int destOffset = offset;
        for (int sourceSample = 0; sourceSample < samplesToCopy; sourceSample += 2)
        {
            float outL = cachedSound.AudioData[position + sourceSample + 0];
            float outR = cachedSound.AudioData[position + sourceSample + 1];

            buffer[destOffset + 0] = outL * LeftVolume;
            buffer[destOffset + 1] = outR * RightVolume;
            destOffset += 2;
        }

        position += samplesToCopy;
        return (int)samplesToCopy;
    }