C++ Win32 PlaySound:如何控制音量?

C++ Win32 PlaySound:如何控制音量?,c++,winapi,audio,multimedia,C++,Winapi,Audio,Multimedia,我正在使用Win32多媒体功能播放应用程序中的声音 我希望能够在不修改系统音量的情况下动态调整正在播放的声音的音量 我能找到的唯一建议是使用该函数设置系统范围内的音量级别(不是我想要的)。两种可能的解决方案: 首先,如果您的目标是Vista及以上版本,则可以使用新的Windows Audio API调整每个应用程序的音量。ISimpleAudioVolume、IAudioEndpointVolume等 如果不合适,可以将WAV文件直接加载到内存中,并在适当的位置修改样本。试试这个: 从磁盘读取W

我正在使用Win32多媒体功能播放应用程序中的声音

我希望能够在不修改系统音量的情况下动态调整正在播放的声音的音量


我能找到的唯一建议是使用该函数设置系统范围内的音量级别(不是我想要的)。

两种可能的解决方案:

首先,如果您的目标是Vista及以上版本,则可以使用新的Windows Audio API调整每个应用程序的音量。ISimpleAudioVolume、IAudioEndpointVolume等

如果不合适,可以将WAV文件直接加载到内存中,并在适当的位置修改样本。试试这个:

从磁盘读取WAV文件并将其放入内存缓冲区,然后将样本缩小。我将假设所讨论的WAV文件是带有未压缩(PCM)样本的16位立体声文件。立体声或单声道。如果不是的话,大部分都会被扔出窗外

我将把读取WAV文件字节放在内存中作为读者的练习:但让我们从下面的代码开始,其中“ReadWavFileIntoMemory”是您自己的函数

DWORD dwFileSize;
BYTE* pFileBytes;
ReadWavFileIntoMemory(szFilename, &pFileBytes, &dwFileSize);
此时,对pFileBytes的检查将如下所示:

RIFF....WAVEfmt ............data....
这是WAV文件头。“数据”是音频样本块的开始

查找“数据”部分,并将“数据”后面的4个字节读入DWORD。这是包含音频样本的“数据”块的大小。采样数(假设PCM 16位是该数字除以2)

现在,我们将创建一个示例指针,指向内存缓冲区中的第一个实际示例:

SHORT* pSample = (SHORT*)(pDataOffset + 8);
pSample指向WAV文件中的第一个16位样本。因此,我们准备将音频样本缩放到适当的音量级别。假设我们的音量范围在0.0到1.0之间。其中0.0表示完全静默。1.0是正常的全容量。现在我们只需将每个样本乘以目标体积:

float fVolume = 0.5; // half-volume
for (DWORD dwIndex = 0; dwIndex < dwNumSamples; dwIndex++)
{
    SHORT shSample = *pSample;
    shSample = (SHORT)(shSample * fVolume);
    *pSample = shSample;
    pSample++;


    if (((BYTE*)pSample) >= (pFileBytes + dwFileSize - 1))
       break;
}
这应该可以做到。如果您打算使用SND_ASYNC标志使上述调用成为非阻塞调用,那么在它完成播放之前,您将无法释放内存缓冲区。所以要小心


至于WAV文件头的解析。通过声明一个名为“FindDataChunk”的假设函数,我挥手走出了这一困境。您可能应该投资编写一个合适的WAV文件头解析器,而不仅仅是寻找头中第一次遇到“数据”的位置。为了简洁起见,我省略了通常的错误检查。因此,上面的代码可能有一些安全问题需要解决,特别是当它涉及到遍历内存缓冲区并写入内存缓冲区时。

添加@selbie clean solution作为实现的答案

#include <Windows.h>
#include <string>
#include <iostream>
#include <fstream>
#include <conio.h>

using namespace std;

void ReadWavFileIntoMemory(string fname, BYTE** pb, DWORD *fsize){
    ifstream f(fname, ios::binary);

    f.seekg(0, ios::end);
    int lim = f.tellg();
    *fsize = lim;

    *pb = new BYTE[lim];
    f.seekg(0, ios::beg);

    f.read((char *)*pb, lim);

    f.close();
}

int main(){
    DWORD dwFileSize;
    BYTE* pFileBytes;
    ReadWavFileIntoMemory("D:\\OpenAL 1.1 SDK\\samples\\media\\fiveptone.wav", &pFileBytes, &dwFileSize);

    BYTE* pDataOffset = (pFileBytes + 40);

    cout << "Length: " << dwFileSize << endl;

    float fVolume = 0.02;

    __int16 * p = (__int16 *)(pDataOffset + 8);
    cout << sizeof(*p) << endl;
    for (int i = 80 / sizeof(*p); i < dwFileSize / sizeof(*p); i++){
        p[i] = (float)p[i] * fVolume;
    }

    cout << "PlaySound" << endl;
    PlaySound((LPCSTR)pFileBytes, NULL, SND_MEMORY);

    return 0;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
无效ReadWavFileIntoMemory(字符串fname,字节**pb,DWORD*fsize){
ifstream f(fname,ios::binary);
f、 seekg(0,ios::end);
int lim=f.tellg();
*fsize=lim;
*pb=新字节[lim];
f、 seekg(0,ios::beg);
f、 读取((字符*)*pb,lim);
f、 close();
}
int main(){
DWORD文件大小;
字节*pFileBytes;
ReadWavFileIntoMemory(“D:\\OpenAL 1.1 SDK\\samples\\media\\fiveptone.wav”、&pFileBytes、&dwFileSize);
字节*pDataOffset=(pFileBytes+40);

回到这里。这些天我很高兴假设核心音频并完成它,但你的答案仍然很好!
PlaySound((LPCSTR)pFileBytes, NULL, SND_MEMORY);
#include <Windows.h>
#include <string>
#include <iostream>
#include <fstream>
#include <conio.h>

using namespace std;

void ReadWavFileIntoMemory(string fname, BYTE** pb, DWORD *fsize){
    ifstream f(fname, ios::binary);

    f.seekg(0, ios::end);
    int lim = f.tellg();
    *fsize = lim;

    *pb = new BYTE[lim];
    f.seekg(0, ios::beg);

    f.read((char *)*pb, lim);

    f.close();
}

int main(){
    DWORD dwFileSize;
    BYTE* pFileBytes;
    ReadWavFileIntoMemory("D:\\OpenAL 1.1 SDK\\samples\\media\\fiveptone.wav", &pFileBytes, &dwFileSize);

    BYTE* pDataOffset = (pFileBytes + 40);

    cout << "Length: " << dwFileSize << endl;

    float fVolume = 0.02;

    __int16 * p = (__int16 *)(pDataOffset + 8);
    cout << sizeof(*p) << endl;
    for (int i = 80 / sizeof(*p); i < dwFileSize / sizeof(*p); i++){
        p[i] = (float)p[i] * fVolume;
    }

    cout << "PlaySound" << endl;
    PlaySound((LPCSTR)pFileBytes, NULL, SND_MEMORY);

    return 0;
}