我有一个C#项目,为RSS提要播放摩尔斯电码.我使用Managed DirectX编写它,却发现Managed DirectX已经过时并且已弃用.我的任务是播放纯正的正弦波突发,其间穿插着静音期(代码),它们的持续时间精确定时.我需要能够调用一个播放纯音多少毫秒的函数,然后Thread.Sleep()然后播放另一个等等.最快,音调和空格可以短至40ms.
它在Managed DirectX中运行良好.为了获得精确定时的音调,我创造了1秒.将正弦波放入辅助缓冲器,然后播放一定持续时间的音调,我在缓冲结束的x毫秒内向前寻找然后播放.
我试过System.Media.SoundPlayer.这是一个失败者[编辑 - 请参阅下面的答案]因为你必须播放(),睡眠(),然后停止()任意音长.结果是音调太长,因CPU负载而异.实际停止音调需要不确定的时间.
然后,我踏上了漫长的尝试使用n音讯1.3.我最终得到了一个提供音调数据的内存驻留流,并再次向前搜索,留下流中剩余的所需音调长度,然后播放.这在DirectSoundOut类上工作了一段时间(见下文),但WaveOut类很快就死了,内部断言说尽管PlayerStopped = true,缓冲区仍在队列中.这是奇怪的,因为我玩到最后然后在音调结束和下一个开始之间等待相同的持续时间.您认为在开始播放40毫秒音调后80毫秒,队列中没有缓冲区.
DirectSoundOut运行良好一段时间,但它的问题是,对于每个音调突发Play()它旋转一个单独的线程.最终(5分钟左右)它就停止工作了.在VS2008 IDE中运行项目时,可以在"输出"窗口中退出线程后查看线程之后的线程.我不会在播放期间创建新对象,我只是Seek()音色流然后反复调用Play(),所以我认为这不是孤立缓冲区的问题/无论是什么堆积直到它被阻塞.
我对这一个没有耐心,所以我希望这里有人遇到类似的要求,并且可以引导我朝着一个可能的解决方案的方向前进.
我正在制作一个使用语音库的程序,当女士说话时,我想让所有其他声音变得柔和或减弱.
我一直在寻找一种手动静音其他应用程序的方法,但我在Windows的通信选项卡(声音选项内)中看到了一个选项,提到该窗口可以为我管理这个.就像在这张图片中:
基本上,我的应用程序被视为通信应用程序(如Skype)需要什么?
我已经杀了一个星期试图在我的一个项目中解决一个神秘的问题,我没有想法.
我写了一个Go包,打算播放包含OpenAL的声音......非常基本的东西.我让它在我的Xubuntu 14.04(32位)上工作,所以我启动到Windows(7,也是32位)以便移植它......这就是问题开始的地方.
每当我尝试使用我的音频包时,该程序就会崩溃,并使用c0000005.我试图通过gdb运行它,并惊讶地发现它没有问题,它甚至播放我的测试声音.
时间过去了,不知道该怎么做,我下载了OpenAL Soft源代码并开始添加printfs - 并发现它崩溃的确切行:
http://repo.or.cz/w/openal-soft.git/blob/HEAD:/Alc/backends/dsound.c#l361
对于那些懒得点击链接(或链接停止工作),这是对DirectSoundCreate的调用.再次运行调试器,我在调用之前和之后看到了我的打印,并且在它们之间创建了4个新线程.
这些是Go文件中的相关内容:
package audio
/*
#cgo CFLAGS: -I"../libraries/include"
#cgo windows,386 LDFLAGS: ../libraries/lib/windows/x86/OpenAL32.dll
#cgo windows,amd64 LDFLAGS: ../libraries/lib/windows/x64/OpenAL32.dll
#cgo linux LDFLAGS: -lopenal
#include "audio.h"
*/
import "C"
import (
"errors"
)
var context *C.ALCcontext
func Init() error {
context = C.initAudio() // it crashes on this line
if context == nil {
return errors.New("could not initialize audio")
}
SetActiveListener(NewListener())
return nil
}
Run Code Online (Sandbox Code Playgroud)
这是实际进行OpenAL调用的C文件:
#include "audio.h"
#include <string.h>
#include <stdio.h>
ALCcontext* initAudio() {
ALCdevice* …
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用Speex编解码器库执行声学回声消除(AEC).根据Speex文档,我需要执行两个调用:
speex_echo_playback(echo_state, echo_frame);
Run Code Online (Sandbox Code Playgroud)
每次播放音频帧,和
speex_echo_capture(echo_state, input_frame, output_frame);
Run Code Online (Sandbox Code Playgroud)
对于每个捕获的帧.
由于我使用的是DirectSound,我认为我可以在调用speex_echo_playback时使用主DirectSound缓冲区作为echo_frame,例如,
DWORD offset = 0;
DWORD length = 0;
LPVOID block1, block2;
DWORD length1, length2;
DWORD flags = DSBLOCK_ENTIREBUFFER;
HRESULT hr = primary_buffer->Lock(
offset
, length
, &block1
, &length1
, &block2
, &length2
, flags
);
// Would like to convert the buffer into a form that
// speex_echo_capture() can use.
// Why does length1 == length2 == 0 always?
hr = primary_buffer->Unlock( block1, length1, block2, length2 );
Run Code Online (Sandbox Code Playgroud)
文档确实说这些是只写指针,但是无论如何都不能自己使用缓冲区数据?
这基本上就是我创建缓冲区的方式:
CComPtr< …
Run Code Online (Sandbox Code Playgroud) 再回到另一个DirectSound问题,可以使用关于DirectSound缓冲区的方法:
我通过网络以大约30ms的间隔进入包含音频数据的数据包,该数据被应用程序的其他部分解码为原始wav数据.
当Indata事件由这些其他代码片段触发时,我基本上将其放入以音频数据作为参数的过程中.
DSCurrentBuffer初始化如下:
ZeroMemory(@BufferDesc, SizeOf(DSBUFFERDESC));
wfx.wFormatTag := WAVE_FORMAT_PCM;
wfx.nChannels := 1;
wfx.nSamplesPerSec := fFrequency;
wfx.wBitsPerSample := 16;
wfx.nBlockAlign := 2; // Channels * (BitsPerSample/8)
wfx.nAvgBytesPerSec := fFrequency * 2; // SamplesPerSec * BlockAlign
BufferDesc.dwSize := SizeOf(DSBUFFERDESC);
BufferDesc.dwFlags := (DSBCAPS_GLOBALFOCUS or DSBCAPS_GETCURRENTPOSITION2 or
DSBCAPS_CTRLPOSITIONNOTIFY);
BufferDesc.dwBufferBytes := BufferSize;
BufferDesc.lpwfxFormat := @wfx;
case DSInterface.CreateSoundBuffer(BufferDesc, DSCurrentBuffer, nil) of
DS_OK:
;
DSERR_BADFORMAT:
ShowMessage('DSERR_BADFORMAT');
DSERR_INVALIDPARAM:
ShowMessage('DSERR_INVALIDPARAM');
end;
Run Code Online (Sandbox Code Playgroud)
我将此数据写入我的辅助缓冲区,如下所示:
var
FirstPart, SecondPart: Pointer;
FirstLength, SecondLength: DWORD;
AudioData: Array [0 .. 511] of Byte;
I, K: Integer; …
Run Code Online (Sandbox Code Playgroud) 我想用语音数据增加缓冲区的音量.关键是我正在使用DirectSound,我有一个主缓冲区和一个辅助缓冲区 - 所有流混合都是手工完成的.在语音聊天中,所有参与者可以具有独立的音量级别.我将每个流数据乘以一个值(增益)并将其加到一个缓冲区.一切正常,但当我尝试将数据乘以大于1.0f的值时 - 我听到一些剪辑或什么.
我尝试过使用Audacity效果压缩器,但这无助于减少奇怪的噪音.
可能我应该以其他方式改变收益?或者只是使用另一种后处理算法?
更新:哇,我刚发现有趣的事情!在增加音量之前,我已经放弃了音频.
这是照片
对不起质量 - 我认为这应该是声音出现的方式(我自己画了红线).真的看起来像超过样本数据类型的值.但我无法理解为什么?我的samplebuffer是BYTE,但我只通过短指针访问它.它已签名但即使*ptr约为15-20万时也会发生剪辑.
使用DirectSound设备播放数字声音.有必要以分贝显示声音活动 - 就像模拟设备一样.
从WAVE PCM数据(44100 Hz,16位)计算声压的正确方法是什么?
我有一个DLL,我想使用Direct Sound播放声音.为了播放声音,我需要可执行文件的HWND.我没有加载DLL的可执行文件的HWND.如何在DLL中获取它而不将其从可执行文件中传入?
我正在尝试在 Windows 上检测耳机是否已插入。我已经尝试过 DirectSound 和 NAudio 库,但没有取得任何成功。有没有人有什么建议?
注意:此问题与此问题重复,但该问题的答案不包含任何代码示例或教程。
我正在编写一个控制台程序,它使用DirectSound API来渲染一些音频数据.在按照DirectSound编程指南(来自Microsoft)时,我偶然发现了一个奇怪的问题.根据文件:
创建设备对象后,必须使用IDirectSound8 :: SetCooperativeLevel方法设置设备的协作级别.除非你这样做,否则不会听到任何声音.
问题是我正在编写一个控制台程序,并且SetCooperativeLevel
需要HWND作为第一个参数.我没有在控制台程序中处理任何HWND.我尝试提供一个空指针,但它失败了一个DSERR_INVALIDPARAM
错误代码.
应该IDirectSound8::SetCooperativeLevel
在控制台程序中提供什么HWND值?计划的音频部分计划构建为共享库,因此几乎不知道"外部"程序.
谢谢你的建议!
注意:我知道有一个更好的解决方案可以简单地渲染音频,比如使用SDL,OpenAL,SFML(基于OpenAL),但对于我当前的项目,DirectSound是强制执行的.
编辑:我发现Microsoft工程师发来的消息消除了SetCooperativeLevel
在创建GLOBAL_FOCUS缓冲区时使用桌面窗口或控制台窗口作为HWND的疑虑.