6

我正在将一些 C# Windows Phone 7 应用程序移植到 Windows 8。

手机应用程序使用 XNA SoundEffect从缓冲区播放任意声音。在最简单的情况下,我只需创建所需持续时间和频率的正弦波。持续时间和频率都可能有很大差异,所以我不想依赖 MediaElements(除非有办法改变基本文件的频率,但这只会帮助我生成单一频率)。

WinRT 中的 XNA SoundEffectInstance 等价物是什么?

我假设我需要为此使用 DirectX,但我不确定如何从其他 C#/XAML 应用程序中解决这个问题。我看过SharpDX,但它似乎没有我认为我需要使用的 DirectSound、SecondaryBuffer、SecondaryBuffer 类。

我在上面做了一些假设。可能是我正在寻找错误的类,或者有一种完全独立的方法可以从 Windows 8 应用程序生成任意声音。


我找到了一个使用 SharpDX 中的 XAudio2 通过 AudioBuffer 播放 wav 文件的示例。这似乎很有希望,我只需要用我生成的音频缓冲区替换本机文件流。

PM> 安装包SharpDX

PM> Install-Package SharpDX.XAudio2

    public void PlaySound()
    {
        XAudio2 xaudio;
        MasteringVoice masteringVoice;

        xaudio = new XAudio2();
        masteringVoice = new MasteringVoice(xaudio);

        var nativefilestream = new NativeFileStream(
            @"Assets\SpeechOn.wav",
            NativeFileMode.Open,
            NativeFileAccess.Read,
            NativeFileShare.Read);

        var soundstream = new SoundStream(nativefilestream);


        var waveFormat = soundstream.Format;
        var buffer = new AudioBuffer
        {
            Stream = soundstream.ToDataStream(),
            AudioBytes = (int)soundstream.Length,
            Flags = BufferFlags.EndOfStream
        };

        var sourceVoice = new SourceVoice(xaudio, waveFormat, true);

        // There is also support for shifting the frequency.
        sourceVoice.SetFrequencyRatio(0.5f);

        sourceVoice.SubmitSourceBuffer(buffer, soundstream.DecodedPacketsInfo);

        sourceVoice.Start();
    }
4

2 回答 2

10

在 Win8RT 中生成动态声音的唯一方法是使用 XAudio2,因此您应该能够使用 SharpDX.XAudio2 来实现。

而不是使用 NativeFileStream,只需实例化一个 DataStream 直接提供您的托管缓冲区(或者您可以使用非托管缓冲区或让 DataStream 为您实例化一个)。代码将是这样的:

// Initialization phase, keep this buffer during the life of your application
// Allocate 10s at 44.1Khz of stereo 16bit signals
var myBufferOfSamples = new short[44100 * 10 * 2];

// Create a DataStream with pinned managed buffer
var dataStream = DataStream.Create(myBufferOfSamples, true, true);

var buffer = new AudioBuffer
        {
            Stream = dataStream,
            AudioBytes = (int)dataStream.Length,
            Flags = BufferFlags.EndOfStream
        };

//...
// Fill myBufferOfSamples
//...

// PCM 44.1Khz stereo 16 bit format
var waveFormat = new WaveFormat();

XAudio2 xaudio = new XAudio2();
MasteringVoice masteringVoice = new MasteringVoice(xaudio);
var sourceVoice = new SourceVoice(xaudio, waveFormat, true);

// Submit the buffer
sourceVoice.SubmitSourceBuffer(buffer, null);

// Start playing
sourceVoice.Start();

用正弦波填充缓冲区的示例方法:

    private void FillBuffer(short[] buffer, int sampleRate, double frequency)
    {
        double totalTime = 0;

        for (int i = 0; i < buffer.Length - 1; i += 2)
        {
            double time = (double)totalTime / (double)sampleRate;
            short currentSample = (short)(Math.Sin(2 * Math.PI * frequency * time) * (double)short.MaxValue);

            buffer[i] = currentSample; //(short)(currentSample & 0xFF);
            buffer[i + 1] = currentSample; //(short)(currentSample >> 8);

            totalTime += 2;
        }

    }
于 2012-09-22T22:34:58.233 回答
2

您还可以使用 WASAPI 在 WinRT 中播放动态生成的声音缓冲区。(xaudio2 不是唯一的解决方案)。

我在这里用 VB 编写了示例代码(C# 基本相同): http: //www.codeproject.com/Articles/460145/Recording-and-playing-PCM-audio-on-Windows-8-VB

我相信 NAudio 的家伙正计划将我的示例代码翻译+合并到 NAudio 中,以获得支持 Win8 的版本,这样会更容易使用。

于 2012-11-29T21:21:22.893 回答