Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se describe cómo crear un componente de Windows Runtime que implemente la interfaz IBasicAudioEffect para crear efectos personalizados para secuencias de audio. Puede usar efectos personalizados con AudioGraph, MediaCapture y MediaComposition.
Note
La interfaz IBasicAudioEffect es una API de Windows Runtime del espacio de nombres Windows.Media.Effects. Estas API funcionan de la misma manera en las aplicaciones de escritorio de WinUI 3 que en UWP. La principal diferencia es la forma de configurar el proyecto y hacer referencia al componente de efecto.
Agregue un componente de Windows Runtime para su efecto de audio
En Visual Studio, agregue un proyecto de componente de Windows Runtime (C#) a la solución winUI 3:
- Haga clic con el botón derecho en la solución en Explorador de soluciones y seleccione Agregar>nuevo Project.
- Seleccione la plantilla de proyecto componente de Windows Runtime.
- Asigne al proyecto el nombre AudioEffectComponent.
- Agregue una referencia de proyecto desde la aplicación winUI 3 principal a este proyecto de componente.
- Cambie el nombre del archivo de clase predeterminado a ExampleAudioEffect.cs.
Implementación de la interfaz IBasicAudioEffect
El efecto de audio debe implementar todos los métodos y propiedades de la interfaz IBasicAudioEffect .
using System.Collections.Generic;
using Windows.Media;
using Windows.Media.Effects;
using Windows.Media.MediaProperties;
using Windows.Foundation.Collections;
namespace AudioEffectComponent;
public sealed class ExampleAudioEffect : IBasicAudioEffect
{
private AudioEncodingProperties _currentEncodingProperties;
private IPropertySet _propertySet;
private float _echoDelay = 0.5f; // delay in seconds
private float _echoMix = 0.5f; // mix level (0-1)
public bool UseInputFrameForOutput => true;
public IReadOnlyList<AudioEncodingProperties> SupportedEncodingProperties
{
get
{
var supportedProperties = new List<AudioEncodingProperties>();
AudioEncodingProperties encodingProps1 =
AudioEncodingProperties.CreatePcm(44100, 1, 32);
encodingProps1.Subtype = MediaEncodingSubtypes.Float;
supportedProperties.Add(encodingProps1);
AudioEncodingProperties encodingProps2 =
AudioEncodingProperties.CreatePcm(48000, 1, 32);
encodingProps2.Subtype = MediaEncodingSubtypes.Float;
supportedProperties.Add(encodingProps2);
return supportedProperties;
}
}
public void SetEncodingProperties(
AudioEncodingProperties encodingProperties)
{
_currentEncodingProperties = encodingProperties;
}
public void SetProperties(IPropertySet configuration)
{
_propertySet = configuration;
// Read custom properties if provided
if (configuration != null &&
configuration.TryGetValue("EchoDelay", out object delay))
{
_echoDelay = (float)delay;
}
if (configuration != null &&
configuration.TryGetValue("EchoMix", out object mix))
{
_echoMix = (float)mix;
}
}
public void ProcessFrame(ProcessAudioFrameContext context)
{
// Audio processing logic goes here.
// See the echo effect example below.
}
public void Close(MediaEffectClosedReason reason)
{
// Clean up resources
}
public void DiscardQueuedFrames()
{
// Discard any cached frames
}
}
Crear un efecto de eco
En el ejemplo siguiente se muestra una ProcessFrame implementación que crea un efecto de eco. El efecto almacena los datos de audio anteriores en un búfer y los mezcla con los datos de audio actuales después de un retraso configurable.
Para acceder al búfer de audio sin procesar, necesitas la interfaz COM IMemoryBufferByteAccess. Añada la siguiente definición en su espacio de nombres de efectos:
using System.Runtime.InteropServices;
[ComImport]
[System.Runtime.InteropServices.Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
void GetBuffer(out byte* buffer, out uint capacity);
}
Importante
Esta técnica accede a un búfer de audio nativo y no administrado. Debe agregar <AllowUnsafeBlocks>true</AllowUnsafeBlocks> al archivo .csproj de su proyecto para habilitar el código no seguro.
private float[] _echoBuffer;
private int _echoBufferPosition;
private float _echoDelay = 0.5f; // delay in seconds
private float _echoMix = 0.5f; // mix level (0-1)
private Windows.Media.MediaProperties.AudioEncodingProperties _currentEncodingProperties;
public unsafe void ProcessFrame(ProcessAudioFrameContext context)
{
AudioFrame inputFrame = context.InputFrame;
using (AudioBuffer inputBuffer =
inputFrame.LockBuffer(AudioBufferAccessMode.ReadWrite))
using (IMemoryBufferReference inputReference =
inputBuffer.CreateReference())
{
byte* dataInBytes;
uint capacityInBytes;
((IMemoryBufferByteAccess)inputReference).GetBuffer(
out dataInBytes, out capacityInBytes);
float* dataInFloat = (float*)dataInBytes;
int dataInFloatLength =
(int)capacityInBytes / sizeof(float);
// Initialize echo buffer on first call
if (_echoBuffer == null)
{
int delaySamples = (int)(
_currentEncodingProperties.SampleRate * _echoDelay);
_echoBuffer = new float[delaySamples];
}
for (int i = 0; i < dataInFloatLength; i++)
{
float input = dataInFloat[i];
float echo = _echoBuffer[_echoBufferPosition];
// Mix the original signal with the echo
dataInFloat[i] = input + (echo * _echoMix);
// Store the current sample in the echo buffer
_echoBuffer[_echoBufferPosition] = input;
_echoBufferPosition =
(_echoBufferPosition + 1) % _echoBuffer.Length;
}
}
}
Añadir el efecto a un grafo de audio
Para usar el efecto personalizado con un AudioGraph, cree una instancia de la definición del efecto y agréguelo a un nodo:
using Windows.Media.Audio;
using Windows.Media.Effects;
var effectDefinition = new AudioEffectDefinition(
typeof(AudioEffectComponent.ExampleAudioEffect).FullName);
audioFileInputNode.EffectDefinitions.Add(effectDefinition);
Pasar la configuración al efecto
Puede pasar valores de configuración al efecto mediante un PropertySet:
var properties = new PropertySet();
properties["EchoDelay"] = 0.3f;
properties["EchoMix"] = 0.6f;
var effectDefinition = new AudioEffectDefinition(
typeof(AudioEffectComponent.ExampleAudioEffect).FullName,
properties);
En el método SetProperties de su efecto (mostrado anteriormente), lea estos valores del conjunto de propiedades para configurar el efecto en tiempo de ejecución.
Agregar el efecto a MediaCapture
También puede agregar el efecto de audio personalizado a una secuencia de audio MediaCapture :
var effectDefinition = new AudioEffectDefinition(
typeof(AudioEffectComponent.ExampleAudioEffect).FullName);
await _mediaCapture.AddAudioEffectAsync(effectDefinition);