Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek ukazuje, jak používat rozhraní API v oboru názvů Windows.Media.Audio k vytváření zvukových grafů pro scénáře směrování, mixování a zpracování zvuku.
Zvukový graf je sada vzájemně propojených zvukových uzlů, kterými proudí zvuková data.
Zvukové vstupní uzly poskytují do grafu zvuková data ze zvukových vstupních zařízení, zvukových souborů nebo z vlastního kódu.
Výstupní uzly zvuku jsou cílem pro zvuk zpracovaný grafem. Zvuk je možné směrovat mimo graf do výstupních zvukových zařízení, zvukových souborů nebo vlastního kódu.
Submixové uzly přebírají zvuk z jednoho nebo více uzlů a kombinují je do jednoho výstupu, který je možné směrovat do jiných uzlů v grafu.
Po vytvoření všech uzlů a nastavení připojení mezi nimi jednoduše spustíte zvukový graf a zvuková data proudí ze vstupních uzlů přes všechny submixové uzly do výstupních uzlů. Tento model vytváří scénáře, jako je nahrávání z mikrofonu zařízení do zvukového souboru, přehrávání zvuku ze souboru do reproduktoru zařízení nebo kombinování zvuku z více zdrojů, které je snadné a snadno implementovat.
S přidáním zvukových efektů do zvukového grafu jsou povolené další scénáře. Každý uzel ve zvukovém grafu lze naplnit nulovými nebo více zvukovými efekty, které provádějí zpracování zvuku na zvuku procházejícím tímto uzlem. Existuje několik předdefinovaných efektů, jako je echo, equalizer, limiting a reverb, které lze připojit ke zvukovému uzlu jen s několika řádky kódu. Můžete také vytvořit vlastní zvukové efekty, které fungují úplně stejně jako předdefinované efekty.
Volba prostředí Windows Runtime AudioGraph nebo XAudio2
Rozhraní API grafu zvuku prostředí Windows Runtime poskytují funkce, které lze implementovat také pomocí rozhraní API XAudio2 založených na modelu COM. Níže jsou uvedené funkce rozhraní prostředí Windows Runtime audio graphu, které se liší od XAudio2.
Rozhraní API prostředí Windows Runtime pro zvukové grafy:
- Jejich použití je výrazně snazší než XAudio2.
- Lze jej používat také z jazyka C# vedle podpory pro C++.
- Můžete použít zvukové soubory, včetně komprimovaných formátů souborů, přímo. XAudio2 funguje jenom na zvukových vyrovnávacích pamětích a neposkytuje žádné možnosti vstupně-výstupních operací souborů.
- V Windows může používat zvukový kanál s nízkou latencí.
- Podpora automatického přepínání koncových bodů při použití výchozích parametrů koncového bodu Pokud například uživatel přepne z reproduktoru zařízení na náhlavní soupravu, zvuk se automaticky přesměruje na nový výstup.
Třída AudioGraph
Třída AudioGraph je nadřazená všem uzlům, které tvoří graf. Tento objekt použijte k vytvoření instancí všech typů zvukových uzlů. Vytvořte instanci třídy AudioGraph inicializací AudioGraphSettings objekt obsahující nastavení konfigurace grafu. a potom voláním AudioGraph.CreateAsync. Vrácená CreateAudioGraphResult poskytuje přístup k vytvořenému zvukovému grafu nebo poskytuje chybovou hodnotu v případě selhání vytváření zvukového grafu.
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;
}
Všechny typy zvukových uzlů se vytvářejí pomocí metod Create* třídy AudioGraph .
Metoda AudioGraph.Start způsobí, že zvukový graf začne zpracovávat zvuková data. Metoda AudioGraph.Stop zastaví zpracování zvuku. Každý uzel v grafu je možné spustit a zastavit nezávisle na době, kdy je graf spuštěný, ale při zastavení grafu nejsou aktivní žádné uzly. ResetAllNodes způsobí, že všechny uzly v grafu zahodí všechna data, která se aktuálně nacházejí v jejich zvukových vyrovnávacích pamětích.
K události QuantumStarted dochází, když graf spouští zpracování nového kvanta zvukových dat. K události QuantumProcessed dochází při dokončení zpracování kvantových dat.
Jediná požadovaná vlastnost AudioGraphSettings je AudioRenderCategory. Zadáním této hodnoty umožníte systému optimalizovat zvukový kanál pro zadanou kategorii.
Kvantová velikost zvukového grafu určuje počet vzorků, které se zpracovávají najednou. Ve výchozím nastavení je kvantová velikost 10 ms založená na výchozí vzorkovací frekvenci. Pokud zadáte vlastní kvantovou velikost nastavením vlastnosti DesiredSamplesPerQuantum , musíte také nastavit QuantumSizeSelectionMode vlastnost NejbližšíToDesired nebo je zadaná hodnota ignorována. Pokud se tato hodnota použije, systém zvolí kvantovou velikost co nejblíže zadané hodnotě. Chcete-li zjistit skutečnou velikost kvanta, zkontrolujte SamplesPerQuantum u objektu AudioGraph po jeho vytvoření.
Pokud plánujete používat pouze zvukový graf se soubory a neplánujete výstup do zvukového zařízení, doporučujeme použít výchozí kvantovou velikost tím, že nenastavíte vlastnost DesiredSamplesPerQuantum .
Vlastnost DesiredRenderDeviceAudioProcessing určuje množství zpracování primárního vykreslovacího zařízení provádí na výstupu zvukového grafu. Výchozí nastavení umožňuje systému použít výchozí zpracování zvuku pro zadanou kategorii vykreslování zvuku. Toto zpracování může výrazně zlepšit zvuk zvuku na některých zařízeních, zejména mobilních zařízení s malými reproduktory. Nezpracované nastavení může zvýšit výkon minimalizací množství provedeného zpracování signálu, ale může mít za následek nižší kvalitu zvuku na některých zařízeních.
Pokud je QuantumSizeSelectionMode nastaven na LowestLatency, zvukový graf automaticky použije Raw pro DesiredRenderDeviceAudioProcessing.
Můžete nastavit AudioGraphSettings.MaxPlaybackSpeedFactor vlastnost nastavit maximální hodnotu použitou pro AudioFileInputNode.PlaybackSpeedFactor, AudioFrameInputNode.PlaybackSpeedFactor a MediaSourceInputNode.PlaybackSpeedFactor vlastnosti. Pokud zvukový graf podporuje faktor rychlosti přehrávání větší než 1, musí systém přidělit další paměť, aby zachoval dostatečnou vyrovnávací paměť zvukových dat. Z tohoto důvodu nastavení MaxPlaybackSpeedFactor na nejnižší hodnotu požadovanou vaší aplikací sníží spotřebu paměti vaší aplikace. Pokud vaše aplikace bude přehrávat obsah jen při normální rychlosti, doporučuje se nastavit MaxPlaybackSpeedFactor na hodnotu 1.
EncodingProperties určuje formát zvuku, který graf používá. Podporují se pouze 32bitové formáty float.
PrimaryRenderDevice nastaví primární vykreslovací zařízení pro zvukový graf. Pokud toto nastavení nenastavíte, použije se výchozí systémové zařízení. Primární vykreslovací zařízení se používá k výpočtu kvantových velikostí pro ostatní uzly v grafu. Pokud v systému nejsou žádná zařízení pro vykreslování zvuku, vytváření zvukového grafu selže.
Můžete nechat zvukový graf používat výchozí zařízení pro vykreslování audia nebo použít třídu Windows.Devices.Enumeration.DeviceInformation k získání seznamu dostupných zařízení systému pro vykreslování audia voláním metody FindAllAsync a předáním selektoru zařízení pro vykreslování audia vráceného metodou Windows.Media.Devices.MediaDevice.GetAudioRenderSelector. Můžete zvolit jeden z vrácených DeviceInformation objekty programově nebo zobrazit uživatelské rozhraní, aby uživatel mohl vybrat zařízení a pak ho použít k nastavení PrimaryRenderDevice vlastnost.
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;
Vstupní uzel zařízení
Vstupní uzel zařízení předá zvuk do grafu ze zvukového zařízení připojeného k systému, například mikrofonu. Vytvořte objekt DeviceInputNode, který používá výchozí zvukové zachytávání zařízení systému voláním CreateDeviceInputNodeAsync. Zadejte MediaCategory, aby systém mohl optimalizovat zvukový kanál pro zadanou kategorii.
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;
}
Pokud chcete pro vstupní uzel zařízení určit konkrétní zařízení pro zachytávání zvuku, můžete použít třídu Windows.Devices.Enumeration.DeviceInformation k získání seznamu zařízení pro zachytávání zvuku dostupných v systému voláním metody FindAllAsync a předáním selektoru zařízení pro zachytávání zvuku vráceného metodou Windows.Media.Devices.MediaDevice.GetAudioCaptureSelector. Můžete zvolit jeden z vrácených objektů DeviceInformation programově nebo zobrazit uživatelské rozhraní, aby uživatel mohl vybrat zařízení a pak ho předat do 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);
Výstupní uzel zařízení
Výstupní uzel zařízení odešle zvuk z grafu do zařízení pro vykreslování zvuku, jako jsou reproduktory nebo náhlavní souprava. Vytvořte DeviceOutputNode voláním CreateDeviceOutputNodeAsync. Výstupní uzel používá PrimárníRenderDevice zvukového grafu.
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;
}
Vstupní uzel souboru
Vstupní uzel souboru umožňuje do grafu načíst data ze zvukového souboru. Vytvořte AudioFileInputNode voláním 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;
}
- Vstupní uzly souborů podporují následující formáty souborů: mp3, wav, wma, m4a.
- Nastavte vlastnost StartTime tak, aby určil časový posun do souboru, kde má začít přehrávání. Pokud je tato vlastnost null, použije se začátek souboru. Nastavte vlastnost EndTime tak, aby určila časový posun do souboru, kde má přehrávání končit. Pokud je tato vlastnost null, použije se konec souboru. Hodnota počátečního času musí být nižší než hodnota koncového času a hodnota koncového času musí být menší nebo rovna době trvání zvukového souboru, kterou lze určit kontrolou hodnoty vlastnosti Duration .
- Vyhledejte pozici ve zvukovém souboru zavoláním funkce Hledat a určením posunu času do souboru, do kterého se má pozice přehrávání přesunout. Zadaná hodnota musí být v rozsahu StartTime a EndTime . Aktuální pozici přehrávání uzlu získáte pomocí vlastnosti Position, která je jen pro čtení.
- Povolte opakování zvukového souboru nastavením vlastnosti LoopCount. Pokud není null, tato hodnota označuje, kolikrát se soubor přehraje po počátečním přehrávání. Například nastavení LoopCount na 1 způsobí, že se soubor přehraje celkem 2krát a jeho nastavení na 5 způsobí, že se soubor přehraje celkem 6krát. Nastavení LoopCount na hodnotu null způsobí, že se soubor trvale smyčí. Pokud chcete smyčku zastavit, nastavte hodnotu na 0.
- Upravte rychlost přehrávání zvukového souboru nastavením PlaybackSpeedFactor. Hodnota 1 označuje původní rychlost souboru, 0,5 je poloviční rychlost a 2 je dvojitá rychlost.
Vstupní uzel MediaSource
Třída MediaSource poskytuje běžný způsob, jak odkazovat na média z různých zdrojů a vystavit společný model pro přístup k datům médií bez ohledu na základní formát média, což může být soubor na disku, datový proud nebo zdroj sítě s adaptivním streamováním. Uzel MediaSourceAudioInputNode umožňuje směrovat zvuková data z MediaSource do zvukového grafu. Vytvořte MediaSourceAudioInputNodevoláním CreateMediaSourceAudioInputNodeAsyncpředáním MediaSource objekt představující obsah, který chcete přehrát. Je vrácena vlastnost CreateMediaSourceAudioInputNodeResult , kterou můžete použít k určení stavu operace kontrolou Status vlastnost. Pokud je stav Success, můžete získat vytvořený MediaSourceAudioInputNode prostřednictvím vlastnosti Node. Následující příklad ukazuje vytvoření uzlu z objektu AdaptiveMediaSource představujícího streamování obsahu přes síť.
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;
}
Chcete-li obdržet oznámení při dosažení konce obsahu MediaSource , zaregistrujte obslužnou rutinu pro událost MediaSourceCompleted .
mediaSourceInputNode.MediaSourceCompleted += MediaSourceInputNode_MediaSourceCompleted;
private void MediaSourceInputNode_MediaSourceCompleted(MediaSourceAudioInputNode sender, object args)
{
audioGraph.Stop();
}
Při přehrávání souboru z disku bude pravděpodobně vždy úspěšně dokončeno, média streamovaná ze zdroje sítě může při přehrávání selhat kvůli změně síťového připojení nebo jiným problémům, které jsou mimo kontrolu zvukového grafu. Pokud se mediaSource během přehrávání stane nepřehrávatelným, zvukový graf vyvolá událost UnrecoverableErrorOccurred . Obslužnou rutinu pro tuto událost můžete použít k zastavení a odstranění zvukového grafu a následné inicializaci grafu.
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();
}
}
Výstupní uzel souboru
Výstupní uzel souboru umožňuje směrovat zvuková data z grafu do zvukového souboru. Vytvořte AudioFileOutputNode voláním 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;
}
- Výstupní uzly souborů podporují následující formáty souborů: mp3, wav, wma, m4a.
- Před voláním AudioFileOutputNode.FinalizeAsync musíte zavolat AudioFileOutputNode.Stop, aby se zastavilo zpracování uzlu, jinak dojde k výjimce.
Vstupní uzel zvukového rámce
Vstupní uzel zvukového rámce umožňuje odesílat zvuková data, která vygenerujete ve vlastním kódu, do zvukového grafu. To umožňuje scénáře, jako je vytvoření vlastního syntetizátoru softwaru. Vytvořte AudioFrameInputNode voláním 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;
}
Událost FrameInputNode.QuantumStarted se vyvolá, když je zvukový graf připravený začít zpracovávat další kvantová zvuková data. Do této události zadáte vlastní generovaná zvuková data z obslužné rutiny.
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);
}
}
- Objekt FrameInputNodeQuantumStartedEventArgs předaný obslužné rutině události QuantumStarted zpřístupňuje vlastnost RequiredSamples, která udává, kolik vzorků audio graf potřebuje k doplnění kvanta, které má být zpracováno.
- Zavolejte AudioFrameInputNode.AddFrame a předejte do grafu objekt AudioFrame naplněný zvukovými daty.
- MediaFrameReader se zvukovými daty můžete použít k získání objektů AudioFrame ze zdroje snímku média, které lze předat do FrameInputNode pomocí AddFrame metody.
- Příklad implementace GenerateAudioData pomocné metody je uveden níže.
Pokud chcete naplnit AudioFrame zvukovými daty, musíte získat přístup k podkladové vyrovnávací paměti zvukového rámce. To provedete tak, že inicializujete rozhraní COM IMemoryBufferByteAccess, jak je uvedeno níže.
[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
void GetBuffer(out byte* buffer, out uint capacity);
}
Následující kód ukazuje příklad implementace GenerateAudioData pomocné metody, která vytvoří AudioFrame a naplní je zvukovými daty.
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;
}
- Vzhledem k tomu, že tato metoda přistupuje k nezpracovanému bufferu, který je základem typů prostředí Windows Runtime, musí být deklarována pomocí klíčového slova unsafe. Projekt musíte také nakonfigurovat v Microsoft Visual Studio tak, aby umožňoval kompilaci nebezpečného kódu otevřením stránky vlastností Properties stránky Build a zaškrtnutím políčka Povolit nebezpečný kód.
- Inicializujte novou instanci AudioFrame v oboru názvů Windows.Media předáním požadované velikosti vyrovnávací paměti do konstruktoru. Velikost vyrovnávací paměti je počet vzorků vynásobených velikostí každého vzorku.
- Získejte AudioBuffer zvukového rámce voláním LockBuffer.
- Získejte instanci rozhraní COM IMemoryBufferByteAccess ze zvukové vyrovnávací paměti voláním metody CreateReference.
- Získejte ukazatel k nezpracovaným datům zvukové vyrovnávací paměti zavoláním IMemoryBufferByteAccess.GetBuffer a přetypujte jej na datový typ vzorků zvukových dat.
- Naplňte vyrovnávací paměť daty a vraťte objekt AudioFrame k odeslání do zvukového grafu.
Výstupní uzel zvukového rámce
Výstupní uzel zvukového rámce umožňuje přijímat a zpracovávat výstup zvukových dat ze zvukového grafu pomocí vlastního kódu, který vytvoříte. Příkladem tohoto scénáře je analýza signálu na zvukovém výstupu. Vytvořte AudioFrameOutputNode voláním CreateFrameOutputNode.
AudioFrameOutputNode frameOutputNode;
private void CreateFrameOutputNode()
{
frameOutputNode = audioGraph.CreateFrameOutputNode();
audioGraph.QuantumStarted += AudioGraph_QuantumStarted;
}
Událost AudioGraph.QuantumStarted se vyvolá, když zvukový graf začne zpracovávat kvantová zvuková data. Ke zvukovým datům můžete přistupovat z obslužné rutiny pro tuto událost.
Note
Pokud chcete načíst zvukové snímky v pravidelném tempu, synchronizované se zvukovým grafem, zavolejte AudioFrameOutputNode.GetFrame z synchronní obslužné rutiny události QuantumStarted . Událost QuantumProcessed je vyvolána asynchronně poté, co zvukový stroj dokončil zpracování zvuku, což znamená, že jeho četnost může být nepravidelná. Proto byste neměli k synchronizaci zpracování dat zvukového rámce použít událost QuantumProcessed .
private void AudioGraph_QuantumStarted(AudioGraph sender, object args)
{
AudioFrame frame = frameOutputNode.GetFrame();
ProcessFrameOutput(frame);
}
- Voláním GetFrame získáte AudioFrame objekt vyplněný zvukovými daty z grafu.
- Příklad implementace pomocné metody ProcessFrameOutput je uveden níže.
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;
}
}
- Podobně jako ve výše uvedeném příkladu vstupního uzlu zvukového snímku budete muset deklarovat rozhraní COM IMemoryBufferByteAccess a nakonfigurovat projekt tak, aby povoloval unsafe kód, abyste měli přístup k podkladové zvukové vyrovnávací paměti.
- Získejte AudioBuffer zvukového rámce voláním LockBuffer.
- Získejte instanci rozhraní COM IMemoryBufferByteAccess ze zvukové vyrovnávací paměti voláním metody CreateReference.
- Získejte ukazatel k nezpracovaným datům zvukové vyrovnávací paměti voláním metody IMemoryBufferByteAccess.GetBuffer a převeďte jej na datový typ vzorků zvukových dat.
Propojení uzlů a uzly dílčího mixu
Všechny typy vstupních uzlů zveřejňují metodu AddOutgoingConnection , která směruje zvuk vytvořený uzlem do uzlu, který je předán do metody. Následující příklad připojí AudioFileInputNode k AudioDeviceOutputNode, což je jednoduché nastavení pro přehrávání zvukového souboru na reproduktoru zařízení.
fileInputNode.AddOutgoingConnection(deviceOutputNode);
Můžete vytvořit více než jedno připojení ze vstupního uzlu k jiným uzlům. Následující příklad přidá další připojení z AudioFileInputNode do AudioFileOutputNode. Teď se zvuk ze zvukového souboru přehraje do reproduktoru zařízení a zapíše se také do zvukového souboru.
fileInputNode.AddOutgoingConnection(fileOutputNode);
Výstupní uzly můžou také přijímat více než jedno připojení z jiných uzlů. V následujícím příkladu je připojení provedeno z AudioDeviceInputNode k uzlu AudioDeviceOutput. Vzhledem k tomu, že výstupní uzel obsahuje připojení ze vstupního uzlu souboru a vstupního uzlu zařízení, bude výstup obsahovat kombinaci zvuku z obou zdrojů. AddOutgoingConnection má přetíženou verzi, která umožňuje zadat hodnotu zesílení pro signál procházející tímto připojením.
deviceInputNode.AddOutgoingConnection(deviceOutputNode, .5);
I když výstupní uzly můžou přijímat připojení z více uzlů, můžete před předáním mixu do výstupu vytvořit mezilehlou kombinaci signálů z jednoho nebo více uzlů. Můžete například chtít nastavit úroveň nebo použít efekty u podmnožiny zvukových signálů v grafu. K tomu použijte AudioSubmixNode. K uzlu submixu můžete připojit jeden nebo více vstupních uzlů či jiných uzlů submixu. V následujícím příkladu se vytvoří nový uzel submix s AudioGraph.CreateSubmixNode. Poté se přidají připojení z uzlu souborového vstupu a uzlu vstupu snímků do uzlu submix. Nakonec je uzel submixu připojený k výstupnímu uzlu souboru.
private void CreateSubmixNode()
{
AudioSubmixNode submixNode = audioGraph.CreateSubmixNode();
fileInputNode.AddOutgoingConnection(submixNode);
frameInputNode.AddOutgoingConnection(submixNode);
submixNode.AddOutgoingConnection(fileOutputNode);
}
Spouštění a zastavování uzlů zvukového grafu
Při volání AudioGraph.Start začne zvukový graf zpracovávat zvuková data. Každý typ uzlu poskytuje metody Start a Stop , které způsobují spuštění nebo zastavení zpracování dat jednotlivého uzlu. Při volání AudioGraph.Stop se veškeré zpracování zvuku ve všech uzlech zastaví bez ohledu na stav jednotlivých uzlů, ale stav každého uzlu lze nastavit, když je zvukový graf zastavený. Můžete například volat Stop na jednotlivém uzlu, když je graf zastavený, a pak volat AudioGraph.Start a jednotlivé uzly zůstanou v zastaveném stavu.
Všechny typy uzlů zveřejňují vlastnost ConsumeInput , která při nastavení na hodnotu false umožňuje uzlu pokračovat ve zpracování zvuku, ale zastaví ho v využívání všech zvukových dat vstupních z jiných uzlů.
Všechny typy uzlů zpřístupňují metodu resetování , která způsobí, že uzel zahodí všechna zvuková data, která jsou aktuálně v jeho vyrovnávací paměti.
Přidání zvukových efektů
Rozhraní API pro zvukové grafy umožňuje přidat zvukové efekty do každého typu uzlu v grafu. Výstupní uzly, vstupní uzly a submixové uzly můžou mít neomezený počet zvukových efektů, které jsou omezené jenom možnostmi hardwaru. Následující příklad ukazuje přidání integrovaného efektu echo do submix uzlu.
EchoEffectDefinition echoEffect = new EchoEffectDefinition(audioGraph);
echoEffect.Delay = 1000.0;
echoEffect.Feedback = .2;
echoEffect.WetDryMix = .5;
submixNode.EffectDefinitions.Add(echoEffect);
- Všechny zvukové efekty implementují IAudioEffectDefinition. Každý uzel zveřejňuje vlastnost EffectDefinitions představující seznam efektů použitých na tento uzel. Přidejte efekt přidáním objektu definice do seznamu.
- V oboru názvů Windows.Media.Audio je k dispozici několik tříd definic efektů. Patří mezi ně:
- Můžete vytvořit vlastní zvukové efekty, které implementují IAudioEffectDefinition a aplikují je na libovolný uzel ve zvukovém grafu.
- Každý typ uzlu poskytuje metodu DisableEffectsByDefinition, která zakáže všechny efekty v seznamu EffectDefinitions uzlu, které byly přidány pomocí zadané definice. EnableEffectsByDefinition umožňuje efekty se zadanou definicí.
Prostorový zvuk
AudioGraph podporuje prostorový zvuk, který umožňuje zadat umístění v prostorovém prostoru, ze kterého se vygeneruje zvuk z jakéhokoli vstupu nebo submixního uzlu. Můžete také určit obrazec a směr, ve kterém se zvuk vysílá, rychlost, která se použije k posunu zvuku uzlu doppleru, a definovat model rozkladu, který popisuje, jak je zvuk ztlumený vzdáleností.
Pokud chcete vytvořit emitér, můžete nejprve vytvořit obrazec, ve kterém se zvuk promítá z emitoru, což může být kužel nebo všesměrový. Třída AudioNodeEmitterShape poskytuje statické metody pro vytváření jednotlivých obrazců. V dalším kroku vytvořte model rozkladu. To definuje, jak se s rostoucí vzdáleností od naslouchacího procesu snižuje hlasitost zvuku z emitéru. CreateNatural metoda vytvoří model rozpadu, který emuluje přirozený rozklad zvuku pomocí modelu odmocniny vzdálenosti. Nakonec vytvořte objekt AudioNodeEmitterSettings. V současné době tento objekt slouží pouze k zapnutí a vypnutí Dopplerova útlumu zdroje zvuku založeného na rychlosti. Zavolejte konstruktor AudioNodeEmitter a předejte mu inicializační objekty, které jste právě vytvořili. Ve výchozím nastavení je emitor umístěn na původu, ale můžete nastavit pozici emitoru s vlastností Position .
Note
Emitory zvukového uzlu mohou zpracovávat pouze zvuk, který je formátován v mono s vzorkovací rychlostí 48kHz. Při pokusu o použití stereofonního zvuku nebo zvuku s jinou vzorkovací frekvencí dojde k výjimce.
Emitor přiřadíte ke zvukovému uzlu při jeho vytvoření pomocí přetížené metody pro vytvoření typu uzlu, který chcete. V tomto příkladu: CreateFileInputNodeAsync slouží k vytvoření vstupního uzlu souboru ze zadaného souboru a objektu AudioNodeEmitter objekt, který chcete přidružit k uzlu.
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;
Objekt AudioDeviceOutputNode, který vydává zvuk z grafu uživateli, má objekt listeneru, k němuž se přistupuje pomocí vlastnosti Listener, která představuje umístění, orientaci a rychlost uživatele v trojrozměrném prostoru. Pozice všech emitorů v grafu jsou relativní vzhledem k pozici a orientaci objektu naslouchacího procesu. Ve výchozím nastavení se posluchač nachází v počátku (0,0,0) a je orientován dopředu podél osy Z, ale jeho polohu a orientaci můžete nastavit pomocí vlastností Position a Orientation.
deviceOutputNode.Listener.Position = new Vector3(100, 0, 0);
deviceOutputNode.Listener.Orientation = Quaternion.CreateFromYawPitchRoll(0, (float)Math.PI, 0);
Umístění, rychlost a směr emitorů za běhu můžete aktualizovat, abyste simulovali pohyb zvukového zdroje prostřednictvím 3D prostoru.
AudioNodeEmitter emitter = fileInputNode.Emitter;
emitter.Position = newObjectPosition;
emitter.DopplerVelocity = newObjectPosition - oldObjectPosition;
Můžete také aktualizovat umístění, rychlost a orientaci objektu naslouchacího procesu za běhu, abyste simulovali pohyb uživatele prostřednictvím 3D prostoru.
deviceOutputNode.Listener.Position = newUserPosition;
Ve výchozím nastavení se prostorový zvuk vypočítává pomocí algoritmu HRTF (head-related transfer function) společnosti Microsoft, který upravuje zvuk na základě jeho tvaru, rychlosti a polohy vzhledem k posluchači. Vlastnost SpatialAudioModel můžete nastavit na FoldDown , abyste použili jednoduchou stereo mix metodu simulace prostorového zvuku, která je méně přesná, ale vyžaduje méně prostředků procesoru a paměti.
Viz také
Windows developer