用过wavOut系列的函数帮帮忙啊!

yangkunhenry 2009-12-15 05:11:00

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
switch(uMsg)
{
case WOM_DONE:
break;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
HWAVEOUT hDevice;
HANDLE hFile = CreateFile(L"D:\\ws.wav",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
long int nFilelen=GetFileSize(hFile,NULL);
DWORD dwRead=0;
DWORD nChannels=0;
DWORD nSamplesPerSec=0;
long int nAvgBytesPerSec=0;
DWORD nBlockAlign = 0;
DWORD wBitsPerSample = 0;
long int nFileSize = 0;
SetFilePointer(hFile,0x16,NULL,FILE_BEGIN);
ReadFile(hFile,&nChannels,2,&dwRead,NULL);
SetFilePointer(hFile,0x18,NULL,FILE_BEGIN);
ReadFile(hFile,&nSamplesPerSec,2,&dwRead,NULL);
SetFilePointer(hFile,0x1c,NULL,FILE_BEGIN);
ReadFile(hFile,&nAvgBytesPerSec,4,&dwRead,NULL);
SetFilePointer(hFile,0x20,NULL,FILE_BEGIN);
ReadFile(hFile,&nBlockAlign,2,&dwRead,NULL);
SetFilePointer(hFile,0x22,NULL,FILE_BEGIN);
ReadFile(hFile,&wBitsPerSample,2,&dwRead,NULL);
SetFilePointer(hFile,0x28,NULL,FILE_BEGIN);
ReadFile(hFile,&nFileSize,4,&dwRead,NULL);
CloseHandle(hFile);
WAVEFORMATEX waveformat;
waveformat.cbSize = sizeof(WAVEFORMATEX);
waveformat.nAvgBytesPerSec = nAvgBytesPerSec;
waveformat.nBlockAlign = nBlockAlign;
waveformat.nChannels = nChannels;
waveformat.nSamplesPerSec = nSamplesPerSec;
waveformat.wBitsPerSample = 2*wBitsPerSample;
waveformat.wFormatTag = WAVE_FORMAT_PCM;
DWORD test = 0;
if(MMSYSERR_NOERROR != (test=waveOutOpen(NULL,WAVE_MAPPER,(WAVEFORMATEX*)&waveformat,NULL,NULL,WAVE_FORMAT_QUERY)))
{
MessageBox(NULL,L"Open Error!",L"Error",0);
return 1;
}
if(MMSYSERR_NOERROR!=(test=waveOutOpen(&hDevice,WAVE_MAPPER,(WAVEFORMATEX*)&waveformat,/*(DWORD)waveOutProc*/NULL,0,/*CALLBACK_FUNCTION*/NULL)))
{
return 1;
}

FILE *file=fopen("D:\\ws.wav","rb");
//fseek(file,44,SEEK_SET);

WAVEHDR wavehdr;
ZeroMemory(&wavehdr,sizeof(wavehdr));
wavehdr.dwBufferLength = nFilelen-44;
wavehdr.lpData = (char*)(file+44);//这个地方用的对不?

test =waveOutPrepareHeader(hDevice,&wavehdr,sizeof(wavehdr));//这里返回11,不知道怎么改了。
test=waveOutWrite(hDevice,&wavehdr,sizeof(wavehdr));
Sleep(1000*60);

return 0;

}

想写个wav格式的文件播放器,遇到问题了,各位帮帮忙哈……谢谢喽。
...全文
177 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
z6482 2012-04-25
  • 打赏
  • 举报
回复
现在回复算挖坟么?真的挺有用的。。
waveformat.wBitsPerSample = 2*wBitsPerSample;
这句好像有问题,我将前面的*2去掉之后才可用。
yschat 2009-12-18
  • 打赏
  • 举报
回复
学习
yangkunhenry 2009-12-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 superly 的回复:]
fread(wavehdr.lpData, nFilelen, 1, file);//读取数据
其中nFilelen就是读取长度,减小这个值,就可以多次读取了;

fseek(file,44,SEEK_SET);//跳过文件头,也可以用:fread(wavehdr.lpData, 44, 1, file);
int ret = 0;
int EachReadLen = 1024;//每次读1KByte
while (ret != EOF)
{
ret = fread(wavehdr.lpData, EachReadLen, 1, file);
while ((wavehdr.dwFlags&WHDR_DONE)==0) Sleep(15);//等待播放完成
......
}
MSDN说明:
When the buffer is finished, the WHDR_DONE bit is set in the dwFlags member of the WAVEHDR structure.
所以可以如下等待播放完成:
while ((wavehdr.dwFlags&WHDR_DONE)==0) Sleep(15);
[/Quote]
这样的话声音会发生间断,我看网上有说双缓冲处理的,到底是怎么个处理方法?老大还说让搞个6缓冲的……
yangkunhenry 2009-12-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 superly 的回复:]
fread(wavehdr.lpData, nFilelen, 1, file);//读取数据
其中nFilelen就是读取长度,减小这个值,就可以多次读取了;

fseek(file,44,SEEK_SET);//跳过文件头,也可以用:fread(wavehdr.lpData, 44, 1, file);
int ret = 0;
int EachReadLen = 1024;//每次读1KByte
while (ret != EOF)
{
ret = fread(wavehdr.lpData, EachReadLen, 1, file);
while ((wavehdr.dwFlags&WHDR_DONE)==0) Sleep(15);//等待播放完成
......
}
MSDN说明:
When the buffer is finished, the WHDR_DONE bit is set in the dwFlags member of the WAVEHDR structure.
所以可以如下等待播放完成:
while ((wavehdr.dwFlags&WHDR_DONE)==0) Sleep(15);
[/Quote]
好的 ,我试试!谢谢大哥了!
SuperLy 2009-12-16
  • 打赏
  • 举报
回复
fread(wavehdr.lpData, nFilelen, 1, file);//读取数据
其中nFilelen就是读取长度,减小这个值,就可以多次读取了;

fseek(file,44,SEEK_SET);//跳过文件头,也可以用:fread(wavehdr.lpData, 44, 1, file);
int ret = 0;
int EachReadLen = 1024;//每次读1KByte
while (ret != EOF)
{
ret = fread(wavehdr.lpData, EachReadLen, 1, file);
while ((wavehdr.dwFlags&WHDR_DONE)==0) Sleep(15);//等待播放完成
......
}
MSDN说明:
When the buffer is finished, the WHDR_DONE bit is set in the dwFlags member of the WAVEHDR structure.
所以可以如下等待播放完成:
while ((wavehdr.dwFlags&WHDR_DONE)==0) Sleep(15);
SuperLy 2009-12-16
  • 打赏
  • 举报
回复
1)声明两个WAVEHDR结构waveHeader1,waveHeader2,并分别对其lpData参数分配缓冲buf1,buf2;

2)声明WAVEFORMATEX结构waveFormat,以及HWAVEOUT结构hWaveOut。调用函数
waveOutOpen( &hWaveOut, WAVE_MAPPER, &waveFormat, (DWORD)waveOutProc, NULL, CALLBACK_FUNCTION );
waveOutProc为回调函数,在后面会提到。


也说一下waveFormat的各参数。根据MSDN解释,nChannels为通道数,nSamplesPerSec为采样率,wFormatTag的值为WAVE_FORMAT_PCM,wBitsPerSample为16,nBlockAlign为nChannels*wBitsPerSample/8,nAvgBytesPerSec为nSamplesPerSec*nBlockAlign;

3)读入buf1,buf2,并设置好相应长度;

4)将waveHeader1,waveHeader2写入wave设备:
waveOutPrepareHeader( hWaveOut, &waveHeader1, sizeof(WAVEHDR));
waveOutPrepareHeader( hWaveOut, &waveHeader2, sizeof(WAVEHDR));

waveOutWrite( hWaveOut, &waveHeader1, sizeof(WAVEHDR) );
waveOutWrite( hWaveOut, &waveHeader2, sizeof(WAVEHDR) );

5)关于回调
void CALLBACK waveOutProc( HWAVEOUT hwo,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2 )
{
if(uMsg == WOM_DONE)
{
LPWAVEHDR pWaveHeader = (LPWAVEHDR)dwParam1;//系统自动识别是哪一个WAVEHDR播放完毕

waveOutUnprepareHeader( hwo, pWaveHeader, sizeof(WAVEHDR) );//播放完后须调用此函数

//此处填充WAVEHDR的lpdate缓冲

waveOutPrepareHeader( hwo, pWaveHeader, sizeof(WAVEHDR));
waveOutWrite( hwo, pWaveHeader, sizeof(WAVEHDR) );

//...
}
return ;
}

6)播放完毕后,调用waveOutClose,释放缓冲。其他的一些waveOut函数,如waveOutPause、waveOutReset等等,在做播放器的时候会用得到。若播放过程中终止,须先调用waveOutReset,再调用waveOutClose。
yangkunhenry 2009-12-15
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 superly 的回复:]
  FILE *file=fopen("D:\\ws.wav","rb");

  file 是文件句柄指针,并非指向文件真实数据,所以要:
  wavehdr.lpData =new char[nFilelen];//分配空间
    fread(wavehdr.lpData, nFilelen, 1, file);//读取数据


...
delete []wavehdr.lpData;
[/Quote]
谢谢了!!!
还有如果这个文件很大,需要将其分块传人内存再进行读取,怎么读?怎么知道一段声音已经放完了?
SuperLy 2009-12-15
  • 打赏
  • 举报
回复
FILE *file=fopen("D:\\ws.wav","rb");

file 是文件句柄指针,并非指向文件真实数据,所以要:
wavehdr.lpData =new char[nFilelen];//分配空间
fread(wavehdr.lpData, nFilelen, 1, file);//读取数据


...
delete []wavehdr.lpData;
yangkunhenry 2009-12-15
  • 打赏
  • 举报
回复

wavehdr.lpData = (char*)(file+44);//这个地方用的对不?

这句改成
wavehdr.lpData =/* (char*)(file+44)*/new char[nFilelen-44+1];
以后的函数就可以返回正确的值,但是仍然播放不出音乐。这个指针到底该怎么设啊?

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧