Wave Driver介绍-3(Wave API waveOutSetVolume)
来源:互联网 发布:远程重启linux 编辑:程序博客网 时间:2024/05/23 01:15
1.1 定义及简要说明
函数waveOutSetVolume可以用来调整系统的音量,其定义如下:
MMRESULT WINAPI waveOutSetVolume(HWAVEOUT hwo, DWORD dwVolume);
其中,第一个参数HWAVEOUT hwo可以传入两种值,第一种是wave-out设备ID号,此时函数调整的是设备音量,第二种是Stream句柄,调整的是所指向的Stream的音量。
今天为这个地方晕乎乎了半天,最后还是写了点测试程序才搞懂,有关这个函数的具体使用方法及操作细节请看下面的验证过程。
注:
下面的代码实际上是一个应用程序中部分代码,有关该应用程序的源码可以从我的资源中下载,主界面如下:
1.2 给函数传入wave-out设备ID的验证
下面的代码实现了对设备音量进行调整的功能,对应上图中的Loud和Soft按键的功能。其中函数void CWaveAPI_TestDlg::OnBnClickedButton1()实现了将设备音量(0~0xffff ffff)增加0x1000的功能,也即Loud按钮的功能,而按钮Soft的功能由函数void CWaveAPI_TestDlg::OnBnClickedButton2()实现,每次点击该按钮设备音量将减少0x1000。
详细如下:
static DWORD g_dwWaveOutGain = 0;
void CWaveAPI_TestDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
DWORD dwDeviceID = 0;
DWORD deDeviceGain = 0;
for (dwDeviceID = 0; dwDeviceID < waveOutGetNumDevs(); dwDeviceID++) {
NKDbgPrintfW(L"Device #%d/r/n", dwDeviceID);
waveOutSetVolume((HWAVEOUT)dwDeviceID, g_dwWaveOutGain);
waveOutGetVolume((HWAVEOUT)dwDeviceID, &deDeviceGain);
NKDbgPrintfW(L"/r/n dst 0x%8x, read 0x%8x/r/n", g_dwWaveOutGain, deDeviceGain);
if (g_dwWaveOutGain <= (0xffffffff - 0x1000))
g_dwWaveOutGain+=0x1000;
else
g_dwWaveOutGain = 0xffffffff;
}
}
void CWaveAPI_TestDlg::OnBnClickedButton2()
{
// TODO: Add your control notification handler code here
DWORD dwDeviceID = 0;
DWORD deDeviceGain = 0;
for (dwDeviceID = 0; dwDeviceID < waveOutGetNumDevs(); dwDeviceID++) {
NKDbgPrintfW(L"Device #%d/r/n", dwDeviceID);
waveOutSetVolume((HWAVEOUT)dwDeviceID, g_dwWaveOutGain);
waveOutGetVolume((HWAVEOUT)dwDeviceID, &deDeviceGain);
NKDbgPrintfW(L"/r/n dst 0x%8x, read 0x%8x/r/n", g_dwWaveOutGain, deDeviceGain);
if (g_dwWaveOutGain >= 0x1000)
g_dwWaveOutGain-=0x1000;
else
g_dwWaveOutGain = 0;
}
}
1.3 给函数传入Stream句柄的验证
下面的代码中包括下面三个函数:
int StringFormatToWaveFormatEx( WAVEFORMATEX *wfx, const TCHAR* szWaveFormat );
ULONG SineWave( void* pBuffer, ULONG ulNumBytes, WAVEFORMATEX *pwfx, double dFrequency );
void PlayBackSound(bool bLoud);
其中第一个函数StringFormatToWaveFormatEx实现了格式转换的功能。我们一般都习惯上使用形如“WAVE_FORMAT_1M08”的标记来表示wave in/out的格式,该函数完成在形如“WAVE_FORMAT_1M08”的标志和结构体WAVEFORMATEX之间进行等价转换的功能。
/* defines for dwFormat field of WAVEINCAPS and WAVEOUTCAPS */
#define WAVE_INVALIDFORMAT 0x00000000 /* invalid format */
#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */
#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */
#define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */
#define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */
#define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */
#define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */
#define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */
#define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */
#define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */
#define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */
#define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */
#define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */
typedef struct
{
WORD wFormatTag; // format type
WORD nChannels; // number of channels (i.e. mono, stereo...)
DWORD nSamplesPerSec; // sample rate
DWORD nAvgBytesPerSec; // for buffer estimation
WORD nBlockAlign; // block size of data
WORD wBitsPerSample; // number of bits per sample of mono data
WORD cbSize; // the count in bytes of the size of
// extra information (after cbSize)
} WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX;
接下来说第二个函数SineWave,它完成根据调用者传入的参数构建正选波数据到pBuffer的功能,可以省却我们解析wav文件的烦恼。
第三个函数PlayBackSound是今天的主角,它完成了创建Stream,并使用Stream播放音频的同时调整音量的功能。
详细的代码如下:
// 转换数据
int StringFormatToWaveFormatEx( WAVEFORMATEX *wfx, const TCHAR* szWaveFormat )
{
int iRet;
DWORD tr=true;
TCHAR channels,bits1,bits2;
ZeroMemory(wfx,sizeof(*wfx));
iRet = _stscanf ( szWaveFormat, TEXT("WAVE_FORMAT_%i%c%c%c"), &wfx->nSamplesPerSec, &channels, &bits1, &bits2 );
if( iRet != 4 )
{
NKDbgPrintfW( ( TEXT( "ERROR: %s not recognized/n" ), (LPWSTR)szWaveFormat ) );
NKDbgPrintfW(TEXT("Possible Cause: Supplied format not in the form of WAVE_FORMAT%%i%%c%%c%%c/n"));
tr = false;
goto Error;
}
wfx->wFormatTag = WAVE_FORMAT_PCM;
switch( channels )
{
case 'M':
case 'm':
wfx->nChannels=1;
break;
default:
wfx->nChannels=2;
}
switch( wfx->nSamplesPerSec )
{
case 1:
case 2:
case 4:
wfx->nSamplesPerSec=11025*wfx->nSamplesPerSec;
}
wfx->wBitsPerSample=(bits1-TEXT('0'))*10+(bits2-TEXT('0'));
wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign;
Error:
return tr;
}
// 产生正选波数据
ULONG SineWave( void* pBuffer, ULONG ulNumBytes, WAVEFORMATEX *pwfx, double dFrequency )
{
double dPhase = 0.0;
double dAmplitude = 1.0;
char *pClear, *pClearEnd;
const double TWOPI = 2* 3.1415926535897931;
pClearEnd = (char*)pBuffer + ulNumBytes;
pClear = pClearEnd - ulNumBytes % 4;
while( pClear<pClearEnd )
{
*pClear = 0;
pClear++;
}
int nsamples = ulNumBytes / pwfx->nBlockAlign;
int i, m_t0 = 0;
int m_dSampleRate = pwfx->nSamplesPerSec;
double dMultiplier, dOffset, dSample;
if( pwfx->wBitsPerSample == 8 )
{
unsigned char * pSamples = (unsigned char *) pBuffer;
dMultiplier = 127.0;
dOffset = 128.0;
if( pwfx->nChannels == 1 )
{
for (i = 0; i < nsamples; i ++ )
{
double t = ((double) (i+m_t0)) / m_dSampleRate;
dSample = dAmplitude * sin( t*dFrequency* TWOPI + dPhase );
pSamples[i] = (unsigned char) (dSample * dMultiplier + dOffset);
}
}
else
{
for (i = 0; i < nsamples; i ++)
{
double t = ((double) (i+m_t0)) / m_dSampleRate;
dSample = dAmplitude * sin (t*dFrequency* TWOPI + dPhase);
pSamples[2*i] = (unsigned char) (dSample * dMultiplier + dOffset);
pSamples[2*i+1] = pSamples[2*i]; // replicate across both channels
}
}
}
else
{
short * pSamples = (short *) pBuffer;
const double dMultiplier2 = 32767.0;
const double dOffset2 = 0.0;
if( pwfx->nChannels == 1 )
{
for (i = 0; i < nsamples; i += 1)
{
double t = ((double) (i+m_t0)) / m_dSampleRate;
dSample = dAmplitude * sin (t*dFrequency* TWOPI + dPhase);
pSamples[i] = (short) (dSample * dMultiplier2 + dOffset2);
}
}
else
{
for (i = 0; i < nsamples; i ++)
{
double t = ((double) (i+m_t0)) / m_dSampleRate;
dSample = dAmplitude * sin( t*dFrequency* TWOPI + dPhase );
pSamples[2*i] = (short) (dSample * dMultiplier2 + dOffset2);
pSamples[2*i+1] = pSamples[2*i]; // replicate across both channels
}
}
}
m_t0 += i;
return ulNumBytes;
}
/*
功能:
播放正选波声音文件
参数:
bLoud:调整播放声音增益
true: 增大
false: 减小
返回值:
无
*/
void PlayBackSound(bool bLoud)
{
// TODO: Add your control notification handler code here
HWAVEOUT hwo = NULL;
WAVEFORMATEX wfx;
MMRESULT hr;
static HANDLE hEvent;
WAVEHDR wh;
char *data = NULL;
DWORD dwSeconds = 1;
double dFrequency = 440.0;
DWORD dwExpectedPlaytime, dwTime = 0;
DWORD dwSleepInterval = 50; //50 milliseconds
// ***********************************************************************
// 1. 初始化相关资源
// ***********************************************************************
// 初始化WAVEFORMATEX变量wfx
if (!StringFormatToWaveFormatEx(&wfx,TEXT("WAVE_FORMAT_2M16"))) {
NKDbgPrintfW(L"Convert Audio Format Failed!/r/n");
return ;
}
// 输出格式信息
NKDbgPrintfW(L"************************************/r/n");
NKDbgPrintfW(L"wfx.wBitsPerSample %d/r/n", wfx.wBitsPerSample);
NKDbgPrintfW(L"wfx.nChannels %d/r/n", wfx.nChannels);
NKDbgPrintfW(L"wfx.nSamplesPerSec %d/r/n", wfx.nSamplesPerSec);
NKDbgPrintfW(L"************************************/r/n");
hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
// 打开wave out设备
hr = waveOutOpen(&hwo, 0, &wfx, NULL,(DWORD)hEvent, CALLBACK_NULL);
if(hr != MMSYSERR_NOERROR)
{
NKDbgPrintfW(L"waveOutOpen failed! Error number 0x%x/r/n", hr);
return ;
}
// 分配buffer
data = new char[dwSeconds * wfx.nAvgBytesPerSec];
if (!data) {
NKDbgPrintfW(L"Out of memeory/r/n");
return ;
}
ZeroMemory(data, dwSeconds * wfx.nAvgBytesPerSec);
// 初始化wh(WAVEHDR)
ZeroMemory(&wh, sizeof(WAVEHDR));
wh.lpData = data;
wh.dwBufferLength = dwSeconds * wfx.nAvgBytesPerSec;
wh.dwLoops = 1;
wh.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
dwExpectedPlaytime = wh.dwBufferLength * 1000 / wfx.nAvgBytesPerSec;
// 创造声波
SineWave(wh.lpData, wh.dwBufferLength, &wfx,dFrequency );
// ***********************************************************************
// 2. 开始播放声音操作
// ***********************************************************************
// 调整Stream音量
DWORD deDeviceGain = 0;
waveOutSetVolume((HWAVEOUT)hwo, g_dwWaveOutGain);
waveOutGetVolume((HWAVEOUT)hwo, &deDeviceGain);
NKDbgPrintfW(L"Volume of device 0 successfully set to 0x%8x, previous 0x%8x/r/n", g_dwWaveOutGain, deDeviceGain);
if (bLoud) {
if (g_dwWaveOutGain <= (0xffffffff - 0x1000))
g_dwWaveOutGain+=0x1000;
else
g_dwWaveOutGain = 0xffffffff;
}else {
if (g_dwWaveOutGain >= 0x1000)
g_dwWaveOutGain-=0x1000;
else
g_dwWaveOutGain = 0;
}
// 准备buffer
hr = waveOutPrepareHeader(hwo, &wh, sizeof(WAVEHDR));
if(hr != MMSYSERR_NOERROR)
{
NKDbgPrintfW(L"waveOutPrepareHeader failed! Error number 0x%x/r/n", hr);
return ;
}
// 写入buffer
hr = waveOutWrite(hwo, &wh, sizeof(WAVEHDR));
while( (!(wh.dwFlags&WHDR_DONE)) && ( dwTime<dwExpectedPlaytime+1000) )
{
Sleep( dwSleepInterval );
dwTime += dwSleepInterval;
}
// ***********************************************************************
// 3. 销毁所有资源
// ***********************************************************************
NKDbgPrintfW(L"Destroy all the resource/r/n");
waveOutReset(hwo);
if(hr != MMSYSERR_NOERROR) {
NKDbgPrintfW(L"waveOutUnprepareHeader failed! Error number 0x%x/r/n", hr);
return ;
}
hr = waveOutUnprepareHeader(hwo,&wh,sizeof(WAVEHDR) );
if(hr != MMSYSERR_NOERROR) {
NKDbgPrintfW(L"waveOutUnprepareHeader failed! Error number 0x%x/r/n", hr);
return ;
}
waveOutClose(hwo);
if(hr != MMSYSERR_NOERROR) {
NKDbgPrintfW(L"waveOutUnprepareHeader failed! Error number 0x%x/r/n", hr);
return ;
}
if (data)
delete []data;
if( hEvent)
CloseHandle(hEvent);
}
前面提到,应用程序中有四个按钮,左边的两个按钮已经讲过,右边的两个按钮“Loud Stream”和“Soft Stream”的实现就是通过调用上面的函数PlayBackSound完成,这部分代码如下:
void CWaveAPI_TestDlg::OnBnClickedButton3()
{
PlayBackSound(true);
}
void CWaveAPI_TestDlg::OnBnClickedButton4()
{
// TODO: Add your control notification handler code here
PlayBackSound(false);
}
- Wave Driver介绍-3(Wave API waveOutSetVolume)
- Wave Driver介绍-3(Wave API waveOutSetVolume)
- Wave Driver介绍-4(Wave API waveOutOpen)
- Wave Driver介绍
- Wave Driver介绍-1(PCM文件格式)
- Wave Driver介绍-2(WAV文件格式)
- Wave Driver介绍-8(软件混音器)
- Wave Driver介绍-1(PCM文件格式)
- Wave Driver介绍-2(WAV文件格式)
- Wave Driver介绍-8(软件混音器)
- Wave Driver介绍-5(Waveform Audio Driver Test测试Case描述)
- Wave Driver介绍-5(Waveform Audio Driver Test测试Case描述)
- wave
- wave
- wave
- Wave Driver介绍-6(控制面板中的音量调整工具)
- Wave Driver介绍-7(驱动中对音量的控制操作-非硬件音量控制)
- Wave Driver介绍-6(控制面板中的音量调整工具)
- LCS算法
- POJ1013解题报告
- iis错误Server Application Error的解决方法
- 最早的计算机病毒
- 一周小结
- Wave Driver介绍-3(Wave API waveOutSetVolume)
- 打开Win7家庭普通版全部Aero特效
- Ubuntu添加开机自动启动程序的方法
- Using EzSetup for creating Pocket PC installations
- 解读iPhone平台的一些优秀设计思路
- fedora13下安装quartus 10.0sp1与niosII 10.0sp1
- 使用Android自带Gallery组件实现CoverFlow,源码+解析
- SVN+Apache+AnkhSVN(或者VISUALSVN)搭建版本控制环境
- 在EditText 过滤Filtering 数据