C# 在AudioFileInputNode完成播放后,自定义音频效果如何产生一些声音

C# 在AudioFileInputNode完成播放后,自定义音频效果如何产生一些声音,c#,audio,uwp,signal-processing,C#,Audio,Uwp,Signal Processing,我正在使用AudiographAPI开发C#和UWP中的音频应用程序。 我的听力图设置如下所示: AudioFileInputNode-->AudioSubmixNode-->AudioDeviceOutputNode 我在AudioSubmixNode上附加了一个自定义回声效果。 如果我播放AudioFileInputNode,我可以听到一些回声。 但是,当AudioFileInputNode播放结束时,回声会突然停止。 我希望它在几秒钟后逐渐停止。 如果我使用AudioGraph API中的

我正在使用AudiographAPI开发C#和UWP中的音频应用程序。 我的听力图设置如下所示: AudioFileInputNode-->AudioSubmixNode-->AudioDeviceOutputNode

我在AudioSubmixNode上附加了一个自定义回声效果。 如果我播放AudioFileInputNode,我可以听到一些回声。 但是,当AudioFileInputNode播放结束时,回声会突然停止。 我希望它在几秒钟后逐渐停止。 如果我使用AudioGraph API中的EchoffectDefinition,则在样本播放完成后,回声不会停止

我不知道问题是来自于我的效果实现,还是听力学API的奇怪行为。。。 该行为与SDK场景6中的“AudioCreation”示例中的行为相同

以下是我的自定义效果实现:

public sealed class AudioEchoEffect : IBasicAudioEffect
{
    public AudioEchoEffect()
    {
    }

    private readonly AudioEncodingProperties[] _supportedEncodingProperties = new AudioEncodingProperties[]
    {
        AudioEncodingProperties.CreatePcm(44100, 1, 32),
        AudioEncodingProperties.CreatePcm(48000, 1, 32),
    };

    private AudioEncodingProperties _currentEncodingProperties;
    private IPropertySet _propertySet;

    private readonly Queue<float> _echoBuffer = new Queue<float>(100000);
    private int _delaySamplesCount;

    private float Delay
    {
        get
        {
            if (_propertySet != null && _propertySet.TryGetValue("Delay", out object val))
            {
                return (float)val;
            }
            return 500.0f;
        }
    }

    private float Feedback
    {
        get
        {
            if (_propertySet != null && _propertySet.TryGetValue("Feedback", out object val))
            {
                return (float)val;
            }
            return 0.5f;
        }
    }

    private float Mix
    {
        get
        {
            if (_propertySet != null && _propertySet.TryGetValue("Mix", out object val))
            {
                return (float)val;
            }
            return 0.5f;
        }
    }

    public bool UseInputFrameForOutput { get { return true; } }

    public IReadOnlyList<AudioEncodingProperties> SupportedEncodingProperties { get { return _supportedEncodingProperties; } }

    public void SetProperties(IPropertySet configuration)
    {
        _propertySet = configuration;
    }

    public void SetEncodingProperties(AudioEncodingProperties encodingProperties)
    {
        _currentEncodingProperties = encodingProperties;

        // compute the number of samples for the delay
        _delaySamplesCount = (int)MathF.Round((this.Delay / 1000.0f) * encodingProperties.SampleRate);

        // fill empty samples in the buffer according to the delay
        for (int i = 0; i < _delaySamplesCount; i++)
        {
            _echoBuffer.Enqueue(0.0f);
        }
    }

    unsafe public void ProcessFrame(ProcessAudioFrameContext context)
    {
        AudioFrame frame = context.InputFrame;

        using (AudioBuffer buffer = frame.LockBuffer(AudioBufferAccessMode.ReadWrite))
        using (IMemoryBufferReference reference = buffer.CreateReference())
        {
            ((IMemoryBufferByteAccess)reference).GetBuffer(out byte* dataInBytes, out uint capacity);
            float* dataInFloat = (float*)dataInBytes;
            int dataInFloatLength = (int)buffer.Length / sizeof(float);

            // read parameters once
            float currentWet = this.Mix;
            float currentDry = 1.0f - currentWet;
            float currentFeedback = this.Feedback;

            // Process audio data
            float sample, echoSample, outSample;
            for (int i = 0; i < dataInFloatLength; i++)
            {
                // read values
                sample = dataInFloat[i];
                echoSample = _echoBuffer.Dequeue();

                // compute output sample
                outSample = (currentDry * sample) + (currentWet * echoSample);
                dataInFloat[i] = outSample;

                // compute delay sample
                echoSample = sample + (currentFeedback * echoSample);
                _echoBuffer.Enqueue(echoSample);
            }
        }
    }

    public void Close(MediaEffectClosedReason reason)
    {
    }

    public void DiscardQueuedFrames()
    {
        // reset the delay buffer
        _echoBuffer.Clear();
        for (int i = 0; i < _delaySamplesCount; i++)
        {
            _echoBuffer.Enqueue(0.0f);
        }
    }
}
公共密封类音频回声效果:IBasicAudioEffect
{
公共音频回声效应()
{
}
私有只读AudioEncodingProperties[]\u supportedEncodingProperties=新AudioEncodingProperties[]
{
CreatePcm(44100,1,32),
CreatePcm(48000,1,32),
};
私有AudioEncodingProperties _currentEncodingProperties;
私人IPropertySet_propertySet;
私有只读队列_echoBuffer=新队列(100000);
私人int_delaySamplesCount;
专用浮点延迟
{
收到
{
if(_propertySet!=null&&u propertySet.TryGetValue(“延迟”,out object val))
{
返回(浮动)值;
}
返回500.0f;
}
}
私有浮动反馈
{
收到
{
if(_propertySet!=null&&u propertySet.TryGetValue(“反馈”,out object val))
{
返回(浮动)值;
}
返回0.5f;
}
}
私人浮动组合
{
收到
{
if(_propertySet!=null&&u propertySet.TryGetValue(“Mix”,out object val))
{
返回(浮动)值;
}
返回0.5f;
}
}
public bool UseInputFrameForOutput{get{return true;}}
公共IReadOnlyList


所以我的问题是:在播放结束后,内置的EchoffectDefinition如何输出一些声音?访问EchoffectDefinition源代码将是一个很大的帮助…

通过无限循环文件输入节点,它将始终提供输入帧,直到音频图停止。但我们当然不想听到声音文件循环,因此我们可以侦听AudioFileInputNode的FileCompleted事件。当文件播放结束时,它将触发该事件,我们只需要将AudioFileInputNode的OutgoingGain设置为零。因此,文件播放一次,但它会继续以静默方式循环通过没有音频内容的输入帧,以便添加回声。

仍然使用AudioCreation示例中的场景4作为示例。在场景4中,有一个名为fileInputNode1的属性。如上所述,请在fileInputNode1中添加以下代码,并使用自定义回显效果再次测试

fileInputNode1.LoopCount = null; //Null makes it loop infinitely
fileInputNode1.FileCompleted += FileInputNode1_FileCompleted;          

private void FileInputNode1_FileCompleted(AudioFileInputNode sender, object args)
{
    fileInputNode1.OutgoingGain = 0.0;
}

我在“音频创作”中使用了代码示例,场景4,其中包含AudioSubmixNode并在其AudioSubmixNode上添加了自定义回声效果,当AudioFileInputNode播放完成后,回声可能会在几秒钟后逐渐停止。您的意思是当您将其与回声效果一起使用时,回声会立即停止吗?您可以尝试将延迟值返回为1000.0f在您的自定义回声效果中,回声延迟会更明显,您可以检查它。感谢您回答@Faywang MSFT。我在场景4中尝试了我的自定义音频效果,问题是相同的。尝试加载一个非常短的示例(例如鼓声)。如果样本长度为1.5秒,延迟为0.5秒,则我只能听到2个回声。当样本播放完成时,我的自定义效果的输出声音似乎被无情地切断…它应该继续并逐渐减小(内置回声会这样做)。我还尝试用Audacity录制扬声器输出,当我观看声音曲线时,很明显我的回声在示例播放结束时被切断。谢谢,我没有使用循环的想法。这肯定会起作用!但在我的实际应用中,我想我会使用AudioFrameInputNode,它会在s中生成一些空帧因为我已经使用循环来实现其他目的……我仍然认为这是一个黑客行为。我们应该有一个Ibasic音频效果的属性来控制这个行为…