2010-02-20 554 views

回答

11

两个可能的解决方案:

首先,如果你的目标Vista和起来,你可以使用新的Windows音频API来调整每个应用程序的音量。 ISimpleAudioVolume,IAudioEndpointVolume等...

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

从磁盘读取WAV文件并将其存储到内存缓冲区中,然后将样本缩小。我将假定所讨论的WAV文件是16位立体声,带有未压缩(PCM)样本。立体声或单声道。如果不是这样,大部分情况都会消失。

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

DWORD dwFileSize; 
BYTE* pFileBytes; 
ReadWavFileIntoMemory(szFilename, &pFileBytes, &dwFileSize); 

在这一点上,pFileBytes的检查看起来类似以下内容:

RIFF....WAVEfmt ............data.... 

这是WAV文件头。 “数据”是音频采样块的开始。

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

// FindDataChunk is your function that parses the WAV file and returns the pointer to the "data" chunk. 
BYTE* pDataOffset = FindDataChunk(pBuffer); 
DWORD dwNumSampleBytes = *(DWORD*)(pDataOffset + 4); 
DWORD dwNumSamples = dwNumSamplesBytes/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; 
} 

此时,您就可以发挥你的内存WAV文件,PlaySound:

PlaySound((LPCSTR)pFileBytes, NULL, SND_MEMORY); 

而且应该这样做。如果您打算使用SND_ASYNC标志使上述调用非阻塞,那么在完成播放之前,您将无法释放内存缓冲区。所以要小心。

至于WAV文件头的解析。通过声明一个名为“FindDataChunk”的假设函数,我手动摆脱了这种方式。你可能应该投资编写一个适当的WAV文件头解析器,而不是仅仅寻求你在头中遇到“数据”的地方。为了简洁起见,我省略了通常的错误检查。因此,使用上述代码可能会遇到一些安全问题 - 尤其是涉及遍历内存缓冲区并写入内存缓冲区时。

+0

刚回到这。现在,我很高兴假设Core Audio已经完成了它,但你的答案非常好! – 2012-01-23 08:03:52

0

添加@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; 
} 

我遇到了正确的大小数据类型(这里我用__int16)在wav文件中操作的问题。

我使用的wav文件附带了OpenAL媒体文件“fiveptone.wav”。

请随意修改,因为我从wav文件和一些试验和错误的文件搜索偏移量。