使用 SlimDX 和 DirectSound 播放声音 (C#)

发布于 2024-09-26 09:39:04 字数 2897 浏览 9 评论 0原文

(如果这是重复的,我深表歉意……我发布了,但没有看到任何证据表明它确实进入了论坛)

我一直在尝试让 SlimDX DirectSound 正常工作。这是我的代码。它从 wav 文件填充辅助缓冲区,然后在线程循环中交替填充缓冲区的下半部分或上半部分。

它可以很好地播放缓冲区的第一个加载。 AutoResetEvents 在应该的时候触发,并且填充缓冲区的下半部分和上半部分(使用 Debug 语句进行验证)。但在第一次加载缓冲区后,播放不会继续。因此,不知何故,缓冲区的重新填充无法正常工作。

有想法吗?

(我使用 DirectSound 是因为这是我发现的设置我想要使用的音频设备的 guid 的唯一方法。我对其他 .NET 友好的方法持开放态度。)

private void PlaySound(Guid soundCardGuid, string audioFile) {
        DirectSound ds = new DirectSound(soundCardGuid);

        ds.SetCooperativeLevel(this.Handle, CooperativeLevel.Priority);

        WaveFormat 格式 = new WaveFormat();
        格式.BitsPerSample = 16;
        格式.BlockAlignment = 4;
        格式.频道= 2;
        format.FormatTag = WaveFormatTag.Pcm;
        格式.SamplesPerSecond = 44100;
        格式.AverageBytesPerSecond = 格式.SamplesPerSecond * 格式.BlockAlignment;

        SoundBufferDescription desc = new SoundBufferDescription();
        desc.Format = 格式;
        desc.Flags = BufferFlags.GlobalFocus;
        desc.SizeInBytes = 8 * format.AverageBytesPerSecond; 

        PrimarySoundBuffer pBuffer = new PrimarySoundBuffer(ds, desc);

        SoundBufferDescription desc2 = new SoundBufferDescription();
        desc2.Format = 格式;
        desc2.Flags = BufferFlags.GlobalFocus | BufferFlags.ControlPositionNotify | BufferFlags.ControlPositionNotify | BufferFlags.GetCurrentPosition2;
        desc2.SizeInBytes = 8 * format.AverageBytesPerSecond;

        secondarySoundBuffer sBuffer1 = new secondarySoundBuffer(ds, desc2);

        NotificationPosition[] 通知 = 新的NotificationPosition[2];
        通知[0].Offset = desc2.SizeInBytes / 2 + 1;
        通知[1].Offset = desc2.SizeInBytes - 1; ;

        通知[0].Event = new AutoResetEvent(false);
        notification[1].Event = new AutoResetEvent(false);
        sBuffer1.SetNotificationPositions(通知);

        byte[] bytes1 = 新字节[desc2.SizeInBytes / 2];
        byte[] bytes2 = 新字节[desc2.SizeInBytes];

        Stream 流 = File.Open(audioFile, FileMode.Open);

        线程 fillBuffer = new Thread(() => {
            int 读取数 = 1;
            int 字节读取;

            bytesRead = Stream.Read(bytes2, 0, desc2.SizeInBytes);
            sBuffer1.Write<字节>(bytes2, 0, LockFlags.None);
            sBuffer1.Play(0, PlayFlags.None); 
            而(真){
                if (bytesRead == 0) { 中断; }
                通知[0].Event.WaitOne();
                bytesRead = Stream.Read(bytes1, 0, bytes1.Length);
                sBuffer1.Write<字节>(bytes1, 0, LockFlags.None);

                if (bytesRead == 0) { 中断; }
                通知[1].Event.WaitOne();
                bytesRead = Stream.Read(bytes1, 0, bytes1.Length);
                sBuffer1.Write(bytes1, desc2.SizeInBytes / 2, LockFlags.None); 
            }
            流.关闭();
            流.Dispose();
        });
        fillBuffer.Start();
    }
}

(apologies if this is a duplicate ... i posted but saw no evidence that it actually made it to the forum)

I've been trying to get SlimDX DirectSound working. Here's the code I have. It fills the secondary buffer from a wav file and then, in a thread loop, alternately fills the lower or upper halves of the buffer.

It plays the first load of the buffer fine. The AutoResetEvents fire when they should and the lower half then upper half of the buffer are populated (verified with Debug statements). But playing does not continue after the first load of the buffer. So somehow the repopulation of the buffer doesn't work as it should.

Ideas?

(I'm using DirectSound because it's the only way I've found to set the guid of the audio device that I want to use. Am open to other .NET-friendly approaches.)

private void PlaySound(Guid soundCardGuid, string audioFile) {
        DirectSound ds = new DirectSound(soundCardGuid);

        ds.SetCooperativeLevel(this.Handle, CooperativeLevel.Priority);

        WaveFormat format = new WaveFormat();
        format.BitsPerSample = 16;
        format.BlockAlignment = 4;
        format.Channels = 2;
        format.FormatTag = WaveFormatTag.Pcm;
        format.SamplesPerSecond = 44100;
        format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlignment;

        SoundBufferDescription desc = new SoundBufferDescription();
        desc.Format = format;
        desc.Flags = BufferFlags.GlobalFocus;
        desc.SizeInBytes = 8 * format.AverageBytesPerSecond; 

        PrimarySoundBuffer pBuffer = new PrimarySoundBuffer(ds, desc);

        SoundBufferDescription desc2 = new SoundBufferDescription();
        desc2.Format = format;
        desc2.Flags = BufferFlags.GlobalFocus | BufferFlags.ControlPositionNotify | BufferFlags.GetCurrentPosition2;
        desc2.SizeInBytes = 8 * format.AverageBytesPerSecond;

        SecondarySoundBuffer sBuffer1 = new SecondarySoundBuffer(ds, desc2);

        NotificationPosition[] notifications = new NotificationPosition[2];
        notifications[0].Offset = desc2.SizeInBytes / 2 + 1;
        notifications[1].Offset = desc2.SizeInBytes - 1; ;

        notifications[0].Event = new AutoResetEvent(false);
        notifications[1].Event = new AutoResetEvent(false);
        sBuffer1.SetNotificationPositions(notifications);

        byte[] bytes1 = new byte[desc2.SizeInBytes / 2];
        byte[] bytes2 = new byte[desc2.SizeInBytes];

        Stream stream = File.Open(audioFile, FileMode.Open);

        Thread fillBuffer = new Thread(() => {
            int readNumber = 1;
            int bytesRead;

            bytesRead = stream.Read(bytes2, 0, desc2.SizeInBytes);
            sBuffer1.Write<byte>(bytes2, 0, LockFlags.None);
            sBuffer1.Play(0, PlayFlags.None); 
            while (true) {
                if (bytesRead == 0) { break; }
                notifications[0].Event.WaitOne();
                bytesRead = stream.Read(bytes1, 0, bytes1.Length);
                sBuffer1.Write<byte>(bytes1, 0, LockFlags.None);

                if (bytesRead == 0) { break; }
                notifications[1].Event.WaitOne();
                bytesRead = stream.Read(bytes1, 0, bytes1.Length);
                sBuffer1.Write<byte>(bytes1, desc2.SizeInBytes / 2, LockFlags.None); 
            }
            stream.Close();
            stream.Dispose();
        });
        fillBuffer.Start();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

摇划花蜜的午后 2024-10-03 09:39:04

您尚未将其设置为在播放缓冲区上循环。将您的代码更改为:

sBuffer1.Play(0, PlayFlags.Looping); 

You haven't set it to loop on the play buffer. Change your code to:

sBuffer1.Play(0, PlayFlags.Looping); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文