Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym artykule opisano sposób tworzenia składnika środowisko wykonawcze systemu Windows implementującego interfejs IBasicAudioEffect w celu utworzenia niestandardowych efektów dla strumieni audio. Możesz używać efektów niestandardowych z audiograph, MediaCapture i MediaComposition.
Note
Interfejs IBasicAudioEffect jest interfejsem API środowiska środowisko wykonawcze systemu Windows w przestrzeni nazw Windows.Media.Effects. Te interfejsy API działają tak samo w aplikacjach klasycznych WinUI 3, jak w systemie UWP. Główna różnica polega na tym, jak skonfigurować projekt i odwołać się do składnika efektu.
Dodaj składnik środowisko wykonawcze systemu Windows dla efektu audio
W Visual Studio dodaj projekt składnika środowisko wykonawcze systemu Windows (C#) do rozwiązania WinUI 3:
- Kliknij rozwiązanie prawym przyciskiem myszy w Eksplorator rozwiązań i wybierz pozycję Dodaj>nowy Project.
- Wybierz szablon projektu Składnik środowiska uruchomieniowego systemu Windows.
- Nadaj projektowi nazwę AudioEffectComponent.
- Dodaj odwołanie do projektu z głównej aplikacji WinUI 3 do tego projektu składnika.
- Zmień nazwę domyślnego pliku klasy na ExampleAudioEffect.cs.
Implementowanie interfejsu IBasicAudioEffect
Efekt dźwiękowy musi implementować wszystkie metody i właściwości interfejsu 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
}
}
Tworzenie efektu echa
W poniższym przykładzie pokazano implementację ProcessFrame , która tworzy efekt echa. Efekt przechowuje poprzednie dane audio w buforze i miesza je z bieżącymi danymi audio po konfigurowalnym opóźnieniu.
Aby uzyskać dostęp do nieprzetworzonego buforu audio, potrzebny jest interfejs IMemoryBufferByteAccess COM. Dodaj następującą definicję w przestrzeni nazw efektu:
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);
}
Ważna
Ta technika uzyskuje dostęp do natywnego, niezarządzanego buforu audio. Aby włączyć niebezpieczny kod, musisz dodać <AllowUnsafeBlocks>true</AllowUnsafeBlocks> do pliku .csproj projektu.
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;
}
}
}
Dodawanie efektu do grafu audio
Aby użyć efektu niestandardowego z elementem AudioGraph, utwórz instancję definicji efektu i dodaj ją do węzła:
using Windows.Media.Audio;
using Windows.Media.Effects;
var effectDefinition = new AudioEffectDefinition(
typeof(AudioEffectComponent.ExampleAudioEffect).FullName);
audioFileInputNode.EffectDefinitions.Add(effectDefinition);
Przekazywanie konfiguracji do efektu
Wartości konfiguracji można przekazać do swojego efektu przy użyciu elementu PropertySet:
var properties = new PropertySet();
properties["EchoDelay"] = 0.3f;
properties["EchoMix"] = 0.6f;
var effectDefinition = new AudioEffectDefinition(
typeof(AudioEffectComponent.ExampleAudioEffect).FullName,
properties);
W metodzie efektu SetProperties (pokazanej wcześniej) odczytaj te wartości z właściwości ustawionej w celu skonfigurowania efektu w czasie wykonywania.
Dodaj efekt do obiektu MediaCapture
Możesz również dodać efekt dźwięku niestandardowego do strumienia audio MediaCapture :
var effectDefinition = new AudioEffectDefinition(
typeof(AudioEffectComponent.ExampleAudioEffect).FullName);
await _mediaCapture.AddAudioEffectAsync(effectDefinition);