问题标签 [waveoutwrite]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
9 回答
5612 浏览

c++ - 为什么 waveOutWrite() 会在调试堆中导致异常?

在研究这个问题时,我在网上发现了多次提到以下场景,总是在编程论坛上作为未回答的问题。我希望在这里发布这个至少可以用来记录我的发现。

首先,症状:在运行使用 waveOutWrite() 输出 PCM 音频的标准代码时,有时在调试器下运行时会出现以下情况:

虽然明显的怀疑是代码中其他地方的堆损坏,但我发现情况并非如此。此外,我能够使用以下代码重现此问题(这是基于对话框的 MFC 应用程序的一部分:)

在任何人对此发表评论之前,是的 - 示例代码播放未初始化的内存。不要在扬声器完全打开的情况下尝试此操作。

一些调试揭示了以下信息: waveOutPrepareHeader() 用一个指针填充 header.reserved,该指针指向一个似乎包含至少两个指针作为其前两个成员的结构。第一个指针设置为 NULL。调用 waveOutWrite() 后,该指针被设置为分配在全局堆上的指针。在伪代码中,它看起来像这样:

通常,标头由 wdmaud.dll 的内部函数 waveCompleteHeader() 返回给应用程序。waveCompleteHeader() 尝试通过调用 GlobalHandle()/GlobalUnlock() 和朋友来释放由 waveOutWrite() 分配的指针。有时,GlobalHandle() 会爆炸,如上所示。

现在,GlobalHandle() 炸弹的原因并不是因为堆损坏,正如我一开始所怀疑的那样 - 这是因为 waveOutWrite() 在没有将内部结构中的第一个指针设置为有效指针的情况下返回。我怀疑它在返回之前释放了该指针指向的内存,但我还没有反汇编它。

这似乎仅在波形播放系统缓冲区不足时发生,这就是为什么我使用单个标头来重现它的原因。

在这一点上,我有一个很好的理由反对这是我的应用程序中的一个错误——毕竟,我的应用程序甚至没有运行。有没有人见过这个?

我在 Windows XP SP2 上看到了这个。声卡来自SigmaTel,驱动版本为5.10.0.4995。

笔记:

为了防止将来出现混淆,我想指出,问题在于使用 malloc()/free() 来管理正在播放的缓冲区的答案是完全错误的。您会注意到我更改了上面的代码以反映建议,以防止更多人犯同样的错误——这没有什么区别。waveCompleteHeader() 释放的缓冲区不是包含 PCM 数据的缓冲区,释放 PCM 缓冲区的责任在于应用程序,并且不要求以任何特定方式分配它。

此外,我确保我使用的所有 waveOut API 调用都不会失败。

我目前假设这要么是 Windows 中的错误,要么是音频驱动程序中的错误。反对意见总是受欢迎的。

0 投票
3 回答
2770 浏览

windows - 来自 waveOutWrite API 方法的回调的延迟(或延迟)时间是多少?

我正在另一个论坛上与一些开发人员就准确生成 MIDI 事件(注意消息等)进行辩论。人耳对轻微的计时误差非常敏感,我认为他们的主要问题来自于他们使用分辨率相对较低的计时器,这些计时器以大约 15 毫秒的间隔量化他们的事件(这足以导致可察觉的不准确性)。

大约 10 年前,我编写了一个示例应用程序(Windows 95 上的 Visual Basic 5),它是一个组合的软件合成器和 MIDI 播放器。基本前提是一个跳跃缓冲播放系统,每个缓冲区是十六分音符的持续时间(例如:每分钟有 120 个四分音符,每个四分音符是 500 毫秒,因此每个十六分音符是 125 毫秒,所以每个缓冲区为 5513 个样本)。每个缓冲区都通过 waveOutWrite 方法播放,该方法的回调函数用于排队下一个缓冲区并发送 MIDI 消息。这使基于 WAV 的音频和 MIDI 音频保持同步。

在我看来,这种方法效果很好——MIDI 音符听起来甚至没有一点不同步(而如果你使用精确到 15 毫秒的普通计时器来播放 MIDI 音符,它们听起来会明显不同步)。

理论上,这种方法会产生精确到样本的 MIDI 时序,即 0.0227 毫秒(因为每毫秒有 44.1 个样本)。我怀疑这是这种方法的真正延迟,因为在缓冲区完成和通知 waveOutWrite 回调之间可能存在一些轻微延迟。有谁知道这个延迟实际上会有多大?

0 投票
2 回答
1328 浏览

winapi - 查询 HWAVEOUT 句柄的波形格式

上下文:我有一段代码知道 waveOut 句柄 (HWAVEOUT) 的值。但是代码没有创建句柄,因此在创建句柄时传递给 waveOutOpen 的 WAVEFORMATEX 是未知的。

我想找出传递给 waveOutOpen 调用的那个 WAVEFORMATEX 结构的内容。

使用它的更多细节:代码在调用而不是 waveOutWrite 的挂钩函数中运行。因此代码知道句柄值,但不知道句柄创建的细节。

只是为了让人们不需要查找:
waveOutOpen 的签名是

waveOutWrite 的签名是:

注意:我也在挂钩 waveOutOpen,但它可能在我有挂钩之前就已经被调用了。

0 投票
1 回答
929 浏览

c# - Control.Invoke() 与其委托的调用之间的延迟是多长时间?

我有一个代码引擎,它通过使用 waveOutOpen 和 waveOutWrite API 方法连续播放较小的块来播放长 WAV 文件。为了在文件播放时更新我的​​ UI,在每个缓冲区完成播放时从回调函数中调用一个单独的线程(因为您希望在回调函数中尽可能少地执行操作),该线程在我的表单中调用一个方法。

该表单包含一个处理方法的类级别EventHandler,在该方法中我使用新信息更新 UI 元素。在从 waveOutWrite 回调函数调用的表单方法中,我使用 Invoke 方法,如下所示:

一切正常,但似乎偶尔会在更新 UI 元素时出现明显的滞后或延迟。这很容易看出,因为我使用 UpdateDisplay 方法来驱动动画,因此延迟显示为“打嗝”,其中精灵在跳到预期位置之前似乎冻结了一瞬间。

像这样的跨线程通信有时是否可能存在很长的(可能是 10-15 毫秒)延迟?如果是这样,处理此类事情的更好方法是什么?

更新:顺便说一句,我绝对不确定Invoke是罪魁祸首。另一种可能性是一段音频完成播放和回调函数实际被调用之间的延迟。

更新 2:根据itowlson的建议,我使用 aSystem.Diagnostics.Stopwatch来衡量Invoke和方法调用之间的延迟。在 1156 次测量中,我在 0 毫秒时得到 1146 次,在 1 毫秒时得到 8 次,在 2 毫秒时得到 2 次。我认为可以肯定地说Invoke不是我的罪魁祸首。

0 投票
3 回答
2247 浏览

c# - waveOutWrite 和 waveOutGetPosition 死锁的问题

我正在开发一个应用程序,该应用程序使用waveOut...来自winmm.dll. 该应用程序使用“跳跃式”缓冲区,它们基本上是一堆样本数组,您可以将它们转储到音频队列中。Windows 按顺序无缝播放它们,并且在每个缓冲区完成时 Windows 调用一个回调函数。在这个函数中,我将下一组样本加载到缓冲区中,然后处理它们,然后将缓冲区转储回音频队列。这样,音频就可以无限期地播放。

出于动画目的,我正在尝试将其合并waveOutGetPosition到应用程序中(因为“缓冲区完成”回调是不规则的,足以导致生涩的动画)。 waveOutGetPosition返回播放的当前位置,所以它是超精确的。

问题是在我的应用程序中,调用waveOutGetPosition最终会导致应用程序锁定 - 声音停止并且调用永远不会返回。我把事情归结为一个简单的应用程序来演示这个问题。您可以在此处运行该应用程序:

http://www.musigenesis.com/SO/waveOut%20demo.exe

如果你只是一遍又一遍地听到一点点钢琴声,它就起作用了。它只是为了证明问题。这个项目的源代码在这里(所有的肉都在 LeapFrogPlayer.cs 中):

http://www.musigenesis.com/SO/WaveOutDemo.zip

第一个按钮以越级模式运行应用程序,无需调用waveOutGetPosition. 如果单击此按钮,应用程序将永远播放而不会中断(X 按钮将关闭它并关闭它)。第二个按钮启动跳跃器并启动一个表单计时器,该计时器调用waveOutGetPosition并显示当前位置。单击此按钮,应用程序将运行一会儿,然后锁定。在我的笔记本电脑上,它通常会在 15-30 秒内锁定;最多只需要一分钟。

我不知道如何解决这个问题,所以非常欢迎任何帮助或建议。我发现关于这个问题的帖子很少,但似乎存在潜在的死锁,无论是多次调用waveOutGetPosition还是waveOutWrite同时发生的调用。我可能过于频繁地调用它,系统无法处理。

编辑:忘了提,我在 Windows Vista 上运行它。这在其他操作系统上可能根本不会发生。

编辑2:除了这些(未回答的)帖子外,我在网上几乎没有发现这个问题:

http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/c6a1e80e-4a18-47e7-af11-56a89f638ad7

编辑3:嗯,我现在可以随意重现这个问题。如果我waveOutGetPosition在之后waveOutWrite(在下面的代码行中)立即调用,则应用程序每次都会挂起。它还以一种特别糟糕的方式挂起 - 它似乎将我的整个操作系统锁定了一段时间,而不仅仅是应用程序本身。因此,waveOutGetPosition如果死锁发生在与几乎相同的时间waveOutWrite,而不仅仅是字面上的同时发生,这似乎可以解释为什么锁对我不起作用。是的。

0 投票
2 回答
2515 浏览

audio - 使用 WaveOUT API 产生无失真的 Tone 声音所需的最小音频缓冲区是多少

WaveOut API 是否对当前播放的缓冲区大小有一些内部限制?我的意思是,如果我提供一个非常小的缓冲区,它是否会以某种方式影响播放到扬声器的声音。当我用小缓冲区生成和播放正弦波时,我遇到了非常奇怪的噪音。像高峰或“BUMP”之类的东西。

完整的故事:

我做了一个可以实时生成窦性声音信号的程序。可变参数是频率和音量。项目要求最大延迟为 50 毫秒。因此该程序必须能够实时产生具有手动可调音频信号频率的正弦信号。

我使用 Windows WaveOut API、C# 和 P/invoke 来访问 API。

当声音缓冲区为 1000 毫秒时,一切正常。如果我根据延迟要求将缓冲区最小化到 50 毫秒,那么对于我在每个缓冲区结束时遇到的某些频率,会出现噪音或“BUMP”。我不明白生成的声音是否格式错误(我检查过但不是)或者音频芯片发生了什么问题,或者初始化和播放有一些延迟。

当我将制作的音频保存到 .wav 文件时,一切都很完美。

这意味着我的代码中一定有一些错误,或者音频子系统对发送给它的缓冲区块有限制。

对于那些不知道 WaveOut 必须首先初始化的人,然后必须为每个缓冲区准备好包含需要播放的字节数的音频头以及指向包含需要播放的音频的内存的指针成为玩家。

更新

以下组合会产生噪音 44100 SamplingRate、16 位、2 通道、50 毫秒缓冲并生成 201Hz、202Hz、203Hz、204Hz、205Hz ... 219Hz、220Hz、240Hz 的 Sinus 音频信号,没问题

为什么相差20,我不知道。

0 投票
1 回答
463 浏览

audio - 如何在 Windows CE 6.0 R3 上 P/Invoke WaveOut API

如何在 Windows CE 6.0 R3 上 P/Invoke WaveOut API?

当我把这个

它适用于 Window XP, 7,但在 Wnidows CE 6.0 上会抛出消息“Can't P/Invoke winmm.dll”。

我究竟做错了什么?WaveOut API 是移动到其他 dll 还是其他什么?

无论如何,SoundPlayer(来自 .NET Compact Framework 3.5)工作正常。

0 投票
1 回答
149 浏览

windows - WaveOutWrite 直接来自网络摄像头音频捕获回调

我正在使用 VFW 和音频捕获回调从网络摄像头捕获音频数据,同时,在同一捕获回调的主体内,使用 waveOutWrite 将采样数据定向到默认 MAPPER。

网络摄像头的信号质量为 1 通道/8 位/11025 个样本/秒。由于带有FORMAT_QUERY标志的waveOpen,默认音频设备支持声音格式。

waveWriteOut的返回是NOERROR,但我能听到的与我的期望相去甚远。房间里很安静,应该是空虚的白噪音。

请听听YouTube 录音

它开始,一个包一个包大小约 16K,WAVEHDR 结构还可以。然后它逐渐减慢并退出系统未恢复错误。

这和什么相似?

下面是来自 VFW 的音频 dta 接收器代码,lpWHdr 看起来不错,甚至内部标志触发为 2 = Prepared .. 似乎 VFW 和 WaveAudio 是相互创建的 :)

我认为缓冲区没有溢出,因为您可以看到 DateTime 毫秒标记,它每 1400 毫秒打勾,采样率 = 11025,缓冲区大小约为 16500 字节 = 看起来不错..

UPD:我只是将非托管缓冲区复制到托管并查看了它的值。看起来像锯齿甚至超载的鼻窦。0 4 0 3 0 32 109 213 255 251 255 243 241 97 0 7 0 2 1 1 0 5 0 然后以大约相同的数字和相同的周期再次上下波动。不完全一样,大致相同(+/-)。此外,我可以使用内部 Windows 记录器记录来自该摄像头的信号,我可以看到信号电平在我的声音上下跳动,所以网络摄像头的麦克风也可以。我想这可能是什么VFW输入音频信号馈线错误。即使它接受了 WAVEFORMATEX 并发回了 WAVEHDR,它们都很好......但是缓冲区数据填充了其他来源,而不是网络摄像头,尽管 VFW 说它必须来自网络摄像头,因为视频是从同一来源捕获的,它正在工作,我只是添加了一条额外消息: SendMessage(camHwnd, WM_CAP_SET_CALLBACK_WAVESTREAM, 0, audioCallback); 我很确定如果我会使用waveIn 而不是VFW,它会正常工作.. 我稍后会检查它.. 但是为什么VFW 的工作方式不像它应该的那样?

0 投票
3 回答
1482 浏览

c++ - 双缓冲 waveOutWrite() 结结巴巴

【谜底已解开;对于那些寻找解释的人,它在这篇文章的底部]

下面是我尝试使用 WindowswaveOut*()函数编写的 Windows 音调发生器。

尽管实际上按照 MSDN 做了所有事情(例如,应该手动重置的回调事件),但我无法从该死的东西中获得平滑的方波播放——实际上,任何平滑的播放,但为了简单起见,我演示了正方形。缓冲区边界总是以点击来迎接我!看起来 Windows 只是忽略了我使用双缓冲的事实。

生成器本身与缓冲区大小无关,如果我使用更大的缓冲区,无缝播放会持续更长的时间——但是当缓冲区最终结束时,会有一个点击。

帮助。

[更新:]

正如我被告知的那样复制标题,但无济于事:

[实际发生的事情:]

由于 Windows 在我切换缓冲区的那一刻就用完了数据,因此播放一直卡顿。为避免这种情况,您必须在反馈循环开始之前向系统提供两个缓冲区,以便当其中一个缓冲区播放完毕时,下一个缓冲区已经准备好并发送,而您重新填充刚刚退出的缓冲区。

愿迷失的灵魂(就像两天前的我)终于在这里找到清晰的方向=)

说真的,目前这是 Internet 上唯一一个提出实际可行解决方案的页面,它没有使用计时器或任何杂物,而是使用正确的方法。