自定义音频效果如何在 AudioFileInputNode 播放完毕后产生一些声音
How can a custom audio effect produce some sound after a AudioFileInputNode has finished playing
我正在使用 AudioGraph API 在 C# 和 UWP 中开发音频应用程序。
我的 AudioGraph 设置如下:
AudioFileInputNode --> AudioSubmixNode --> AudioDeviceOutputNode.
我在 AudioSubmixNode 上附加了自定义回声效果。
如果我播放 AudioFileInputNode,我可以听到一些回声。
但是当AudioFileInputNode播放结束后,回声就粗暴的停止了。
我希望它在几秒钟后逐渐停止。
如果我使用 AudioGraph 中的 EchoEffectDefinition API,回声不会在样本播放完成后停止。
我不知道问题是出在我的效果实现上还是 AudioGraph 的异常行为API...
该行为与 SDK 中的 "AudioCreation" 示例场景 6 中的行为相同。
这是我的自定义效果实现:
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);
}
}
}
编辑:
我更改了音频效果以将输入样本与正弦波混合。 ProcessFrame 效果方法在样本播放前后连续运行(当效果处于活动状态时)。所以正弦波应该在样本播放前后听到。但是 AudioGraph API 似乎在没有活动播放时忽略了效果输出...
这是音频输出的屏幕截图:
所以我的问题是:内置的EchoEffectDefinition如何在播放结束后输出一些声音?访问 EchoEffectDefinition 源代码将有很大帮助...
通过无限循环文件输入节点,它会一直提供一个输入帧,直到音频图停止。但是我们当然不想听到文件循环,所以我们可以监听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;
}
我正在使用 AudioGraph API 在 C# 和 UWP 中开发音频应用程序。 我的 AudioGraph 设置如下: AudioFileInputNode --> AudioSubmixNode --> AudioDeviceOutputNode.
我在 AudioSubmixNode 上附加了自定义回声效果。 如果我播放 AudioFileInputNode,我可以听到一些回声。 但是当AudioFileInputNode播放结束后,回声就粗暴的停止了。 我希望它在几秒钟后逐渐停止。 如果我使用 AudioGraph 中的 EchoEffectDefinition API,回声不会在样本播放完成后停止。
我不知道问题是出在我的效果实现上还是 AudioGraph 的异常行为API... 该行为与 SDK 中的 "AudioCreation" 示例场景 6 中的行为相同。
这是我的自定义效果实现:
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);
}
}
}
编辑: 我更改了音频效果以将输入样本与正弦波混合。 ProcessFrame 效果方法在样本播放前后连续运行(当效果处于活动状态时)。所以正弦波应该在样本播放前后听到。但是 AudioGraph API 似乎在没有活动播放时忽略了效果输出...
这是音频输出的屏幕截图:
所以我的问题是:内置的EchoEffectDefinition如何在播放结束后输出一些声音?访问 EchoEffectDefinition 源代码将有很大帮助...
通过无限循环文件输入节点,它会一直提供一个输入帧,直到音频图停止。但是我们当然不想听到文件循环,所以我们可以监听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;
}