Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Artikel ini menunjukkan cara menggunakan API di namespace Windows.Media.Audio untuk membuat graf audio untuk skenario perutean, pencampuran, dan pemrosesan audio.
Grafik audio adalah sekumpulan simpul audio yang saling terhubung di mana data audio mengalir.
Simpul input audio menyediakan data audio ke grafik dari perangkat input audio, file audio, atau dari kode kustom.
Simpul output audio adalah tujuan untuk audio yang diproses oleh grafik. Audio dapat dirutekan dari grafik ke perangkat output audio, file audio, atau kode kustom.
Simpul submix mengambil audio dari satu atau beberapa simpul dan menggabungkannya ke dalam satu output yang dapat dirutekan ke simpul lain dalam grafik.
Setelah semua simpul dibuat dan koneksi di antaranya disiapkan, Anda cukup memulai grafik audio dan data audio mengalir dari simpul input, melalui simpul submiks apa pun, ke simpul output. Model ini membuat skenario seperti merekam dari mikrofon perangkat ke file audio, memutar audio dari file ke speaker perangkat, atau mencampur audio dari beberapa sumber dengan cepat dan mudah diimplementasikan.
Skenario tambahan diaktifkan dengan penambahan efek audio ke grafik audio. Setiap simpul dalam grafik audio dapat diisi dengan nol atau lebih efek audio yang melakukan pemrosesan audio pada audio yang melewati simpul. Ada beberapa efek bawaan seperti echo, equalizer, limiting, dan reverb yang dapat dilampirkan ke simpul audio hanya dengan beberapa baris kode. Anda juga dapat membuat efek audio kustom Anda sendiri yang berfungsi persis sama dengan efek bawaan.
Memilih Windows Runtime AudioGraph atau XAudio2
API grafik audio Windows Runtime menawarkan fungsionalitas yang juga dapat diimplementasikan dengan menggunakan API XAudio2 berbasis COM. Berikut ini adalah fitur kerangka kerja grafik audio Windows Runtime yang berbeda dari XAudio2.
API grafik audio Windows Runtime:
- Secara signifikan lebih mudah digunakan daripada XAudio2.
- Dapat digunakan dari C# selain didukung untuk C++.
- Dapat menggunakan file audio, termasuk format file terkompresi, secara langsung. XAudio2 hanya beroperasi pada buffer audio dan tidak menyediakan kemampuan I/O file apa pun.
- Dapat menggunakan alur audio latensi rendah di Windows.
- Mendukung peralihan titik akhir otomatis saat parameter titik akhir default digunakan. Misalnya, jika pengguna beralih dari speaker perangkat ke headset, audio secara otomatis dialihkan ke output baru.
Kelas AudioGraph
Kelas AudioGraph adalah induk dari semua simpul yang membentuk grafik. Gunakan objek ini untuk membuat instans dari semua jenis simpul audio. Buat instans kelas AudioGraph dengan menginisialisasi objek AudioGraphSettings yang berisi pengaturan konfigurasi untuk grafik, lalu panggil AudioGraph.CreateAsync. CreateAudioGraphResult yang dikembalikan memberikan akses ke grafik audio yang dibuat atau memberikan nilai kesalahan jika pembuatan grafik audio gagal.
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;
}
Semua jenis node audio dibuat dengan menggunakan metode Create* dari kelas AudioGraph .
Metode AudioGraph.Start menyebabkan grafik audio mulai memproses data audio. Metode AudioGraph.Stop menghentikan pemrosesan audio. Setiap simpul dalam grafik dapat dimulai dan dihentikan secara independen saat grafik berjalan, tetapi tidak ada simpul yang aktif saat grafik dihentikan. ResetAllNodes menyebabkan semua simpul dalam grafik membuang data apa pun yang saat ini ada di buffer audio mereka.
Peristiwa QuantumStarted terjadi ketika grafik memulai pemrosesan kuantum data audio baru. Peristiwa QuantumProcessed terjadi ketika pemrosesan kuantum selesai.
Satu-satunya properti AudioGraphSettings yang diperlukan adalah AudioRenderCategory. Menentukan nilai ini memungkinkan sistem mengoptimalkan alur audio untuk kategori yang ditentukan.
Ukuran kuantum grafik audio menentukan jumlah sampel yang diproses pada satu waktu. Secara bawaan, ukuran kuantum adalah 10 ms pada laju sampel default. Jika Anda menentukan ukuran kuantum kustom dengan mengatur properti DesiredSamplesPerQuantum , Anda juga harus mengatur properti QuantumSizeSelectionMode ke ClosestToDesired atau nilai yang disediakan diabaikan. Jika nilai ini digunakan, sistem akan memilih ukuran kuantum sedekat mungkin dengan yang Anda tentukan. Untuk menentukan ukuran kuantum aktual, periksa SamplesPerQuantum dari AudioGraph setelah dibuat.
Jika Anda hanya berencana untuk menggunakan grafik audio dengan file dan tidak berencana untuk menghasilkan ke perangkat audio, disarankan agar Anda menggunakan ukuran kuantum default dengan tidak mengatur properti DesiredSamplesPerQuantum .
Properti DesiredRenderDeviceAudioProcessing menentukan jumlah pemrosesan yang dilakukan perangkat render utama pada output grafik audio. Pengaturan Default memungkinkan sistem menggunakan pemrosesan audio default untuk kategori render audio yang ditentukan. Pemrosesan ini dapat secara signifikan meningkatkan suara audio di beberapa perangkat, terutama perangkat seluler dengan speaker kecil. Pengaturan Mentah dapat meningkatkan performa dengan meminimalkan jumlah pemrosesan sinyal yang dilakukan, tetapi dapat mengakibatkan kualitas suara yang lebih rendah pada beberapa perangkat.
Jika QuantumSizeSelectionMode diatur ke LowestLatency, grafik audio akan secara otomatis menggunakan Raw untuk DesiredRenderDeviceAudioProcessing.
Anda dapat mengatur properti AudioGraphSettings.MaxPlaybackSpeedFactor untuk mengatur nilai maksimum yang digunakan untuk properti AudioFileInputNode.PlaybackSpeedFactor, AudioFrameInputNode.PlaybackSpeedFactor, dan MediaSourceInputNode.PlaybackSpeedFactor . Ketika grafik audio mendukung faktor kecepatan pemutaran yang lebih besar dari 1, sistem harus mengalokasikan memori tambahan untuk mempertahankan buffer data audio yang memadai. Untuk alasan ini, mengatur MaxPlaybackSpeedFactor ke nilai terendah yang diperlukan oleh aplikasi Anda akan mengurangi konsumsi memori aplikasi Anda. Jika aplikasi Anda hanya akan memutar konten dengan kecepatan normal, disarankan agar Anda mengatur MaxPlaybackSpeedFactor ke 1.
EncodingProperties menentukan format audio yang digunakan oleh grafik. Hanya format float 32-bit yang didukung.
PrimaryRenderDevice mengatur perangkat render utama untuk grafik audio. Jika Anda tidak mengatur ini, perangkat sistem default akan digunakan. Perangkat render utama digunakan untuk menghitung ukuran kuantum untuk simpul lain dalam grafik. Jika tidak ada perangkat render audio yang ada di sistem, pembuatan grafik audio akan gagal.
Anda dapat membiarkan grafik audio menggunakan perangkat render audio default atau menggunakan kelas Windows.Devices.Enumeration.DeviceInformation untuk mendapatkan daftar perangkat render audio yang tersedia pada sistem dengan memanggil FindAllAsync dan meneruskan pemilih perangkat render audio yang dikembalikan oleh Windows.Media.Devices.MediaDevice.GetAudioRenderSelector. Anda dapat memilih salah satu objek DeviceInformation yang dikembalikan secara terprogram atau menampilkan UI untuk memungkinkan pengguna memilih perangkat lalu menggunakannya untuk mengatur properti 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;
Node input perangkat
Simpul input perangkat menyalurkan audio ke dalam grafik dari perangkat pengambilan audio yang terhubung ke sistem, seperti mikrofon. Buat objek DeviceInputNode yang menggunakan perangkat penangkapan audio default sistem dengan memanggil CreateDeviceInputNodeAsync. Berikan MediaCategory untuk memungkinkan sistem mengoptimalkan alur audio untuk kategori yang ditentukan.
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;
}
Jika Anda ingin menentukan perangkat perekam audio tertentu untuk node input perangkat, Anda dapat menggunakan kelas Windows.Devices.Enumeration.DeviceInformation untuk mendapatkan daftar perangkat perekam audio yang tersedia di sistem dengan memanggil FindAllAsync dan meneruskan selektor perangkat perekam audio yang dikembalikan oleh Windows.Media.Devices.MediaDevice.GetAudioCaptureSelector. Anda dapat memilih salah satu objek DeviceInformation yang dikembalikan secara terprogram atau menampilkan UI untuk memungkinkan pengguna memilih perangkat lalu meneruskannya ke 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);
Node keluaran perangkat
Simpul output perangkat mendorong audio dari grafik ke perangkat render audio, seperti speaker atau headset. Buat DeviceOutputNode dengan memanggil CreateDeviceOutputNodeAsync. Node output menggunakan PrimaryRenderDevice dari graf audio.
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;
}
Node input berkas
Simpul input file memungkinkan Anda untuk memberi umpan data dari file audio ke dalam grafik. Buat AudioFileInputNode dengan memanggil 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;
}
- Simpul input file mendukung format file berikut: mp3, wav, wma, m4a.
- Atur properti StartTime untuk menentukan offset waktu ke dalam file tempat pemutaran harus dimulai. Jika properti ini null, awal file digunakan. Atur properti EndTime untuk menentukan offset waktu ke dalam file di mana pemutaran harus berakhir. Jika properti ini null, akhir file akan digunakan. Nilai waktu mulai harus lebih rendah dari nilai waktu akhir, dan nilai waktu akhir harus kurang dari atau sama dengan durasi file audio, yang dapat ditentukan dengan memeriksa nilai properti Durasi .
- Cari ke posisi dalam file audio dengan memanggil Cari dan tentukan offset waktu ke dalam file tempat posisi pemutaran harus dipindahkan. Nilai yang ditentukan harus berada dalam rentang StartTime dan EndTime . Dapatkan posisi pemutaran saat ini dari simpul dengan properti Position yang bersifat baca-saja.
- Aktifkan perulangan file audio dengan mengatur properti LoopCount . Ketika non-null, nilai ini menunjukkan berapa kali file akan diputar setelah pemutaran awal. Jadi, misalnya, mengatur LoopCount ke 1 akan menyebabkan file diputar total 2 kali, dan mengaturnya ke 5 akan menyebabkan file diputar 6 kali secara total. Mengatur LoopCount ke null menyebabkan file diulang tanpa batas waktu. Untuk menghentikan perulangan, atur nilai ke 0.
- Sesuaikan kecepatan di mana file audio diputar kembali dengan mengatur PlaybackSpeedFactor. Nilai 1 menunjukkan kecepatan asli file, .5 adalah setengah kecepatan, dan 2 adalah kecepatan ganda.
Node input MediaSource
Kelas MediaSource menyediakan cara umum untuk mereferensikan media dari sumber yang berbeda dan mengekspos model umum untuk mengakses data media terlepas dari format media yang mendasar, yang bisa menjadi file pada disk, aliran, atau sumber jaringan streaming adaptif. Simpul MediaSourceAudioInputNode memungkinkan Anda mengarahkan data audio dari MediaSource ke grafik audio. Buat MediaSourceAudioInputNode dengan memanggil CreateMediaSourceAudioInputNodeAsync, meneruskan objek MediaSource yang mewakili konten yang ingin Anda putar. CreateMediaSourceAudioInputNodeResult dikembalikan yang dapat Anda gunakan untuk menentukan status operasi dengan memeriksa properti Status. Jika statusnya adalah Berhasil, Anda bisa mendapatkan MediaSourceAudioInputNode yang dibuat dengan mengakses properti Node . Contoh berikut menunjukkan pembuatan simpul dari objek AdaptiveMediaSource yang mewakili streaming konten melalui jaringan.
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;
}
Untuk menerima pemberitahuan ketika pemutaran telah mencapai akhir konten MediaSource , daftarkan handler untuk peristiwa MediaSourceCompleted .
mediaSourceInputNode.MediaSourceCompleted += MediaSourceInputNode_MediaSourceCompleted;
private void MediaSourceInputNode_MediaSourceCompleted(MediaSourceAudioInputNode sender, object args)
{
audioGraph.Stop();
}
Meskipun pemutaran file dari disk kemungkinan besar akan selalu berhasil, media yang di-streaming dari sumber jaringan dapat gagal saat pemutaran karena perubahan koneksi jaringan atau masalah lain yang berada di luar kendali audio graph. Jika MediaSource menjadi tidak dapat diputar selama pemutaran, graf audio akan memicu peristiwa UnrecoverableErrorOccurred. Anda dapat menggunakan handler untuk kejadian ini untuk menghentikan dan membuang grafik audio lalu menginisialisasi ulang grafik Anda.
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();
}
}
Node output file
Simpul output file memungkinkan Anda mengarahkan data audio dari grafik ke dalam file audio. Buat AudioFileOutputNode dengan memanggil 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;
}
- Simpul output file mendukung format file berikut: mp3, wav, wma, m4a.
- Anda harus memanggil AudioFileOutputNode.Stop untuk menghentikan pemrosesan simpul sebelum memanggil AudioFileOutputNode.FinalizeAsync atau pengecualian akan dilemparkan.
Node input untuk bingkai audio
Node input frame audio memungkinkan Anda memasukkan data audio yang Anda buat sendiri melalui kode Anda ke dalam grafik audio. Ini memungkinkan skenario seperti membuat synthesizer perangkat lunak kustom. Buat AudioFrameInputNode dengan memanggil 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;
}
Peristiwa FrameInputNode.QuantumStarted dinaikkan ketika grafik audio siap untuk mulai memproses kuantum data audio berikutnya. Anda menyediakan data audio kustom yang Anda hasilkan melalui handler ke event ini.
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);
}
}
- Objek FrameInputNodeQuantumStartedEventArgs yang diteruskan ke penanganan aktivitas QuantumStarted mengekspos properti RequiredSamples yang menunjukkan berapa banyak sampel grafik audio yang perlu mengisi kuantum yang akan diproses.
- Panggil AudioFrameInputNode.AddFrame untuk meneruskan objek AudioFrame yang diisi dengan data audio ke dalam grafik.
- Anda dapat menggunakan MediaFrameReader dengan data audio untuk mendapatkan objek AudioFrame dari sumber bingkai media, yang dapat diteruskan ke FrameInputNode menggunakan metode AddFrame .
- Contoh implementasi metode pembantu GenerateAudioData ditunjukkan di bawah ini.
Untuk mengisi AudioFrame dengan data audio, Anda harus mendapatkan akses ke buffer memori yang mendasar dari bingkai audio. Untuk melakukan ini, inisialisasi antarmuka COM IMemoryBufferByteAccess seperti yang ditunjukkan di bawah ini.
[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
void GetBuffer(out byte* buffer, out uint capacity);
}
Kode berikut menunjukkan contoh implementasi metode pembantu GenerateAudioData yang membuat AudioFrame dan mengisinya dengan data audio.
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;
}
- Karena metode ini mengakses buffer mentah yang mendasari tipe Windows Runtime, metode ini harus dideklarasikan menggunakan kata kunci unsafe. Anda juga harus mengonfigurasi proyek Anda di Microsoft Visual Studio untuk mengizinkan kompilasi kode tidak aman dengan membuka halaman Properti proyek, mengklik halaman properti Build, dan memilih kotak centang Izinkan Kode Tidak Aman.
- Inisialisasi instans baru AudioFrame dalam namespace Windows.Media dengan memberikan ukuran buffer yang diinginkan ke dalam konstruktor. Ukuran buffer adalah jumlah sampel yang dikalikan dengan ukuran setiap sampel.
- Dapatkan AudioBuffer dari bingkai audio dengan memanggil LockBuffer.
- Dapatkan instans antarmuka COM IMemoryBufferByteAccess dari buffer audio dengan memanggil CreateReference.
- Dapatkan pointer ke data buffer audio mentah dengan memanggil IMemoryBufferByteAccess.GetBuffer dan konversikan ke tipe data sampel audio.
- Isi buffer dengan data dan kembalikan AudioFrame untuk pengiriman ke grafik audio.
Node keluaran frame audio
Simpul output bingkai audio memungkinkan Anda menerima dan memproses output data audio dari grafik audio dengan kode kustom yang Anda buat. Contoh skenario untuk ini adalah melakukan analisis sinyal pada output audio. Buat AudioFrameOutputNode dengan memanggil CreateFrameOutputNode.
AudioFrameOutputNode frameOutputNode;
private void CreateFrameOutputNode()
{
frameOutputNode = audioGraph.CreateFrameOutputNode();
audioGraph.QuantumStarted += AudioGraph_QuantumStarted;
}
Peristiwa AudioGraph.QuantumStarted dipicu ketika graf audio mulai memproses satu kuantum data audio. Anda dapat mengakses data audio dari dalam handler untuk kejadian ini.
Note
Jika Anda ingin mengambil frame audio secara berkala, disinkronkan dengan graf audio, panggil AudioFrameOutputNode.GetFrame dari dalam penangan peristiwa sinkron QuantumStarted. Peristiwa QuantumProcessed dimunculkan secara asinkron setelah mesin audio menyelesaikan pemrosesan audio, yang berarti iramanya mungkin tidak teratur. Oleh karena itu, Anda tidak boleh menggunakan peristiwa QuantumProcessed untuk pemrosesan data bingkai audio yang disinkronkan.
private void AudioGraph_QuantumStarted(AudioGraph sender, object args)
{
AudioFrame frame = frameOutputNode.GetFrame();
ProcessFrameOutput(frame);
}
- Panggil GetFrame untuk mendapatkan objek AudioFrame yang diisi dengan data audio dari grafik.
- Contoh implementasi metode pembantu ProcessFrameOutput ditunjukkan di bawah ini.
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;
}
}
- Seperti contoh node input bingkai audio di atas, Anda harus mendeklarasikan antarmuka IMemoryBufferByteAccess COM dan mengonfigurasi proyek Anda untuk memungkinkan kode yang tidak aman untuk mengakses buffer audio yang mendasar.
- Dapatkan AudioBuffer dari bingkai audio dengan memanggil LockBuffer.
- Dapatkan instance antarmuka COM IMemoryBufferByteAccess dari buffer audio dengan memanggil CreateReference.
- Dapatkan penunjuk ke data buffer audio mentah dengan memanggil IMemoryBufferByteAccess.GetBuffer dan konversikan ke jenis data sampel dari data audio tersebut.
Koneksi node dan simpul submix
Semua jenis node input mengekspos metode AddOutgoingConnection yang merutekan audio yang dihasilkan oleh simpul ke simpul yang diteruskan ke metode . Contoh berikut menghubungkan AudioFileInputNode ke AudioDeviceOutputNode, yang merupakan penyiapan sederhana untuk memutar file audio di speaker perangkat.
fileInputNode.AddOutgoingConnection(deviceOutputNode);
Anda dapat membuat lebih dari satu koneksi dari simpul input ke simpul lain. Contoh berikut menambahkan koneksi lain dari AudioFileInputNode ke AudioFileOutputNode. Sekarang, audio dari file audio diputar melalui speaker perangkat dan juga disimpan ke file audio.
fileInputNode.AddOutgoingConnection(fileOutputNode);
Simpul output juga dapat menerima lebih dari satu koneksi dari simpul lain. Dalam contoh berikut, koneksi dibuat dari AudioDeviceInputNode ke simpul AudioDeviceOutput . Karena simpul output memiliki koneksi dari simpul input file dan node input perangkat, output akan berisi campuran audio dari kedua sumber. AddOutgoingConnection menyediakan kelebihan beban yang memungkinkan Anda menentukan nilai keuntungan untuk sinyal yang melewati koneksi.
deviceInputNode.AddOutgoingConnection(deviceOutputNode, .5);
Meskipun simpul output dapat menerima koneksi dari beberapa simpul, Anda mungkin ingin membuat campuran sinyal perantara dari satu atau beberapa simpul sebelum meneruskan campuran ke output. Misalnya, Anda mungkin ingin mengatur tingkat atau menerapkan efek ke subset sinyal audio dalam grafik. Untuk melakukan ini, gunakan AudioSubmixNode. Anda dapat terhubung ke simpul submix dari satu atau beberapa simpul input atau simpul submix lainnya. Dalam contoh berikut, simpul submix baru dibuat dengan AudioGraph.CreateSubmixNode. Kemudian, koneksi ditambahkan dari simpul masukan berkas dan simpul masukan frame ke simpul submix. Akhirnya, simpul submix terhubung ke simpul output file.
private void CreateSubmixNode()
{
AudioSubmixNode submixNode = audioGraph.CreateSubmixNode();
fileInputNode.AddOutgoingConnection(submixNode);
frameInputNode.AddOutgoingConnection(submixNode);
submixNode.AddOutgoingConnection(fileOutputNode);
}
Memulai dan menghentikan simpul grafik audio
Saat AudioGraph.Start dipanggil, grafik audio mulai memproses data audio. Setiap jenis node menyediakan metode Mulai dan Hentikan yang menyebabkan node individual memulai atau berhenti memproses data. Ketika AudioGraph.Stop dipanggil, semua pemrosesan audio di semua simpul dihentikan terlepas dari status simpul individual, tetapi status setiap simpul dapat diatur saat grafik audio dihentikan. Misalnya, Anda dapat memanggil Hentikan pada simpul individual saat grafik dihentikan lalu memanggil AudioGraph.Start, dan simpul individual akan tetap dalam status berhenti.
Semua jenis node mengekspos properti ConsumeInput yang, ketika diatur ke false, memungkinkan node untuk melanjutkan pemrosesan audio tetapi menghentikannya untuk mengonsumsi data audio apa pun yang dimasukkan dari simpul lain.
Semua jenis node mengekspos metode Reset yang menyebabkan node membuang data audio apa pun yang saat ini ada di buffernya.
Menambahkan efek audio
API grafik audio memungkinkan Anda menambahkan efek audio ke setiap jenis simpul dalam grafik. Simpul output, simpul input, dan simpul submiks masing-masing dapat memiliki jumlah efek audio yang tidak terbatas, hanya dibatasi oleh kemampuan perangkat keras. Contoh berikut menunjukkan penambahan efek gema bawaan ke simpul submix.
EchoEffectDefinition echoEffect = new EchoEffectDefinition(audioGraph);
echoEffect.Delay = 1000.0;
echoEffect.Feedback = .2;
echoEffect.WetDryMix = .5;
submixNode.EffectDefinitions.Add(echoEffect);
- Semua efek audio mengimplementasikan IAudioEffectDefinition. Setiap simpul mengekspos properti EffectDefinitions yang mewakili daftar efek yang diterapkan pada simpul tersebut. Tambahkan efek dengan menambahkan objek definisinya ke daftar.
- Ada beberapa kelas definisi efek yang disediakan dalam namespace Windows.Media.Audio. Ini termasuk:
- Anda dapat membuat efek audio Anda sendiri yang mengimplementasikan IAudioEffectDefinition dan menerapkannya ke node apa pun dalam grafik audio.
- Setiap jenis node mengekspos metode DisableEffectsByDefinition yang menonaktifkan semua efek dalam daftar EffectDefinitions node yang ditambahkan menggunakan definisi yang ditentukan. EnableEffectsByDefinition memungkinkan efek dengan definisi yang ditentukan.
Audio spasial
AudioGraph mendukung audio spasial, yang memungkinkan Anda menentukan lokasi dalam ruang 3D tempat audio dari input atau simpul submix dipancarkan. Anda juga dapat menentukan bentuk dan arah pancaran audio, kecepatan yang akan digunakan untuk menggeser audio simpul akibat efek Doppler, serta menentukan model peluruhan yang menjelaskan bagaimana audio diredam seiring bertambahnya jarak.
Untuk membuat emiter, Anda dapat terlebih dahulu membuat bentuk di mana suara diproyeksikan dari emiter, yang dapat berupa kerucut atau omnidirectional. Kelas AudioNodeEmitterShape menyediakan metode statis untuk membuat masing-masing bentuk ini. Selanjutnya, buat model peluruhan. Ini mendefinisikan bagaimana volume audio dari emiter menurun saat jarak dari pendengar meningkat. Metode CreateNatural membuat model peluruhan yang meniru peluruhan alami suara menggunakan model penurunan berdasarkan kuadrat jarak. Terakhir, buat objek AudioNodeEmitterSettings . Saat ini, objek ini hanya digunakan untuk mengaktifkan dan menonaktifkan redaman Doppler berbasis kecepatan audio pemancar. Panggil konstruktor AudioNodeEmitter, dengan meneruskan objek-objek inisialisasi yang baru saja Anda buat. Secara default, emiter ditempatkan di asal, tetapi Anda dapat mengatur posisi emiter dengan properti Posisi .
Note
Pemancar simpul audio hanya dapat memproses audio yang diformat dalam mono dengan laju sampel 48kHz. Upaya untuk menggunakan audio stereo atau audio dengan laju sampel yang berbeda akan menyebabkan pengecualian.
Anda menetapkan pemancar ke simpul audio saat membuatnya dengan menggunakan metode pembuatan kelebihan beban untuk jenis simpul yang Anda inginkan. Dalam contoh ini, CreateFileInputNodeAsync digunakan untuk membuat simpul input file dari file tertentu dan objek AudioNodeEmitter yang ingin Anda kaitkan dengan simpul.
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 yang menghasilkan audio dari grafik ke pengguna memiliki objek pendengar, diakses dengan properti Listener, yang mewakili lokasi, orientasi, dan kecepatan pengguna di ruang 3D. Posisi semua emiter dalam grafik relatif terhadap posisi dan orientasi objek pendengar. Secara default, listener terletak di asal (0,0,0) menghadap ke depan di sepanjang sumbu Z, tetapi Anda dapat mengatur posisi dan orientasinya dengan properti Posisi dan Orientasi .
deviceOutputNode.Listener.Position = new Vector3(100, 0, 0);
deviceOutputNode.Listener.Orientation = Quaternion.CreateFromYawPitchRoll(0, (float)Math.PI, 0);
Anda dapat memperbarui lokasi, kecepatan, dan arah emitor pada runtime untuk mensimulasikan pergerakan sumber audio melalui ruang 3D.
AudioNodeEmitter emitter = fileInputNode.Emitter;
emitter.Position = newObjectPosition;
emitter.DopplerVelocity = newObjectPosition - oldObjectPosition;
Anda juga dapat memperbarui lokasi, kecepatan, dan orientasi objek pendengar pada runtime untuk mensimulasikan pergerakan pengguna melalui ruang 3D.
deviceOutputNode.Listener.Position = newUserPosition;
Secara default, audio spasial dihitung menggunakan algoritma fungsi transfer relatif kepala (HRTF) Microsoft untuk meredakan audio berdasarkan bentuk, kecepatan, dan posisinya relatif terhadap pendengar. Anda dapat mengatur properti SpatialAudioModel ke FoldDown untuk menggunakan metode campuran stereo sederhana untuk mensimulasikan audio spasial yang kurang akurat tetapi membutuhkan lebih sedikit sumber daya CPU dan memori.
Baca juga
Windows developer