Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln visar hur du använder API:erna i Windows. Media.Audio namnrymd för att skapa ljuddiagram för scenarier för ljuddirigering, blandning och bearbetning.
Ett ljuddiagram är en uppsättning sammankopplade ljudnoder genom vilka ljuddata flödar.
Noder för ljudindata tillhandahåller ljuddata till grafen från ljudindataenheter, ljudfiler eller från anpassad kod.
Noder för ljudutdata är målet för ljud som bearbetas av diagrammet. Ljud kan dirigeras ut ur diagrammet till ljudutdataenheter, ljudfiler eller anpassad kod.
Submix-noder tar ljud från en eller flera noder och kombinerar dem till en enda utdata som kan dirigeras till andra noder i diagrammet.
När alla noder har skapats och anslutningarna mellan dem har konfigurerats startar du bara ljuddiagrammet och ljuddataflödena från indatanoderna, via eventuella undermixnoder, till utdatanoderna. Den här modellen gör scenarier som att spela in från en enhets mikrofon till en ljudfil, spela upp ljud från en fil till en enhets högtalare eller blanda ljud från flera källor snabbt och enkelt att implementera.
Ytterligare scenarier aktiveras med tillägg av ljudeffekter i ljuddiagrammet. Varje nod i ett ljuddiagram kan fyllas med noll eller fler ljudeffekter som utför ljudbearbetning på ljudet som passerar genom noden. Det finns flera inbyggda effekter som eko, equalizer, begränsning och reverb som kan kopplas till en ljudnod med bara några rader kod. Du kan också skapa egna anpassade ljudeffekter som fungerar exakt likadant som de inbyggda effekterna.
Välja Windows Runtime AudioGraph eller XAudio2
API:erna för Windows Runtime ljuddiagram erbjuder funktioner som också kan implementeras med hjälp av COM-baserade API:er XAudio2. Följande är funktioner i Windows Runtime ljudgraframverk som skiljer sig från XAudio2.
Windows Runtime-API:erna för ljudgrafer:
- Är betydligt enklare att använda än XAudio2.
- Kan användas från C# förutom att stödjas för C++.
- Kan använda ljudfiler, inklusive komprimerade filformat, direkt. XAudio2 fungerar bara på ljudbuffertar och tillhandahåller inga fil-I/O-funktioner.
- Kan använda ljudpipelinen med låg latens i Windows.
- Stöd för automatisk slutpunktsväxling när standardslutpunktsparametrar används. Om användaren till exempel växlar från en enhets högtalare till ett headset omdirigeras ljudet automatiskt till de nya utdata.
AudioGraph-klass
Klassen AudioGraph är överordnad för alla noder som utgör diagrammet. Använd det här objektet för att skapa instanser av alla typer av ljudnoder. Skapa en instans av klassen AudioGraph genom att initiera ett AudioGraphSettings objekt som innehåller konfigurationsinställningar för diagrammet. och anropa sedan AudioGraph.CreateAsync. Den returnerade CreateAudioGraphResult ger åtkomst till den skapade ljudgrafen eller ger ett felvärde om det inte går att skapa ljuddiagram.
AudioGraph audioGraph;
private async Task InitAudioGraph()
{
AudioGraphSettings settings = new AudioGraphSettings(Windows.Media.Render.AudioRenderCategory.Media);
CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);
if (result.Status != AudioGraphCreationStatus.Success)
{
ShowErrorMessage("AudioGraph creation error: " + result.Status);
return;
}
audioGraph = result.Graph;
}
Alla typer av ljudnoder skapas med hjälp av metoderna Skapa* i klassen AudioGraph .
Metoden AudioGraph.Start gör att ljuddiagrammet börjar bearbeta ljuddata. Metoden AudioGraph.Stop stoppar ljudbearbetningen. Varje nod i diagrammet kan startas och stoppas oberoende av varandra medan grafen körs, men inga noder är aktiva när grafen stoppas. ResetAllNodes gör att alla noder i diagrammet tar bort alla data som för närvarande finns i deras ljudbuffertar.
QuantumStarted-händelsen inträffar när grafen startar bearbetningen av en ny kvant av ljuddata. QuantumProcessed-händelsen inträffar när bearbetningen av ett kvantum har slutförts.
Den enda egenskapen AudioGraphSettings som krävs är AudioRenderCategory. Om du anger det här värdet kan systemet optimera ljudpipelinen för den angivna kategorin.
Kvantstorleken för ljuddiagrammet avgör antalet prover som bearbetas samtidigt. Som standard är kvantstorleken 10 ms baserat på standardexempelfrekvensen. Om du anger en anpassad kvantstorlek genom att ange egenskapen DesiredSamplesPerQuantum måste du också ange egenskapen QuantumSizeSelectionMode till ClosestToDesired eller så ignoreras det angivna värdet. Om det här värdet används väljer systemet en kvantstorlek så nära den som du anger. Om du vill fastställa den faktiska kvantstorleken kontrollerar du SamplesPerQuantum för AudioGraph när den har skapats.
Om du bara planerar att använda ljuddiagrammet med filer och inte planerar att mata ut till en ljudenhet rekommenderar vi att du använder kvantstorleken som standard genom att inte ange egenskapen DesiredSamplesPerQuantum .
Egenskapen DesiredRenderDeviceAudioProcessing avgör hur mycket bearbetning den primära renderingsenheten utför på utdata från ljuddiagrammet. Med standardinställningen kan systemet använda standardljudbearbetningen för den angivna ljudåtergivningskategorin. Den här bearbetningen kan avsevärt förbättra ljudet av ljud på vissa enheter, särskilt mobila enheter med små högtalare. Raw-inställningen kan förbättra prestandan genom att minimera mängden signalbearbetning som utförs, men kan resultera i sämre ljudkvalitet på vissa enheter.
Om QuantumSizeSelectionMode är inställt på LowestLatency använder ljuddiagrammet automatiskt Raw för DesiredRenderDeviceAudioProcessing.
Du kan ange egenskapen AudioGraphSettings.MaxPlaybackSpeedFactor för att ange ett maximalt värde som används för egenskaperna AudioFileInputNode.PlaybackSpeedFactor, AudioFrameInputNode.PlaybackSpeedFactor och MediaSourceInputNode.PlaybackSpeedFactor . När ett ljuddiagram stöder en uppspelningshastighetsfaktor som är större än 1 måste systemet allokera ytterligare minne för att upprätthålla en tillräcklig buffert av ljuddata. Av den anledningen minskar minnesförbrukningen för din app genom att ange MaxPlaybackSpeedFactor till det lägsta värde som krävs av appen. Om din app bara spelar upp innehåll med normal hastighet rekommenderar vi att du anger MaxPlaybackSpeedFactor till 1.
EncodingProperties avgör vilket ljudformat som används av diagrammet. Endast 32-bitars float-format stöds.
PrimaryRenderDevice anger den primära återgivningsenheten för ljuddiagrammet. Om du inte anger detta används standardsystemenheten. Den primära återgivningsenheten används för att beräkna kvantstorlekarna för andra noder i diagrammet. Om det inte finns några ljudåtergivningsenheter i systemet misslyckas skapandet av ljuddiagram.
Du kan låta ljuddiagrammet använda standardenheten för ljudåtergivning eller använda Windows. Devices.Enumeration.DeviceInformation för att få en lista över systemets tillgängliga ljudåtergivningsenheter genom att anropa FindAllAsync och skicka in väljaren för ljudåtergivningsenheten som returneras av Windows. Media.Devices.MediaDevice.GetAudioRenderSelector. Du kan välja ett av de returnerade DeviceInformation-objekten programmatiskt eller visa användargränssnittet så att användaren kan välja en enhet och sedan använda den för att ange egenskapen PrimaryRenderDevice .
Windows.Devices.Enumeration.DeviceInformationCollection devices =
await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Media.Devices.MediaDevice.GetAudioRenderSelector());
// Show UI to allow the user to select a device
Windows.Devices.Enumeration.DeviceInformation selectedDevice = ShowMyDeviceSelectionUI(devices);
settings.PrimaryRenderDevice = selectedDevice;
Enhetsindatanod
En enhetsinmatningsnod matar in ljud i grafen från en ljudinspelningsenhet som är ansluten till systemet, till exempel en mikrofon. Skapa ett DeviceInputNode objekt som använder systemets standardenhet för ljudavbildning genom att anropa CreateDeviceInputNodeAsync. Ange en MediaCategory så att systemet kan optimera ljudpipelinen för den angivna kategorin.
AudioDeviceInputNode deviceInputNode;
private async Task CreateDeviceInputNode()
{
// Create a device output node
CreateAudioDeviceInputNodeResult result = await audioGraph.CreateDeviceInputNodeAsync(Windows.Media.Capture.MediaCategory.Media);
if (result.Status != AudioDeviceNodeCreationStatus.Success)
{
// Cannot create device output node
ShowErrorMessage(result.Status.ToString());
return;
}
deviceInputNode = result.DeviceInputNode;
}
Om du vill ange en specifik ljudinspelningsenhet för enhetens indatanod kan du använda Windows. Devices.Enumeration.DeviceInformation för att hämta en lista över systemets tillgängliga ljudinspelningsenheter genom att anropa FindAllAsync och skicka in väljaren för ljudinspelningsenheten som returneras av Windows. Media.Devices.MediaDevice.GetAudioCaptureSelector. Du kan välja ett av de returnerade DeviceInformation-objekten programmatiskt eller visa användargränssnittet så att användaren kan välja en enhet och sedan skicka den till CreateDeviceInputNodeAsync.
Windows.Devices.Enumeration.DeviceInformationCollection devices =
await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Media.Devices.MediaDevice.GetAudioCaptureSelector());
// Show UI to allow the user to select a device
Windows.Devices.Enumeration.DeviceInformation selectedDevice = ShowMyDeviceSelectionUI(devices);
CreateAudioDeviceInputNodeResult result =
await audioGraph.CreateDeviceInputNodeAsync(Windows.Media.Capture.MediaCategory.Media, audioGraph.EncodingProperties, selectedDevice);
Enhetens utdatanod
En enhetsutdatanod skickar ljud från grafen till en ljudåtergivningsenhet, till exempel högtalare eller ett headset. Skapa en DeviceOutputNode genom att anropa CreateDeviceOutputNodeAsync. Utdatanoden använder PrimaryRenderDevice i ljuddiagrammet.
AudioDeviceOutputNode deviceOutputNode;
private async Task CreateDeviceOutputNode()
{
// Create a device output node
CreateAudioDeviceOutputNodeResult result = await audioGraph.CreateDeviceOutputNodeAsync();
if (result.Status != AudioDeviceNodeCreationStatus.Success)
{
// Cannot create device output node
ShowErrorMessage(result.Status.ToString());
return;
}
deviceOutputNode = result.DeviceOutputNode;
}
Filindatanod
Med en filinmatningsnod kan du mata in data från en ljudfil i grafen. Skapa en AudioFileInputNode genom att anropa CreateFileInputNodeAsync.
AudioFileInputNode fileInputNode;
private async Task CreateFileInputNode()
{
if (audioGraph == null)
{
return;
}
FileOpenPicker filePicker = new FileOpenPicker();
filePicker.SuggestedStartLocation = PickerLocationId.MusicLibrary;
filePicker.FileTypeFilter.Add(".mp3");
filePicker.FileTypeFilter.Add(".wav");
filePicker.FileTypeFilter.Add(".wma");
filePicker.FileTypeFilter.Add(".m4a");
filePicker.ViewMode = PickerViewMode.Thumbnail;
WinRT.Interop.InitializeWithWindow.Initialize(filePicker, _hwnd);
StorageFile file = await filePicker.PickSingleFileAsync();
// File can be null if cancel is hit in the file picker
if (file == null)
{
return;
}
CreateAudioFileInputNodeResult result = await audioGraph.CreateFileInputNodeAsync(file);
if (result.Status != AudioFileNodeCreationStatus.Success)
{
ShowErrorMessage(result.Status.ToString());
return;
}
fileInputNode = result.FileInputNode;
}
- Filindatanoder stöder följande filformat: mp3, wav, wma, m4a.
- Ange egenskapen StartTime för att ange tidsförskjutningen i filen där uppspelningen ska börja. Om den här egenskapen är null används början av filen. Ange egenskapen EndTime för att ange tidsförskjutningen i filen där uppspelningen ska avslutas. Om den här egenskapen är null används slutet av filen. Starttidsvärdet måste vara lägre än sluttidsvärdet och sluttidsvärdet måste vara mindre än eller lika med ljudfilens varaktighet, vilket kan fastställas genom att kontrollera egenskapsvärdet Varaktighet .
- Sök efter en position i ljudfilen genom att anropa Sök och ange tidsförskjutningen i filen som uppspelningspositionen ska flyttas till. Det angivna värdet måste ligga inom intervallet StartTime och EndTime . Hämta nodens aktuella uppspelningsposition med egenskapen skrivskyddad position .
- Aktivera loopning av ljudfilen genom att ange egenskapen LoopCount . När det inte är null anger det här värdet hur många gånger filen ska spelas upp efter den första uppspelningen. Om du till exempel anger LoopCount till 1 kommer filen att spelas upp 2 gånger totalt, och om du ställer in den på 5 spelas filen upp totalt 6 gånger. Om LoopCount anges till null loopas filen på obestämd tid. Om du vill sluta loopa anger du värdet till 0.
- Justera hastigheten med vilken ljudfilen spelas upp genom att ange PlaybackSpeedFactor. Värdet 1 anger filens ursprungliga hastighet, .5 är halv hastighet och 2 är dubbel hastighet.
MediaSource-indatanod
Klassen MediaSource är ett vanligt sätt att referera till media från olika källor och exponerar en vanlig modell för att komma åt mediedata oavsett det underliggande medieformatet, som kan vara en fil på disk, en ström eller en anpassningsbar strömmande nätverkskälla. Med en MediaSourceAudioInputNode-nod kan du dirigera ljuddata från en MediaSource till ljuddiagrammet. Skapa en MediaSourceAudioInputNode genom att anropa CreateMediaSourceAudioInputNodeAsync och skicka in ett MediaSource-objekt som representerar det innehåll som du vill spela upp. En CreateMediaSourceAudioInputNodeResult returneras som du kan använda för att fastställa status för åtgärden genom att kontrollera egenskapen Status . Om statusen är Lyckades kan du hämta den skapade MediaSourceAudioInputNode genom att komma åt egenskapen Node . I följande exempel visas skapandet av en nod från ett AdaptiveMediaSource-objekt som representerar innehåll som strömmas över nätverket.
MediaSourceAudioInputNode mediaSourceInputNode;
private async Task CreateMediaSourceInputNode(Uri contentUri)
{
if (audioGraph == null)
{
return;
}
var adaptiveMediaSourceResult = await AdaptiveMediaSource.CreateFromUriAsync(contentUri);
if (adaptiveMediaSourceResult.Status != AdaptiveMediaSourceCreationStatus.Success)
{
Debug.WriteLine("Failed to create AdaptiveMediaSource");
return;
}
MediaSource mediaSource = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSourceResult.MediaSource);
CreateMediaSourceAudioInputNodeResult mediaSourceAudioInputNodeResult =
await audioGraph.CreateMediaSourceAudioInputNodeAsync(mediaSource);
if (mediaSourceAudioInputNodeResult.Status != MediaSourceAudioInputNodeCreationStatus.Success)
{
switch (mediaSourceAudioInputNodeResult.Status)
{
case MediaSourceAudioInputNodeCreationStatus.FormatNotSupported:
Debug.WriteLine("The MediaSource uses an unsupported format");
break;
case MediaSourceAudioInputNodeCreationStatus.NetworkError:
Debug.WriteLine("The MediaSource requires a network connection and a network-related error occurred");
break;
case MediaSourceAudioInputNodeCreationStatus.UnknownFailure:
default:
Debug.WriteLine("An unknown error occurred while opening the MediaSource");
break;
}
return;
}
mediaSourceInputNode = mediaSourceAudioInputNodeResult.Node;
}
Om du vill få ett meddelande när uppspelningen har nått slutet av MediaSource-innehållet registrerar du en hanterare för händelsen MediaSourceCompleted .
mediaSourceInputNode.MediaSourceCompleted += MediaSourceInputNode_MediaSourceCompleted;
private void MediaSourceInputNode_MediaSourceCompleted(MediaSourceAudioInputNode sender, object args)
{
audioGraph.Stop();
}
När du spelar upp en fil från disken kan det hända att media som strömmas från en nätverkskälla misslyckas under uppspelningen på grund av en ändring i nätverksanslutningen eller andra problem som ligger utanför ljuddiagrammets kontroll. Om en MediaSource blir ospelbar under uppspelning utlöser ljuddiagrammet händelsen UnrecoverableErrorOccurred. Du kan använda hanteraren för den här händelsen för att stoppa och ta bort ljuddiagrammet och sedan initiera om diagrammet.
if (audioGraph != null)
{
audioGraph.UnrecoverableErrorOccurred += AudioGraph_UnrecoverableErrorOccurred;
}
private void AudioGraph_UnrecoverableErrorOccurred(AudioGraph sender, AudioGraphUnrecoverableErrorOccurredEventArgs args)
{
if (sender == audioGraph && args.Error != AudioGraphUnrecoverableError.None)
{
Debug.WriteLine("The audio graph encountered and unrecoverable error.");
audioGraph.Stop();
audioGraph.Dispose();
_ = InitAudioGraph();
}
}
Filutdatanod
Med en filutdatanod kan du dirigera ljuddata från grafen till en ljudfil. Skapa en AudioFileOutputNode genom att anropa CreateFileOutputNodeAsync.
AudioFileOutputNode fileOutputNode;
private async Task CreateFileOutputNode()
{
FileSavePicker saveFilePicker = new FileSavePicker();
saveFilePicker.FileTypeChoices.Add("Pulse Code Modulation", new System.Collections.Generic.List<string>() { ".wav" });
saveFilePicker.FileTypeChoices.Add("Windows Media Audio", new System.Collections.Generic.List<string>() { ".wma" });
saveFilePicker.FileTypeChoices.Add("MPEG Audio Layer-3", new System.Collections.Generic.List<string>() { ".mp3" });
saveFilePicker.SuggestedFileName = "New Audio Track";
WinRT.Interop.InitializeWithWindow.Initialize(saveFilePicker, _hwnd);
StorageFile file = await saveFilePicker.PickSaveFileAsync();
// File can be null if cancel is hit in the file picker
if (file == null)
{
return;
}
MediaEncodingProfile mediaEncodingProfile;
switch (file.FileType.ToLowerInvariant())
{
case ".wma":
mediaEncodingProfile = MediaEncodingProfile.CreateWma(AudioEncodingQuality.High);
break;
case ".mp3":
mediaEncodingProfile = MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High);
break;
case ".wav":
mediaEncodingProfile = MediaEncodingProfile.CreateWav(AudioEncodingQuality.High);
break;
default:
throw new ArgumentException();
}
// Operate node at the graph format, but save file at the specified format
CreateAudioFileOutputNodeResult result = await audioGraph.CreateFileOutputNodeAsync(file, mediaEncodingProfile);
if (result.Status != AudioFileNodeCreationStatus.Success)
{
// FileOutputNode creation failed
ShowErrorMessage(result.Status.ToString());
return;
}
fileOutputNode = result.FileOutputNode;
}
- Filutdatanoder stöder följande filformat: mp3, wav, wma, m4a.
- Du måste anropa AudioFileOutputNode.Stop för att stoppa nodens bearbetning innan du anropar AudioFileOutputNode.FinalizeAsync , annars utlöses ett undantag.
Indatanod för ljudbildruta
Med en indatanod för ljudram kan du skicka ljuddata som du genererar i din egen kod till ljuddiagrammet. Detta möjliggör scenarier som att skapa en anpassad programvarusyntes. Skapa en AudioFrameInputNode genom att anropa CreateFrameInputNode.
AudioFrameInputNode frameInputNode;
private void CreateFrameInputNode()
{
// Create the FrameInputNode at the same format as the graph, except explicitly set mono.
AudioEncodingProperties nodeEncodingProperties = audioGraph.EncodingProperties;
nodeEncodingProperties.ChannelCount = 1;
frameInputNode = audioGraph.CreateFrameInputNode(nodeEncodingProperties);
// Initialize the Frame Input Node in the stopped state
frameInputNode.Stop();
// Hook up an event handler so we can start generating samples when needed
// This event is triggered when the node is required to provide data
frameInputNode.QuantumStarted += node_QuantumStarted;
}
Händelsen FrameInputNode.QuantumStarted aktiveras när ljuddiagrammet är redo att börja bearbeta nästa kvant av ljuddata. Du tillhandahåller dina anpassade ljuddata som du har genererat inifrån hanteraren till den här händelsen.
private void node_QuantumStarted(AudioFrameInputNode sender, FrameInputNodeQuantumStartedEventArgs args)
{
// GenerateAudioData can provide PCM audio data by directly synthesizing it or reading from a file.
// Need to know how many samples are required. In this case, the node is running at the same rate as the rest of the graph
// For minimum latency, only provide the required amount of samples. Extra samples will introduce additional latency.
uint numSamplesNeeded = (uint)args.RequiredSamples;
if (numSamplesNeeded != 0)
{
AudioFrame audioData = GenerateAudioData(numSamplesNeeded);
frameInputNode.AddFrame(audioData);
}
}
- Objektet FrameInputNodeQuantumStartedEventArgs som skickas till händelsehanteraren för QuantumStarted exponerar egenskapen RequiredSamples, som anger hur många samplingar ljudgrafen behöver för att fylla kvantumet som ska bearbetas.
- Anropa AudioFrameInputNode.AddFrame för att skicka ett AudioFrame objekt fyllt med ljuddata i diagrammet.
- Du kan använda MediaFrameReader med ljuddata för att hämta AudioFrame-objekt från en medieramkälla, som kan skickas till en FrameInputNode med hjälp av metoden AddFrame .
- Ett exempel på implementering av hjälpmetoden GenerateAudioData visas nedan.
Om du vill fylla i en AudioFrame med ljuddata, måste du få åtkomst till ljudramens underliggande minnesbuffert. Det gör du genom att initiera COM-gränssnittet IMemoryBufferByteAccess enligt nedan.
[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
void GetBuffer(out byte* buffer, out uint capacity);
}
Följande kod visar ett exempel på en implementering av en GenerateAudioData hjälpmetod som skapar en AudioFrame och fyller den med ljuddata.
private double audioWaveTheta = 0;
unsafe private AudioFrame GenerateAudioData(uint samples)
{
// Buffer size is (number of samples) * (size of each sample)
// We choose to generate single channel (mono) audio. For multi-channel, multiply by number of channels
uint bufferSize = samples * sizeof(float);
AudioFrame frame = new AudioFrame(bufferSize);
using (AudioBuffer buffer = frame.LockBuffer(AudioBufferAccessMode.Write))
using (IMemoryBufferReference reference = buffer.CreateReference())
{
byte* dataInBytes;
uint capacityInBytes;
float* dataInFloat;
// Get the buffer from the AudioFrame
((IMemoryBufferByteAccess)reference).GetBuffer(out dataInBytes, out capacityInBytes);
// Cast to float since the data we are generating is float
dataInFloat = (float*)dataInBytes;
float freq = 1000; // choosing to generate frequency of 1kHz
float amplitude = 0.3f;
int sampleRate = (int)audioGraph.EncodingProperties.SampleRate;
double sampleIncrement = (freq * (Math.PI * 2)) / sampleRate;
// Generate a 1kHz sine wave and populate the values in the memory buffer
for (int i = 0; i < samples; i++)
{
double sinValue = amplitude * Math.Sin(audioWaveTheta);
dataInFloat[i] = (float)sinValue;
audioWaveTheta += sampleIncrement;
}
}
return frame;
}
- Eftersom den här metoden kommer åt den råbuffert som ligger bakom de Windows Runtime typerna måste den deklareras med nyckelordet unsafe. Du måste också konfigurera projektet i Microsoft Visual Studio för att tillåta kompilering av osäker kod genom att öppna projektets Egenskaper sida. klicka på egenskapssidan Build och markera kryssrutan Allow Unsafe Code.
- Initiera en ny instans av AudioFrame i Windows. Media namnområde, genom att skicka den önskade buffertstorleken till konstruktorn. Buffertstorleken är antalet exempel multiplicerat med storleken på varje prov.
- Hämta ljudramens AudioBuffer genom att anropa LockBuffer.
- Hämta en instans av COM-gränssnittet IMemoryBufferByteAccess från ljudbufferten genom att anropa CreateReference.
- Hämta en pekare till råa ljudbuffertdata genom att anropa IMemoryBufferByteAccess.GetBuffer och casta den till samplingsdatatypen för ljuddata.
- Fyll bufferten med data och returnera AudioFrame för överföring till ljuddiagrammet.
Utdatanod för ljudram
Med en ljudramsutdatanod kan du ta emot och bearbeta ljuddatautdata från ljuddiagrammet med anpassad kod som du skapar. Ett exempelscenario för detta är att utföra signalanalys på ljudutdata. Skapa en AudioFrameOutputNode genom att anropa CreateFrameOutputNode.
AudioFrameOutputNode frameOutputNode;
private void CreateFrameOutputNode()
{
frameOutputNode = audioGraph.CreateFrameOutputNode();
audioGraph.QuantumStarted += AudioGraph_QuantumStarted;
}
Händelsen AudioGraph.QuantumStarted utlöses när ljuddiagrammet har börjat bearbeta ett kvantum med ljuddata. Du kan komma åt ljuddata från hanteraren för den här händelsen.
Note
Om du vill hämta ljudramar med jämna mellanrum, synkroniserat med ljudgrafen, anropar du AudioFrameOutputNode.GetFrame inifrån den synkrona händelsehanteraren för QuantumStarted. QuantumProcessed-händelsen aktiveras asynkront när ljudmotorn har slutfört ljudbearbetningen, vilket innebär att dess takt kan vara oregelbunden. Därför bör du inte använda QuantumProcessed-händelsen för synkroniserad bearbetning av ljudramsdata.
private void AudioGraph_QuantumStarted(AudioGraph sender, object args)
{
AudioFrame frame = frameOutputNode.GetFrame();
ProcessFrameOutput(frame);
}
- Anropa GetFrame för att hämta ett AudioFrame objekt fyllt med ljuddata från diagrammet.
- Ett exempel på implementering av hjälpmetoden ProcessFrameOutput visas nedan.
unsafe private void ProcessFrameOutput(AudioFrame frame)
{
using (AudioBuffer buffer = frame.LockBuffer(AudioBufferAccessMode.Write))
using (IMemoryBufferReference reference = buffer.CreateReference())
{
byte* dataInBytes;
uint capacityInBytes;
float* dataInFloat;
// Get the buffer from the AudioFrame
((IMemoryBufferByteAccess)reference).GetBuffer(out dataInBytes, out capacityInBytes);
dataInFloat = (float*)dataInBytes;
}
}
- Precis som exemplet med indatanoden för ljudramen ovan måste du deklarera COM-gränssnittet IMemoryBufferByteAccess och konfigurera projektet så att osäker kod tillåts för att få åtkomst till den underliggande ljudbufferten.
- Hämta ljudramens AudioBuffer genom att anropa LockBuffer.
- Hämta en instans av COM-gränssnittet IMemoryBufferByteAccess från ljudbufferten genom att anropa CreateReference.
- Hämta en pekare till rå ljudbuffertdata genom att anropa IMemoryBufferByteAccess.GetBuffer och typkonvertera den till samplens datatyp för ljuddata.
Nodanslutningar och undermixnoder
Alla typer av indatanoder exponerar metoden AddOutgoingConnection som dirigerar ljudet som genereras av noden till den nod som skickas till metoden. I följande exempel ansluts en AudioFileInputNode till en AudioDeviceOutputNode, vilket är en enkel konfiguration för att spela upp en ljudfil på enhetens högtalare.
fileInputNode.AddOutgoingConnection(deviceOutputNode);
Du kan skapa fler än en anslutning från en indatanod till andra noder. I följande exempel läggs en annan anslutning från AudioFileInputNode till en AudioFileOutputNode. Nu spelas ljudet från ljudfilen upp till enhetens högtalare och skrivs också ut till en ljudfil.
fileInputNode.AddOutgoingConnection(fileOutputNode);
Utdatanoder kan också ta emot mer än en anslutning från andra noder. I följande exempel görs en anslutning från en AudioDeviceInputNode till noden AudioDeviceOutput. Eftersom utdatanoden har anslutningar från filindatanoden och enhetens indatanod innehåller utdata en blandning av ljud från båda källorna. AddOutgoingConnection har en överladdning som gör att du kan ange ett förstärkningsvärde för signalen som passerar genom anslutningen.
deviceInputNode.AddOutgoingConnection(deviceOutputNode, .5);
Även om utdatanoder kan acceptera anslutningar från flera noder, kanske du vill skapa en mellanliggande blandning av signaler från en eller flera noder innan du skickar mixen till utdata. Du kanske till exempel vill ange nivån eller tillämpa effekter på en delmängd av ljudsignalerna i en graf. Det gör du genom att använda AudioSubmixNode. Du kan ansluta till en undermixnod från en eller flera indatanoder eller andra undermixnoder. I följande exempel skapas en ny undermixnod med AudioGraph.CreateSubmixNode. Sedan läggs anslutningar till mellan en filinmatningsnod och en bildruteinmatningsnod och submix-noden. Slutligen är submixnoden ansluten till en filutgångsnod.
private void CreateSubmixNode()
{
AudioSubmixNode submixNode = audioGraph.CreateSubmixNode();
fileInputNode.AddOutgoingConnection(submixNode);
frameInputNode.AddOutgoingConnection(submixNode);
submixNode.AddOutgoingConnection(fileOutputNode);
}
Starta och stoppa ljuddiagramnoder
När AudioGraph.Start anropas börjar ljuddiagrammet bearbeta ljuddata. Varje nodtyp innehåller start- och stoppmetoder som gör att den enskilda noden startar eller slutar bearbeta data. När AudioGraph.Stop anropas stoppas all ljudbearbetning i alla noder oavsett tillståndet för enskilda noder, men tillståndet för varje nod kan anges medan ljuddiagrammet stoppas. Du kan till exempel anropa Stoppa på en enskild nod medan grafen stoppas och sedan anropa AudioGraph.Start, och den enskilda noden förblir i stoppat tillstånd.
Alla nodtyper exponerar egenskapen ConsumeInput som, när den är inställd på false, tillåter noden att fortsätta ljudbearbetningen men hindrar den från att använda ljuddata som matas in från andra noder.
Alla nodtyper exponerar återställningsmetoden som gör att noden tar bort alla ljuddata som för närvarande finns i bufferten.
Lägga till ljudeffekter
Med API:et för ljuddiagram kan du lägga till ljudeffekter till varje typ av nod i en graf. Utdatanoder, indatanoder och undermixnoder kan ha ett obegränsat antal ljudeffekter, som endast begränsas av maskinvarans funktioner. I följande exempel visas hur du lägger till den inbyggda ekoeffekten till en undermixnod.
EchoEffectDefinition echoEffect = new EchoEffectDefinition(audioGraph);
echoEffect.Delay = 1000.0;
echoEffect.Feedback = .2;
echoEffect.WetDryMix = .5;
submixNode.EffectDefinitions.Add(echoEffect);
- Alla ljudeffekter implementerar IAudioEffectDefinition. Varje nod exponerar en EffectDefinitions-egenskap som representerar listan över effekter som tillämpas på noden. Lägg till en effekt genom att lägga till dess definitionsobjekt i listan.
- Det finns flera effektdefinitionsklasser som finns i Windows. Media.Audio namnrymd. Dessa inkluderar:
- Du kan skapa egna ljudeffekter som implementerar IAudioEffectDefinition och tillämpa dem på valfri nod i en ljudgraf.
- Varje nodtyp exponerar en DisableEffectsByDefinition-metod som inaktiverar alla effekter i nodens EffectDefinitions-lista som lades till med den angivna definitionen. EnableEffectsByDefinition aktiverar effekterna med den angivna definitionen.
Rumsligt ljud
AudioGraph stöder rumsligt ljud, vilket gör att du kan ange platsen i 3D-utrymme från vilken ljud från alla indata- eller undermixnoder genereras. Du kan också ange en form och riktning i vilken ljud genereras, en hastighet som ska användas för att Doppler flytta nodens ljud och definiera en modell för sönderfall som beskriver hur ljudet dämpas med avstånd.
Om du vill skapa en emitter kan du först skapa en form där ljudet projiceras från sändaren, som kan vara en kon eller omnidirectional. Klassen AudioNodeEmitterShape innehåller statiska metoder för att skapa var och en av dessa former. Skapa sedan en sönderfallsmodell. Detta definierar hur volymen av ljudet från sändaren minskar när avståndet från lyssnaren ökar. Metoden CreateNatural skapar en förfallsmodell som emulerar det naturliga sönderfallet av ljud med hjälp av en avståndsmodell för kvadratisk falloff. Skapa slutligen ett AudioNodeEmitterSettings objekt. För närvarande används det här objektet endast för att aktivera och inaktivera hastighetsbaserad Doppler-dämpning av sändarens ljud. Anropa Konstruktorn AudioNodeEmitter och skicka in de initieringsobjekt som du nyss skapade. Som standard placeras emittern vid ursprunget, men du kan ange positionen för emittern med egenskapen Position .
Note
Ljudnodsemittare kan bara bearbeta ljud som är formaterat i mono med en exempelfrekvens på 48 kHz. Om du försöker använda stereoljud eller ljud med en annan exempelfrekvens resulterar det i ett undantag.
Du tilldelar emittern till en ljudnod när du skapar den med hjälp av den överlagrade metoden för att skapa den nodtyp du vill ha. I det här exemplet används CreateFileInputNodeAsync för att skapa en filindatanod från en angiven fil och AudioNodeEmitter objekt som du vill associera med noden.
var emitterShape = AudioNodeEmitterShape.CreateOmnidirectional();
var decayModel = AudioNodeEmitterDecayModel.CreateNatural(.1, 1, 10, 100);
var settings = AudioNodeEmitterSettings.None;
var emitter = new AudioNodeEmitter(emitterShape, decayModel, settings);
emitter.Position = new Vector3(10, 0, 5);
CreateAudioFileInputNodeResult result = await audioGraph.CreateFileInputNodeAsync(file, emitter);
if (result.Status != AudioFileNodeCreationStatus.Success)
{
ShowErrorMessage(result.Status.ToString());
return;
}
fileInputNode = result.FileInputNode;
AudioDeviceOutputNode som matar ut ljud från grafen till användaren har ett lyssnarobjekt, används med egenskapen Listener, som representerar användarens plats, orientering och hastighet i 3D-utrymmet. Positionerna för alla utsändare i diagrammet är relativa till lyssnarobjektets position och orientering. Som standard finns lyssnaren vid ursprunget (0,0,0) framåt längs Z-axeln, men du kan ange dess position och orientering med egenskaperna Position och Orientering .
deviceOutputNode.Listener.Position = new Vector3(100, 0, 0);
deviceOutputNode.Listener.Orientation = Quaternion.CreateFromYawPitchRoll(0, (float)Math.PI, 0);
Du kan uppdatera position, hastighet och riktning för sändare under körning för att simulera rörelsen hos en ljudkälla genom ett 3D-utrymme.
AudioNodeEmitter emitter = fileInputNode.Emitter;
emitter.Position = newObjectPosition;
emitter.DopplerVelocity = newObjectPosition - oldObjectPosition;
Du kan också uppdatera plats, hastighet och orientering för lyssnarobjektet vid körning för att simulera användarens förflyttning via 3D-utrymme.
deviceOutputNode.Listener.Position = newUserPosition;
Som standard beräknas rumsligt ljud med Microsoft algoritm för head-relative transfer (HRTF) för att dämpa ljudet baserat på dess form, hastighet och position i förhållande till lyssnaren. Du kan ange egenskapen SpatialAudioModel till FoldDown för att använda en enkel stereoblandningsmetod för att simulera rumsligt ljud som är mindre exakt men som kräver mindre processor- och minnesresurser.
Se även
Windows developer