Ses grafikleri

Bu makalede, Windows içindeki API'lerin nasıl kullanılacağı gösterilmektedir. Media.Audio ad alanı, ses yönlendirme, karıştırma ve işleme senaryolarına yönelik ses grafikleri oluşturur.

Ses grafı, ses verilerinin aktığı birbirine bağlı ses düğümleri kümesidir.

  • Ses giriş düğümleri ses giriş cihazlarından, ses dosyalarından veya özel koddan grafiğe ses verileri sağlar.

  • Ses çıkış düğümleri , grafik tarafından işlenen sesin hedefidir. Ses, grafın dışına ses çıkış cihazlarına, ses dosyalarına veya özel koda yönlendirilebilir.

  • Alt düğümler bir veya daha fazla düğümden ses alır ve bunları grafikteki diğer düğümlere yönlendirilebilen tek bir çıkışta birleştirir.

Tüm düğümler oluşturulduktan ve aralarındaki bağlantılar ayarlandıktan sonra, ses grafiğini başlatmanız ve ses verilerinin giriş düğümlerinden herhangi bir alt düğüm aracılığıyla çıkış düğümlerine akması yeterlidir. Bu model, bir cihazın mikrofonundan ses dosyasına kaydetme, bir dosyadan cihazın hoparlöründen ses çalma veya birden çok kaynaktan gelen sesleri karıştırma gibi senaryoları hızlı ve kolay bir şekilde uygular.

Ek senaryolar, ses grafiğine ses efektleri eklenmesiyle etkinleştirilir. Ses grafiğindeki her düğüm, düğümden geçen ses üzerinde ses işleme gerçekleştiren sıfır veya daha fazla ses efektiyle doldurulabilir. Yalnızca birkaç satır kod içeren bir ses düğümüne bağlanabilen yankı, eşitleyici, sınırlama ve ters çevirme gibi çeşitli yerleşik efektler vardır. Ayrıca, yerleşik efektlerle tam olarak aynı şekilde çalışan kendi özel ses efektlerinizi de oluşturabilirsiniz.

Windows Çalışma Zamanı AudioGraph veya XAudio2'yi seçme

Windows Çalışma Zamanı ses grafiği API'leri, COM tabanlı XAudio2 API'leri kullanılarak da uygulanabilen işlevler sunar. XAudio2'den farklı Windows Çalışma Zamanı ses grafı çerçevesinin özellikleri aşağıdadır.

Windows Çalışma Zamanı ses grafı API'leri:

  • Kullanımı XAudio2'den önemli ölçüde daha kolaydır.
  • C++ için desteklenmenin yanı sıra C# dilinden de kullanılabilir.
  • Sıkıştırılmış dosya biçimleri dahil olmak üzere ses dosyalarını doğrudan kullanabilir. XAudio2 yalnızca ses arabellekleri üzerinde çalışır ve herhangi bir dosya G/Ç özelliği sunmaz.
  • Windows'da düşük gecikme süreli ses işlem hattını kullanabilir.
  • Varsayılan uç nokta parametreleri kullanıldığında otomatik uç nokta değiştirme desteği. Örneğin, kullanıcı cihazın hoparlöründen mikrofonlu kulaklığa geçerse ses otomatik olarak yeni çıkışa yönlendirilir.

AudioGraph sınıfı

AudioGraph sınıfı, grafiği oluşturan tüm düğümlerin üst öğesidir. Tüm ses düğümü türlerinin örneklerini oluşturmak için bu nesneyi kullanın. AudioGraphSettings grafik için yapılandırma ayarlarını içeren bir AudioGraph sınıfı örneği oluşturun, ve ardından AudioGraph.CreateAsync çağrısı yapın. Döndürülen CreateAudioGraphResult oluşturulan ses grafiğine erişim verir veya ses grafiği oluşturma başarısız olursa bir hata değeri sağlar.

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;
}
  • Tüm ses düğümü türleri , AudioGraph sınıfının Create* yöntemleri kullanılarak oluşturulur.

  • AudioGraph.Start yöntemi, ses grafiğinin ses verilerini işlemeye başlamasına neden olur. AudioGraph.Stop yöntemi ses işlemeyi durdurur. Grafik çalışırken grafikteki her düğüm bağımsız olarak başlatılabilir ve durdurulabilir, ancak grafik durdurulduğunda hiçbir düğüm etkin olmaz. ResetAllNodes , grafikteki tüm düğümlerin ses arabelleklerinde bulunan tüm verileri atmalarına neden olur.

  • QuantumStarted olayı, grafik yeni bir ses verisi kuantumunun işlenmesini başlatırken gerçekleşir. QuantumProcessed olayı, bir kuantumun işlenmesi tamamlandığında gerçekleşir.

  • Gereken tek AudioGraphSettings özelliği AudioRenderCategory'dir. Bu değerin belirtilmesi, sistemin belirtilen kategori için ses işlem hattını iyileştirmesine olanak tanır.

  • Ses grafiğinin kuantum boyutu, bir kerede işlenen örnek sayısını belirler. Varsayılan olarak, kuantum boyutu varsayılan örnek hızına göre 10 ms'dir. DesiredSamplesPerQuantum özelliğini ayarlayarak özel bir kuantum boyutu belirtirseniz, QuantumSizeSelectionMode özelliğini ClosestToDesired olarak da ayarlamanız gerekir; aksi takdirde sağlanan değer yoksayılır. Bu değer kullanılırsa, sistem belirttiğinize mümkün olduğunca yakın bir kuantum boyutu seçer. Gerçek kuantum boyutunu belirlemek için, oluşturulduktan sonra AudioGraph'ın SamplesPerQuantum'unu denetleyin.

  • Ses grafiğini yalnızca dosyalarla kullanmayı planlıyorsanız ve bir ses cihazına çıkış yapmayı planlamıyorsanız, DesiredSamplesPerQuantum özelliğini ayarlamayarak varsayılan kuantum boyutunu kullanmanız önerilir.

  • DesiredRenderDeviceAudioProcessing özelliği, birincil işleme cihazının ses grafiğinin çıkışında gerçekleştirdiği işleme miktarını belirler. Varsayılan ayarı, sistemin belirtilen ses işleme kategorisi için varsayılan ses işlemeyi kullanmasına olanak tanır. Bu işlem, özellikle küçük hoparlörlü mobil cihazlar olmak üzere bazı cihazlardaki sesin sesini önemli ölçüde iyileştirebilir. Ham ayarı, gerçekleştirilen sinyal işleme miktarını en aza indirerek performansı artırabilir, ancak bazı cihazlarda daha az ses kalitesine neden olabilir.

  • QuantumSizeSelectionModeLowestLatency olarak ayarlanırsa, ses grafiği DesiredRenderDeviceAudioProcessing için otomatik olarak Raw kullanır.

  • AudioGraphSettings.MaxPlaybackSpeedFactor özelliğini AudioFileInputNode.PlaybackSpeedFactor, AudioFrameInputNode.PlaybackSpeedFactor ve MediaSourceInputNode.PlaybackSpeedFactor özellikleri için kullanılan en yüksek değeri ayarlamak üzere ayarlayabilirsiniz. Bir ses grafiği 1'den büyük bir oynatma hızı katsayısını desteklediğinde, sistem yeterli bir ses verisi arabelleğini korumak için ek bellek ayırmalıdır. Bu nedenle MaxPlaybackSpeedFactor değerini uygulamanızın gerektirdiği en düşük değere ayarlamak uygulamanızın bellek tüketimini azaltır. Uygulamanız içeriği yalnızca normal hızda oynatacaksa MaxPlaybackSpeedFactor değerini 1 olarak ayarlamanız önerilir.

  • EncodingProperties, graf tarafından kullanılan ses biçimini belirler. Yalnızca 32 bit float biçimleri desteklenir.

  • PrimaryRenderDevice, ses grafı için birincil işleme cihazını ayarlar. Bunu ayarlamazsanız, varsayılan sistem cihazı kullanılır. Birincil işleme cihazı, grafikteki diğer düğümlerin kuantum boyutlarını hesaplamak için kullanılır. Sistemde ses işleme cihazı yoksa ses grafı oluşturma işlemi başarısız olur.

Ses grafiğinin varsayılan ses oluşturma cihazını kullanmasına izin verebilir veya Windows.Devices.Enumeration.DeviceInformation sınıfını kullanarak, FindAllAsync yöntemini çağırıp Windows.Media.Devices.MediaDevice.GetAudioRenderSelector tarafından döndürülen ses oluşturma cihazı seçicisini geçirerek sistemde kullanılabilen ses oluşturma cihazlarının listesini alabilirsiniz. Döndürülen DeviceInformation nesnelerinden birini program aracılığıyla seçebilir veya kullanıcının bir cihaz seçmesine izin vermek için kullanıcı arabirimini gösterebilir ve ardından PrimaryRenderDevice özelliğini ayarlamak için kullanabilirsiniz.

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;

Cihaz giriş düğümü

Cihaz giriş düğümü, mikrofon gibi sisteme bağlı bir ses yakalama cihazından grafiğe ses besler. Sistemin varsayılan ses yakalama cihazını kullanan bir DeviceInputNode nesnesi oluşturmak için CreateDeviceInputNodeAsync yöntemini çağırın. Sistemin belirtilen kategori için ses işlem hattını iyileştirmesine izin vermek için bir MediaCategory sağlayın.

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;
}

Cihaz giriş düğümü için belirli bir ses yakalama cihazı belirtmek istiyorsanız, Windows.Devices.Enumeration.DeviceInformation sınıfını kullanarak, Windows.Media.Devices.MediaDevice.GetAudioCaptureSelector tarafından döndürülen ses yakalama cihazı seçicisini geçirip FindAllAsync yöntemini çağırarak sistemde kullanılabilir ses yakalama cihazlarının listesini alabilirsiniz. Döndürülen DeviceInformation nesnelerinden birini program aracılığıyla seçebilir veya kullanıcının bir cihaz seçip createDeviceInputNodeAsync'e geçirmesine izin vermek için kullanıcı arabirimini gösterebilirsiniz.

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);

Cihaz çıkış düğümü

Cihaz çıkış düğümü, sesi grafikten hoparlör veya kulaklık gibi bir ses işleme cihazına iletir. CreateDeviceOutputNodeAsync çağrısı yaparak DeviceOutputNode oluşturun. Çıkış düğümü, ses grafiğinin PrimaryRenderDevice değerini kullanır.

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;
}

Dosya giriş düğümü

Dosya giriş düğümü, ses dosyasındaki verileri grafiğe beslemenizi sağlar. CreateFileInputNodeAsync çağrısı yaparak AudioFileInputNode oluşturun.

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;
}
  • Dosya giriş düğümleri şu dosya biçimlerini destekler: mp3, wav, wma, m4a.
  • Oynatmanın dosya içinde başlayacağı zaman uzaklığını belirtmek için StartTime özelliğini ayarlayın. Bu özellik null ise, dosyanın başlangıcı kullanılır. Oynatmanın sona ereceği dosya içindeki zaman uzaklığını belirtmek için EndTime özelliğini ayarlayın. Bu özellik null ise, dosyanın sonu kullanılır. Başlangıç zamanı değeri bitiş saati değerinden düşük olmalı ve bitiş saati değeri ses dosyasının süresinden küçük veya buna eşit olmalıdır. Bu değer Duration özelliği değeri denetlenerek belirlenebilir.
  • Seek yöntemini çağırarak ve oynatma konumunun dosya içinde taşınacağı zaman ofsetini belirterek ses dosyasında bir konuma gidin. Belirtilen değer StartTime ve EndTime aralığında olmalıdır. Düğümün geçerli oynatma konumunu yalnızca okunur Position özelliğini kullanarak alın.
  • LoopCount özelliğini ayarlayarak ses dosyasının döngüsünü etkinleştirin. Null olmayan bir değer olduğunda, bu değer dosyanın ilk kayıttan yürütmeden sonra kaç kez oynatılacağını gösterir. Bu nedenle, örneğin , LoopCount değerinin 1 olarak ayarlanması dosyanın toplamda 2 kez oynatılmasına ve 5 olarak ayarlanması dosyanın toplamda 6 kez oynatılmasına neden olur. LoopCount'un null olarak ayarlanması, dosyanın süresiz olarak döngüye alınmasına neden olur. Döngünün durdurulması için değeri 0 olarak ayarlayın.
  • PlaybackSpeedFactor ayarını yaparak ses dosyasının oynatıldığı hızı ayarlayın. 1 değeri dosyanın özgün hızını, .5'in yarı hızlı olduğunu ve 2'nin iki kat hızlı olduğunu gösterir.

MediaSource giriş düğümü

MediaSource sınıfı, farklı kaynaklardan medyaya başvurmak için ortak bir yol sağlar ve temel alınan medya biçiminden bağımsız olarak medya verilerine erişmek için ortak bir model sunar. Bu, disk, akış veya uyarlamalı akış ağ kaynağı olabilir. MediaSourceAudioInputNode düğümü, MediaSource'tan ses verilerini ses grafı içine yönlendirmenizi sağlar. Oynatmak istediğiniz içeriği temsil eden bir MediaSource nesnesi geçirerek, CreateMediaSourceAudioInputNodeAsync çağrısıyla bir MediaSourceAudioInputNode oluşturun. Status özelliğini denetleyerek işlemin durumunu belirlemek için kullanabileceğiniz bir CreateMediaSourceAudioInputNodeResult döndürülür. Durum Başarılı ise, Node özelliğine erişerek oluşturulan MediaSourceAudioInputNode değerini alabilirsiniz. Aşağıdaki örnekte, ağ üzerinden içerik akışını temsil eden AdaptiveMediaSource nesnesinden düğüm oluşturma işlemi gösterilmektedir.

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;
}

MediaSource içeriğinin sonuna oynatma ulaştığında bildirim almak için MediaSourceCompleted olayına bir işleyici kaydedin.

mediaSourceInputNode.MediaSourceCompleted += MediaSourceInputNode_MediaSourceCompleted;
private void MediaSourceInputNode_MediaSourceCompleted(MediaSourceAudioInputNode sender, object args)
{
    audioGraph.Stop();
}

Diskten bir dosyanın oynatılması neredeyse her zaman başarıyla tamamlanacak olsa da, ağ bağlantısındaki bir değişiklik veya ses grafiğinin denetimi dışında olan başka sorunlar nedeniyle ağ kaynağından akışla alınan medya oynatma sırasında başarısız olabilir. Bir MediaSource, oynatma sırasında oynatılamaz duruma gelirse ses grafı UnrecoverableErrorOccurred olayını tetikler. Ses grafını durdurmak ve atmak ve ardından grafınızı yeniden başlatabilmek için bu olayın işleyicisini kullanabilirsiniz.

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();
    }
}

Dosya çıkış düğümü

Dosya çıkış düğümü, grafikteki ses verilerini bir ses dosyasına yönlendirmenizi sağlar. CreateFileOutputNodeAsync çağrısı yaparak AudioFileOutputNode oluşturun.

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;
}

Ses çerçevesi giriş düğümü

Ses çerçevesi giriş düğümü, kendi kodunuzda oluşturduğunuz ses verilerini ses grafına göndermenizi sağlar. Bu, özel bir yazılım sentezleyicisi oluşturma gibi senaryoları etkinleştirir. CreateFrameInputNode çağrısı yaparak AudioFrameInputNode oluşturun.

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;
}

FrameInputNode.QuantumStarted olayı, ses grafı bir sonraki ses verisi kuantumunu işlemeye hazır olduğunda tetiklenir. Özel olarak oluşturulan ses verilerinizi işleyicinin içinden bu olaya sağlarsınız.

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);
    }
}
  • QuantumStarted olay işleyicisine geçirilen FrameInputNodeQuantumStartedEventArgs nesnesi, ses grafiğinin işlenecek kuantumu doldurmak için kaç örneğe ihtiyaç duyduğunu belirten RequiredSamples özelliğini sunar.
  • Grafiğe ses verileriyle doldurulmuş bir AudioFrame nesnesi geçirmek için AudioFrameInputNode.AddFrame çağrısı yapın.
  • MediaFrameReader'ı ses verileriyle birlikte kullanarak, AddFrame yöntemi kullanılarak bir FrameInputNode'a geçirilebilen bir medya çerçevesi kaynağından AudioFrame nesneleri alabilirsiniz.
  • GenerateAudioData yardımcı yönteminin örnek bir uygulaması aşağıda gösterilmiştir.

AudioFrame ses verileriyle doldurmak için, ses çerçevesinin temel alınan bellek arabelleğine erişmeniz gerekir. Bunu yapmak için, aşağıda gösterildiği gibi IMemoryBufferByteAccess COM arabirimini başlatın.

[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
    void GetBuffer(out byte* buffer, out uint capacity);
}

Aşağıdaki kod, GenerateAudioDataAudioFrame oluşturan bir yardımcı yönteminin örnek uygulamasını gösterir.

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;
}
  • Bu yöntem Windows Çalışma Zamanı türlerini temel alan ham arabelleğe eriştiğinden, unsafe anahtar sözcüğü kullanılarak bildirilmelidir. Ayrıca projenin Properties sayfasını açarak güvenli olmayan kodun derlenmesine izin vermek için projenizi Microsoft Visual Studio yapılandırmanız gerekir. Build özellik sayfasına tıklayıp Güvensiz Koda İzin Veda Et onay kutusunu seçin.
  • İstenen arabellek boyutunu oluşturucuya geçirerek Windows.Media ad alanında yeni bir AudioFrame örneği oluşturun. Arabellek boyutu, örnek sayısının her bir örneğin boyutuyla çarpımıdır.
  • LockBuffer çağrısı yaparak ses çerçevesinin AudioBuffer alın.
  • CreateReference'ı çağırarak ses arabelleğinden IMemoryBufferByteAccess COM arabiriminin bir örneğini alın.
  • IMemoryBufferByteAccess.GetBuffer çağrısını yaparak ham ses arabelleği verilerine bir işaretçi alın ve bunu ses verisinin örnek veri türüne dönüştürün.
  • Arabelleği veriyle doldurun ve ses grafiğine gönderilmek için AudioFrame döndürün.

Ses çerçevesi çıkış düğümü

Ses çerçevesi çıkış düğümü, oluşturduğunuz özel kodla ses grafından ses verisi çıkışı almanıza ve işlemenize olanak tanır. Bunun için örnek bir senaryo, ses çıkışında sinyal analizi gerçekleştirmektir. CreateFrameOutputNode çağrısı yaparak AudioFrameOutputNode oluşturun.

AudioFrameOutputNode frameOutputNode;
private void CreateFrameOutputNode()
{
    frameOutputNode = audioGraph.CreateFrameOutputNode();
    audioGraph.QuantumStarted += AudioGraph_QuantumStarted;
}

AudioGraph.QuantumStarted olayı, ses grafı bir ses verilerinin kuantumunu işlemeye başladığında oluşturulur. Ses verilerine bu olay için işleyici içinden erişebilirsiniz.

Note

Ses grafıyla eşitlenmiş normal bir tempoda ses çerçeveleri almak istiyorsanız, zaman uyumlu QuantumStarted olay işleyicisinin içinden AudioFrameOutputNode.GetFrame'i çağırın. QuantumProcessed olayı, ses altyapısı ses işlemeyi tamamladıktan sonra zaman uyumsuz olarak tetiklendiğinden, temposu düzensiz olabilir. Bu nedenle, ses çerçevesi verilerinin eşitlenmiş işlenmesi için QuantumProcessed olayını kullanmamalısınız.

private void AudioGraph_QuantumStarted(AudioGraph sender, object args)
{
    AudioFrame frame = frameOutputNode.GetFrame();
    ProcessFrameOutput(frame);
}
  • AudioFrame grafikten ses verileriyle doldurulmuş bir nesne almak için GetFrame çağrısı yapın.
  • ProcessFrameOutput yardımcı yönteminin örnek bir uygulaması aşağıda gösterilmiştir.
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;
    }
}
  • Yukarıdaki ses çerçevesi giriş düğümü örneğinde olduğu gibi, IMemoryBufferByteAccess COM arabirimini bildirmeniz ve projenizi temel alınan ses arabelleğine erişmek için güvenli olmayan koda izin verecek şekilde yapılandırmanız gerekir.
  • LockBuffer çağrısı yaparak ses çerçevesinin AudioBuffer alın.
  • CreateReference'ı çağırarak ses arabelleğinden IMemoryBufferByteAccess COM arabiriminin bir örneğini alın.
  • IMemoryBufferByteAccess.GetBuffer çağrısını yaparak ham ses arabelleği verilerine yönelik bir işaretçi elde edin ve bunu ses verisinin örnek veri türüne dönüştürün.

Düğüm bağlantıları ve alt miks düğümleri

Tüm giriş düğümü türleri, düğüm tarafından üretilen sesi yönteme parametre olarak geçirilen düğüme yönlendiren AddOutgoingConnection yöntemini sunar. Aşağıdaki örnek AudioFileInputNode bir AudioDeviceOutputNode bağlar. Bu, cihazın hoparlöründe bir ses dosyasını oynatmak için basit bir kurulumdur.

fileInputNode.AddOutgoingConnection(deviceOutputNode);

Giriş düğümünden diğer düğümlere birden fazla bağlantı oluşturabilirsiniz. Aşağıdaki örnek, AudioFileInputNode düğümünden AudioFileOutputNode düğümüne başka bir bağlantı ekler. Artık ses dosyasındaki ses, cihazın hoparlöründe çalınarak bir ses dosyasına yazılır.

fileInputNode.AddOutgoingConnection(fileOutputNode);

Çıkış düğümleri diğer düğümlerden birden fazla bağlantı da alabilir. Aşağıdaki örnekte, AudioDeviceInputNodeAudioDeviceOutput düğümüne bağlantı oluşturulur. Çıkış düğümünün dosya giriş düğümünden ve cihaz giriş düğümünden bağlantıları olduğundan, çıkış her iki kaynaktan ses karışımı içerir. AddOutgoingConnection , bağlantıdan geçen sinyal için bir kazanç değeri belirtmenize olanak tanıyan bir aşırı yükleme sağlar.

deviceInputNode.AddOutgoingConnection(deviceOutputNode, .5);

Çıkış düğümleri birden çok düğümden gelen bağlantıları kabul etse de, karışımı bir çıkışa geçirmeden önce bir veya daha fazla düğümden ara bir sinyal karışımı oluşturmak isteyebilirsiniz. Örneğin, düzeyi ayarlamak veya bir grafikteki ses sinyallerinin bir alt kümesine efektler uygulamak isteyebilirsiniz. Bunu yapmak için AudioSubmixNode kullanın. Bir alt karışım düğümüne, bir veya daha fazla giriş düğümünden ya da diğer alt karışım düğümlerinden bağlanabilirsiniz. Aşağıdaki örnekte, AudioGraph.CreateSubmixNode ile yeni bir alt düğüm oluşturulur. Ardından, dosya giriş düğümünden ve çerçeve giriş düğümünden submix düğümüne bağlantılar eklenir. Son olarak, alt miks düğümü bir dosya çıkış düğümüne bağlanır.

private void CreateSubmixNode()
{
    AudioSubmixNode submixNode = audioGraph.CreateSubmixNode();
    fileInputNode.AddOutgoingConnection(submixNode);
    frameInputNode.AddOutgoingConnection(submixNode);
    submixNode.AddOutgoingConnection(fileOutputNode);
}

Ses grafiği düğümlerini başlatma ve durdurma

AudioGraph.Start çağrıldığında ses grafı ses verilerini işlemeye başlar. Her düğüm türü, tek tek düğümün verileri işlemeyi başlatmasına veya durdurmasına neden olan Başlangıç ve Durdurma yöntemleri sağlar. AudioGraph.Stop çağrıldığında, tek tek düğümlerin durumundan bağımsız olarak tüm düğümlerdeki tüm ses işleme durdurulur, ancak ses grafiği durdurulurken her düğümün durumu ayarlanabilir. Örneğin, grafik durdurulurken tek bir düğümde Durdur'u çağırabilir ve ardından AudioGraph.Start çağrısı yapabilir ve tek düğüm durdurulmuş durumda kalır.

Tüm düğüm türleri, false olarak ayarlandığında düğümün ses işlemeye devam etmesine izin veren ancak diğer düğümlerden giriş yapılan ses verilerini tüketmesini engelleyen ConsumInput özelliğini kullanıma sunar.

Tüm düğüm türleri, düğümün kendi arabelleğinde o anda bulunan tüm ses verilerini atmasını sağlayan Reset yöntemini sunar.

Ses efektleri ekleme

Ses grafı API'si, grafikteki her düğüm türüne ses efektleri eklemenize olanak tanır. Çıkış düğümleri, giriş düğümleri ve alt düğümlerin her biri yalnızca donanımın özellikleriyle sınırlı olan sınırsız sayıda ses efektine sahip olabilir. Aşağıdaki örnek, yerleşik yankı efektini bir alt miks düğümüne eklemeyi göstermektedir.

EchoEffectDefinition echoEffect = new EchoEffectDefinition(audioGraph);
echoEffect.Delay = 1000.0;
echoEffect.Feedback = .2;
echoEffect.WetDryMix = .5;

submixNode.EffectDefinitions.Add(echoEffect);
  • Tüm ses efektleri IAudioEffectDefinition uygular. Her düğüm, bu düğüme uygulanan efektlerin listesini temsil eden bir EffectDefinitions özelliğini kullanıma sunar. Listeye tanım nesnesini ekleyerek bir efekt ekleyin.
  • Windows.Media.Audio ad alanında sağlanan çeşitli efekt tanımlama sınıfları vardır. Bunlar şunlardır:
  • IAudioEffectDefinition uygulayan kendi ses efektlerinizi oluşturabilir ve bunları ses grafiğindeki herhangi bir düğüme uygulayabilirsiniz.
  • Her düğüm türü, belirtilen tanım kullanılarak eklenen düğümün EffectDefinitions listesindeki tüm efektleri devre dışı getiren bir DisableEffectsByDefinition yöntemini kullanıma sunar. EnableEffectsByDefinition , belirtilen tanım ile etkileri etkinleştirir.

Uzamsal ses

AudioGraph , herhangi bir giriş veya alt düğümden gelen sesin yayıldığı 3B alanda konum belirtmenize olanak tanıyan uzamsal sesi destekler. Ayrıca sesin yayılacağı şekli ve yönü, Doppler'ın düğümün sesini kaydırmak için kullanılacak bir hız belirtebilirsiniz ve sesin uzaklık ile nasıl kısıtlandığını açıklayan bir bozulma modeli tanımlayabilirsiniz.

Bir yayıcı oluşturmak için, önce sesin yayıcıdan yansıtıldığı bir şekil oluşturabilirsiniz; bu bir koni veya çok yönlü olabilir. AudioNodeEmitterShape sınıfı bu şekillerin her birini oluşturmak için statik yöntemler sağlar. Ardından, bir çürüme modeli oluşturun. Bu, dinleyiciden uzaklık arttıkça vericiden gelen sesin ses düzeyinin nasıl azaldığını tanımlar. CreateNatural yöntemi, uzaklığın karesiyle azalan bir model kullanarak sesin doğal azalımını taklit eden bir azalım modeli oluşturur. Son olarak bir AudioNodeEmitterSettings nesnesi oluşturun. Şu anda bu nesne yalnızca yayıcının sesinin hız tabanlı Doppler'ı azaltmasını etkinleştirmek ve devre dışı bırakmak için kullanılır. Az önce oluşturduğunuz başlatma nesnelerini geçirerek AudioNodeEmitter oluşturucuyu çağırın. Varsayılan olarak, yayımlayıcı kaynak konuma yerleştirilir, ancak emitör konumunu Position özelliğiyle ayarlayabilirsiniz.

Note

Ses düğümü yayıcıları yalnızca 48kHz örnek hızıyla mono olarak biçimlendirilmiş sesi işleyebilir. Stereo ses veya farklı bir örnekleme hızına sahip ses kullanmaya çalışmak, bir özel durum oluşturur.

İstediğiniz düğüm türü için aşırı yüklemeli oluşturma yöntemini kullanarak düğümü oluşturduğunuzda, yayıcıyı bir ses düğümüne atarsınız. Bu örnekte, belirtilen bir dosyadan dosya giriş düğümü oluşturmak için CreateFileInputNodeAsync kullanılır ve düğümle ilişkilendirmek istediğiniz AudioNodeEmitter nesnesi kullanılır.

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;

Grafikten kullanıcıya ses veren AudioDeviceOutputNode bir dinleyici nesnesine sahiptir. 3B alanda kullanıcının konumunu, yönlendirmesini ve hızını temsil eden Listener özelliğiyle erişilir. Grafikteki tüm yayıcıların konumları dinleyici nesnesinin konumuna ve yönüne göredir. Varsayılan olarak dinleyici, Z ekseni boyunca ileriye dönük başlangıç noktasında (0,0,0) bulunur, ancak Konum ve Yönlendirme özellikleriyle konumunu ve yönlendirmesini ayarlayabilirsiniz.

deviceOutputNode.Listener.Position = new Vector3(100, 0, 0);
deviceOutputNode.Listener.Orientation = Quaternion.CreateFromYawPitchRoll(0, (float)Math.PI, 0);

Bir ses kaynağının 3B alan üzerinden hareketini simüle etmek için vericilerin konumunu, hızını ve yönünü çalışma zamanında güncelleştirebilirsiniz.

AudioNodeEmitter emitter = fileInputNode.Emitter;
emitter.Position = newObjectPosition;
emitter.DopplerVelocity = newObjectPosition - oldObjectPosition;

Ayrıca, kullanıcının 3B alan üzerinden hareketini simüle etmek için çalışma zamanında dinleyici nesnesinin konumunu, hızını ve yönlendirmesini güncelleştirebilirsiniz.

deviceOutputNode.Listener.Position = newUserPosition;

Varsayılan olarak uzamsal ses, Microsoft baş göreli aktarım işlevi (HRTF) algoritması kullanılarak hesaplanır ve ses, dinleyiciye göre şekline, hızına ve konumuna göre hafifletilir. SpatialAudioModel özelliğini FoldDown olarak ayarlayarak daha az doğru olan ancak daha az CPU ve bellek kaynağı gerektiren uzamsal sesin benzetimini yapmak için basit bir stereo karışımı yöntemi kullanabilirsiniz.

Ayrıca bakınız