书接上文,在学习笔记-C语言关于waveout接口的使用(一)中我们展示了如何正确但是有点不惜代价地使用waveOut接口播放音乐,而在(二)篇中,我们将展示如何一次只读取文件的一小部分,即不使用跟音乐文件大小相当的内存来播放音乐。
那么该怎么做呢,聪明的读者肯定想到了,哎我用while循环疯狂向设备写入小部分数据不就好了。的确,这样确实可以,但是每两次waveOutwrite之间会有让人无法忍受的间隔,各位可以动手改改试试。不想改也行,体贴的我已经为大伙准备好了对应的代码,直接运行就行。
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib,"Winmm.lib")
int main()
{
HWAVEOUT device; //设备句柄
WAVEFORMATEX wfx; //结构体初始化设置
WAVEHDR wave_buff; //wave缓存区设置
FILE* file;
int buffsize = 44100; //缓冲区大小
int file_tile; //文件结尾位置
wfx.nSamplesPerSec = 44100; //采样频率
wfx.wBitsPerSample = 16; //采样位深
wfx.nChannels = 2; //音道
wfx.cbSize = 0; //附加信息
wfx.wFormatTag = WAVE_FORMAT_PCM; //PCM编码格式,也可以赋1
wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
if(waveOutOpen(&device,WAVE_MAPPER,&wfx,0,0,CALLBACK_NULL)!=MMSYSERR_NOERROR)
{
fprintf(stderr, "unable to open WAVE_MAPPER device\n");
return 0;
}
printf("The Wave Mapper device was opened successfully!\n");
//打开文件
file = fopen("text.wav", "rb+");
if (file == NULL)
{
printf("无法打开文件\n");
return 0;
}
ZeroMemory(&wave_buff, sizeof(WAVEHDR)); //清空结构体数组内容
wave_buff.dwBufferLength = buffsize;
wave_buff.lpData = (unsigned char*)malloc(buffsize);
if (wave_buff.lpData == NULL)return NULL;
fseek(file, 0, SEEK_END);
file_tile = ftell(file); //获取文件大小
//跳过头文件
fseek(file, 44, SEEK_SET);
//将文件内容输入缓存并把缓存输出到设备
while (1)
{
//判断是否读到文件末尾
if (ftell(file) + buffsize >= file_tile)
{
buffsize = file_tile - ftell(file);
wave_buff.dwBufferLength = buffsize;
}
printf("%d %d\n", ftell(file),buffsize);
//读取音频文件数据
fread(wave_buff.lpData, sizeof(unsigned char), buffsize, file);
//准备要播放的缓冲区
waveOutPrepareHeader(device, &wave_buff, sizeof(WAVEHDR));
//将缓冲区写入设备
waveOutWrite(device, &wave_buff, sizeof(WAVEHDR));
//等待音乐播放结束,然后清理缓冲区
while(waveOutUnprepareHeader(device,&wave_buff,sizeof(WAVEHDR))==WAVERR_STILLPLAYING)
Sleep(10);
if (ftell(file) + buffsize >= file_tile)break;
}
waveOutClose(device);
fclose(file);
free(wave_buff.lpData);
return 0;
}
大伙运行就会发现这音乐怎么这么卡啊,确定,直接用while循环就会导致每次写入时来不及准备和清理缓冲区,所以接下来我们就得更深入的去使用更加美妙的代码了,敬请期待:
学习笔记-C语言关于waveout接口的使用(三)