c++ - 如何使 DirectBuffer 次级声音?

标签 c++ c windows

我正在尝试通过简单的敲击键盘来获取声音。看起来像一个小鼓机。 如果 DirectSound 不是执行此操作的正确方法,请提出其他建议。 在我的代码中我不知道出了什么问题。这是没有错误检查和翻译的:

//Declaring the IDirectSound object

IDirectSound* device;

DirectSoundCreate(NULL, &device, NULL);
device->SetCooperativeLevel(hWnd, DSSCL_NORMAL );

/* Declaring secondary buffers */
IDirectSoundBuffer* kickbuf;
IDirectSoundBuffer* snarebuf;

/* Declaring .wav files pointers
   And to structures for reading the information int the begining of the .wav file */
FILE* fkick;
FILE* fsnare;
sWaveHeader kickHdr;
sWaveHeader snareHdr;

结构体sWaveHeader的声明方式如下:

typedef struct sWaveHeader
{
char            RiffSig[4];        // 'RIFF'
unsigned long   WaveformChunkSize; // 8
char            WaveSig[4];        // 'WAVE'
char            FormatSig[4];      // 'fmt '
unsigned long   FormatChunkSize;   // 16
unsigned short  FormatTag;         // WAVE_FORMAT_PCM
unsigned short  Channels;          // Channels
unsigned long   SampleRate;
unsigned long   BytesPerSec;
unsigned short  BlockAlign;
unsigned short  BitsPerSample;
char            DataSig[4];        // 'data'
unsigned long   DataSize;
} sWaveHeader;

.wav 文件打开

#define KICK "D:/muzic/kick.wav"
#define SNARE "D:/muzic/snare.wav"
fkick = fopen(KICK, "rb")
fsnare = fopen(SNARE, "rb")

这里我创建了一个函数,为 snarebuf* 和 **kickbuf 完成常见工作

int read_wav_to_WaveHeader (sWaveHeader* , FILE* , IDirectSoundBuffer* ); // The declaring

但我不会编写这个函数,只是展示它与 kickbuf 等一起工作的方式。

fseek(fkick, 0, SEEK_SET); // Zero the position in file
fread(&kickHdr, 1, sizeof(sWaveHeader), fkick); // reading the sWaveHeader structure from file

这里检查 sWaveHeader 结构是否适合:

if(memcmp(pwvHdr.RiffSig, "RIFF", 4) ||
       memcmp(pwvHdr.WaveSig, "WAVE", 4) ||
       memcmp(pwvHdr.FormatSig, "fmt ", 4) ||
       memcmp(pwvHdr.DataSig, "data", 4))
   return 1;

声明缓冲区的格式和描述符并填充它们:

DSBUFFERDESC bufDesc;
WAVEFORMATEX wvFormat;

ZeroMemory(&wvFormat, sizeof(WAVEFORMATEX));
    wvFormat.wFormatTag     = WAVE_FORMAT_PCM;
    wvFormat.nChannels      = kickHdr.Channels;
    wvFormat.nSamplesPerSec = kickHdr.SampleRate;
    wvFormat.wBitsPerSample = kickHdr.BitsPerSample;
    wvFormat.nBlockAlign    = wvFormat.wBitsPerSample / 8 * wvFormat.nChannels;

ZeroMemory(&bufDesc, sizeof(DSBUFFERDESC));
    bufDesc.dwSize = sizeof(DSBUFFERDESC);
    bufDesc.dwFlags = DSBCAPS_CTRLVOLUME | 
                      DSBCAPS_CTRLPAN |
                      DSBCAPS_CTRLFREQUENCY;
    bufDesc.dwBufferBytes = kickHdr.DataSize;
    bufDesc.lpwfxFormat = &wvFormat;

好吧,创建一个缓冲区:

device->CreateSoundBuffer(&bufDesc, &kickbuf, NULL); // Any mistakes by this point?

现在锁定缓冲区并向其中加载一些数据。 此数据在 WAVE 文件中的 sizeof(sWaveHeader) 字节之后开始,我错了吗?

LPVOID Ptr1;     // pointer on a pointer on a First block of data 
LPVOID Ptr2;     // pointer on a pointer on a Second block of data
DWORD Size1, Size2;  // their sizes

现在调用 Lock() 方法:

kickbuf->Lock((DWORD)LockPos, (DWORD)Size,
                             &Ptr1, &Size1,
                             &Ptr2, &Size2, 0);

正在加载数据(可以吗?):

fseek(fkick, sizeof(sWaveHeader), SEEK_SET);
fread(Ptr1, 1, Size1, fkick);
    if(Ptr2 != NULL)
        fread(Ptr2, 1, Size2, fkick);

解锁缓冲区:

kickbuf->Unlock(Ptr1, Size1, Ptr2, Size2);

设置音量:

kickbuf->SetVolume(-2500);

然后我做了一个 wile(1) 循环: 1. 要求按键 2. 如果按下:

kickbuf->SetCurrentPosition(0)
kickbuf->Play(0,0,0);

但是没有声音播放,请说明我的代码或整个概念中有什么不正确的地方。谢谢。

最佳答案

当您初始化 WAVEFORMATEX 时,您忘记设置 nAvgBytesPerSec 成员。在 wvFormat.nBlockAlign 初始化后添加此行:

wvFormat.nAvgBytesPerSec = wvFormat.nSamplesPerSec * wvFormat.nBlockAlign;

另外,我怀疑这可能是一个问题:

kickbuf->SetVolume(-2500);

我怀疑这只会将你的样本衰减到绝对静音。尝试接听该调用,以便以最大音量播放。

但更有可能的是,上面的示例代码都没有显示对任何 DirectSound API 的返回值或任何文件 I/O 值的验证。您是否验证了所有 DSound API 返回的 HRESULT 都返回 S_OK?您是否尝试过打印或使用 OutputDebugString 来打印您为 WAVEFORMATEX 成员计算的值?
您是否调试了 fread 调用以验证是否将有效数据放入缓冲区?

希望这有帮助。

关于c++ - 如何使 DirectBuffer 次级声音?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26828211/

相关文章:

c++ - C++11 unique_ptr 和 shared_ptr 是否能够转换为彼此的类型?

c - 如何让 gcc 生成合适的代码来检查缓冲区是否充满 NUL 字节?

node.js - 如何静态存储和调用node.js回调函数

windows - 使用 Windows Server 托管网站时,最低限度的安全配置建议是什么

windows - 有没有办法在当前文件夹中打开命令提示符?

c++ - 为什么 Visual Studio 无法编译我的 QT 项目,因为它找不到库?

android - 在我的 C 代码中调用 soundtouch 代码,程序崩溃了

c++ - Visual Studio C++ : Getting Unresolved tokens and unresolved link. 我该怎么办?

c - 将 char* 添加到 char**

c - GetPrivateProfileString 和 AppData VirtualStore 目录