WAV,MDI播放

以下代码测试能正常运行,供参考

代码包括DirectSound播放wav声音,但是只能播放PMC格式wav,对ADPCM的WAV无法播放,网上资料好像说要解码ADPCM,有高手看到的话求解下,还有利用mciSendCommand播放声音-好像说这个只能播放单个声音,后面就是DirectMusic对wav和MDI的播放

// TestSoundPlay.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windowsx.h>
#include <dsound.h>
#include "dmusici.h"
#include "dxutil.h"
#include <iostream>
#include <sstream>
#include <string>
#include <math.h>
#include <conio.h>
#include<Digitalv.h>
#include <assert.h>
using namespace std;
#pragma comment( lib, "winmm.lib")
#pragma comment( lib, "dxerr8.lib")
#pragma comment( lib, "dsound.lib")
#pragma comment( lib, "dxguid.lib")
#pragma comment( lib, "strmiids.lib")
//#pragma comment( lib, "odbc32.lib")
//#pragma comment( lib, "odbccp32.lib")


HWND g_hWnd = NULL;
/***获取控制台窗口句柄方法1***/
typedef HWND (WINAPI *PROCGETCONSOLEWINDOW)();
PROCGETCONSOLEWINDOW GetConsoleWindow;
HWND GetWindHwnd()
{
	
	HMODULE hKernel32 = GetModuleHandle("kernel32");
	GetConsoleWindow = (PROCGETCONSOLEWINDOW)GetProcAddress(hKernel32,"GetConsoleWindow");
	return GetConsoleWindow();
}
/***获取控制台窗口句柄方法2***/
HWND GetConsoleWindowHandle()
{
	char title[512];
	HWND hWnd;

	GetConsoleTitle(title, sizeof(title));
	hWnd = FindWindow(NULL, title);
	return(hWnd);
}
//枚举声音设备
BOOL CALLBACK DSEnumProc(LPGUID lpGUID, 
						 LPCTSTR lpszDesc,
						 LPCTSTR lpszDrvName, 
						 LPVOID lpContext )
{
	HWND hCombo = *(HWND *)lpContext;
	LPGUID lpTemp = NULL;

	if ( lpGUID != NULL )
	{
		if (( lpTemp = LPGUID(malloc( sizeof(GUID)))) == NULL )
			return( TRUE );

		memcpy( lpTemp, lpGUID, sizeof(GUID));
	}

	ComboBox_AddString( hCombo, lpszDesc );
	ComboBox_SetItemData( hCombo,
		ComboBox_FindString( hCombo, 0, lpszDesc ),
		lpTemp );
	return( TRUE );
}

LPDIRECTSOUND8 m_pSound;     //wav

struct WAVE_HEADER
{
	char    riff_sig[4];            // 'RIFF'
	long    waveform_chunk_size;    // 8
	char    wave_sig[4];            // 'WAVE'
	char    format_sig[4];          // 'fmt ' (notice space after)
	long    format_chunk_size;      // 16;
	short   format_tag;             // WAVE_FORMAT_PCM
	short   channels;               // # of channels
	long    sample_rate;            // sampling rate
	long    bytes_per_sec;          // bytes per second
	short   block_align;            // sample block alignment
	short   bits_per_sample;        // bits per second
	char    data_sig[4];            // 'data'
	DWORD   data_size;              // size of waveform data
};
const TCHAR* GetDefaultFilePath(string &str)
{
	TCHAR szPath[MAX_PATH] = {NULL};
	GetModuleFileName((HMODULE)NULL, szPath, MAX_PATH);
	string  strPath =szPath;
	strPath = strPath.substr(0, strPath.rfind(_T('\\')) + 1);
	str = strPath;
	return str.c_str();
}
//从文件加载资源-辅缓冲-储存实际音频数据
IDirectSoundBuffer* CreateBufferFromFile(const TCHAR* pszName)
{
	TCHAR szPath[MAX_PATH] = {NULL};
	GetModuleFileName((HMODULE)NULL, szPath, MAX_PATH);
	string  strPath =szPath;
	strPath = strPath.substr(0, strPath.rfind(_T('\\')) + 1);
	strPath.append(pszName);
	pszName = strPath.c_str();

	HANDLE hFile = ::CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		WAVE_HEADER wh = { 0 };
		DWORD dwRet = 0;
		char chTest[20] = { 0 };
		char chUseless[4] = {0};
		DWORD dwRet2 = 0;
		ReadFile(hFile, &wh, sizeof(WAVE_HEADER), &dwRet, NULL);
	
		//check the 'fact' field
		if (memcmp(wh.data_sig,"fact",4) == 0)
		{
			ReadFile(hFile,&chUseless,4,&dwRet2,NULL);
			ReadFile(hFile,&wh.data_sig,4,&dwRet2,NULL);
			ReadFile(hFile,&wh.data_size,4,&dwRet2,NULL);
		}
		// check the sig fields. returning if an error.
		if(memcmp(wh.riff_sig, "RIFF", 4)   || memcmp(wh.wave_sig, "WAVE", 4) ||
			memcmp(wh.format_sig, "fmt ", 4) || memcmp(wh.data_sig, "data", 4)|| 
			(wh.data_size == 0))
		{
			CloseHandle(hFile);
			return NULL;
		}

		WAVEFORMATEX wave_format = { 0 };
		wave_format.wFormatTag      = WAVE_FORMAT_PCM;
		wave_format.nChannels       = wh.channels;
		wave_format.nSamplesPerSec  = wh.sample_rate;
		wave_format.wBitsPerSample  = wh.bits_per_sample;
		wave_format.nBlockAlign     = wave_format.wBitsPerSample / 8 * wave_format.nChannels;
		wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign;

		DSBUFFERDESC dsbd = { 0 };
		dsbd.dwSize          = sizeof(DSBUFFERDESC);
		dsbd.dwFlags         = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
		dsbd.dwBufferBytes   = wh.data_size;
		dsbd.lpwfxFormat     = &wave_format;

		IDirectSoundBuffer* pBuffer = NULL;
		HRESULT hr = m_pSound->CreateSoundBuffer(&dsbd, &pBuffer, NULL);
		if (FAILED(hr))
		{
			CloseHandle(hFile);
			return NULL;
		}

		void* pV = NULL; // Pointer to locked buffer memory
		dwRet = 0;
		// 锁定缓冲区-用于写入数据
		if (FAILED(hr = pBuffer->Lock(0, wh.data_size, &pV, &dwRet, NULL, NULL, 0L)))
		{
			CloseHandle(hFile);
			return NULL;
		}

		//读入数据
		ReadFile(hFile, pV, wh.data_size, &dwRet, NULL);
		if (dwRet == 0)
		{
			// Wav is blank, so just fill with silence
			FillMemory((BYTE*)pV, wh.data_size,(BYTE)(wave_format.wBitsPerSample == 8 ? 128 : 0 ));
		}
		else if (dwRet < wh.data_size)
		{
			FillMemory(((BYTE*)pV + dwRet), wh.data_size - dwRet,(BYTE)(wave_format.wBitsPerSample == 8 ? 128 : 0 ));
		}
		pBuffer->Unlock(pV, wh.data_size, NULL, 0 );
		return pBuffer;
	}
	return NULL;
}
//设置主缓冲区格式
bool SetPrimBuffFmat(HRESULT &hr)
{
	LPDIRECTSOUNDBUFFER pDSBPrimary;

	// Get the primary buffer
	DSBUFFERDESC dsbd;
	ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
	dsbd.dwSize        = sizeof(DSBUFFERDESC);
	dsbd.dwFlags       = DSBCAPS_PRIMARYBUFFER;//主缓冲标记,详见ReadMe.txt
	dsbd.dwBufferBytes = 0;
	dsbd.lpwfxFormat   = NULL;

	if(FAILED(m_pSound->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL)))
	{
		return false;
	}

	// 设置音频格式属性
	WAVEFORMATEX wfx;
	ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); 
	wfx.wFormatTag      = WAVE_FORMAT_PCM; 
	wfx.nChannels       = (WORD)2; 
	wfx.nSamplesPerSec  = 22050; // 22 Khz (CD quality is ~ 44 Khz, so this is "half-CD" quality)
	wfx.wBitsPerSample  = (WORD) 16; // 2 bytes per sample * 22050 samples/sec = 44100 bytes/sec)
	wfx.nBlockAlign     = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
	wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;

	if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) ) {
		return 0;
	}

	// 释放主缓冲区接口-非物理删除,COM对象只有在所有接口都释放时才删除
	SAFE_RELEASE( pDSBPrimary );
	return 0;
}
// wav play
IDirectSoundBuffer *pDSBuffer = NULL;
int PlayForWav(char *Filename = NULL)
{
	//枚举声音设备
	/*************
	HWND cmd = GetWindHwnd();
	HWND hCombo = cmd;
	//DSDEVID_DefaultPlayback-声音播放设备,可以通过DirectSoundEnumerate 枚举出所有可用设备
	if FAILED(DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc,
		(VOID*)&hCombo))
	{
		return( TRUE );
	}
	****************/

	//创建设备对象
	HRESULT hr = DirectSoundCreate8(&DSDEVID_DefaultPlayback, &m_pSound, NULL);
	if (FAILED(hr))
	{
		return 0;
	}
	//设置声音协作度--多个程序可能使用同个设备,为防止冲突,不设置则没声音
	if(FAILED(hr = m_pSound->SetCooperativeLevel(GetConsoleWindowHandle(), DSSCL_NORMAL))) {
		return 0;
	}
	//设置主缓冲区格式
	SetPrimBuffFmat(hr);
	//加载资源
	pDSBuffer=CreateBufferFromFile(Filename);
	if(pDSBuffer != NULL) {
		// Play sound looping
		pDSBuffer->SetCurrentPosition(0);
		pDSBuffer->SetVolume(DSBVOLUME_MAX);
		pDSBuffer->Play(0,0,DSBPLAY_LOOPING);
	}
	return 1;
}

// mid playe intface
// DirectMusic Performance, loader, and segment objects
IDirectMusicPerformance8 *g_pDMPerformance;  // 演奏对象
IDirectMusicLoader8      *g_pDMLoader;       // 加载器
IDirectMusicSegment8     *g_pDMSegment;      // 将要播放的生效段
IDirectMusicAudioPath    *g_pDMPath;
void InitMidPlay()
{
	CoInitialize(0);
	// Create the DirectMusic loader object
	CoCreateInstance(CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC, 
		IID_IDirectMusicLoader8, (void**)&g_pDMLoader);

	// Create the DirectMusic performance object
	CoCreateInstance(CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC, 
		IID_IDirectMusicPerformance8, (void**)&g_pDMPerformance);
	// Initialize the performance with the standard audio path.
	// This initializes both DirectMusic and DirectSound and 
	// sets up the synthesizer. 
	//g_pDMPerformance->InitAudio(NULL,         // 指向一个关联的IDirectMusic对象
	//	NULL,                                 // 指向一个关联的IDirectSound对象
	//	g_hWnd,                               // 播放关联窗口,可以NULL
	//	DMUS_APATH_SHARED_STEREOPLUSREVERB,   // 声音通道格式:立体声混响,3D音效,单声道,立体声
	//	128,                                  // 音乐通道数量
	//	DMUS_AUDIOF_ALL,                      // 声音播放参数-效果
	//	NULL                                  // 指向一个DMUS_AUDIOPARAMS对象,更纤细地说明各种参数
	//	);
	g_pDMPerformance->InitAudio(NULL, NULL, g_hWnd,
		DMUS_APATH_SHARED_STEREOPLUSREVERB, 64,
		DMUS_AUDIOF_ALL, NULL);
	//g_pDMpath 控制音量
	g_pDMPerformance->GetDefaultAudioPath(&g_pDMPath);
	// Tell DirectMusic where the default search path is
	char strPath[MAX_PATH];
	WCHAR wstrSearchPath[MAX_PATH];
	//GetCurrentDirectory(MAX_PATH, strPath);
	string str;
	const char *Path = GetDefaultFilePath(str);
	sprintf(strPath,Path);
	MultiByteToWideChar(CP_ACP, 0, strPath, -1, wstrSearchPath, MAX_PATH);
	g_pDMLoader->SetSearchDirectory(GUID_DirectMusicAllTypes,   // 指定搜索的文件格式
		wstrSearchPath,                                         // 指定搜索路径
		FALSE                                                   // 如果为TRUE,则在设定路径前删除所有对象信息
		);                                                      // 防止当有同名路径存在时访问上级目录

	//g_pDMPath->SetVolume(0,0);//-9600~0
}
BOOL PlayMID(const char *Filename)
{
	string str;
	GetDefaultFilePath(str);
	str.append(Filename);
	Filename = str.c_str();
	DMUS_OBJECTDESC dmod;

	// Get the object
	ZeroMemory(&dmod, sizeof(DMUS_OBJECTDESC));
	dmod.dwSize = sizeof(DMUS_OBJECTDESC);
	dmod.guidClass = CLSID_DirectMusicSegment;
	dmod.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
	mbstowcs(dmod.wszFileName, Filename, MAX_PATH);
	if(FAILED(g_pDMLoader->GetObject(&dmod, IID_IDirectMusicSegment8, (LPVOID*)&g_pDMSegment)))
		return FALSE;

	// Setup MIDI playing
	if(strstr(Filename, ".mid") != NULL) {
		if(FAILED(g_pDMSegment->SetParam(GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, NULL)))
			return FALSE;
	} 

	// Download the band
	if(FAILED(g_pDMSegment->Download(g_pDMPerformance)))
		return FALSE;

	// Set to loop forever
	g_pDMSegment->SetRepeats(DMUS_SEG_REPEAT_INFINITE);
	// Play on default audio path
	g_pDMPerformance->PlaySegmentEx(g_pDMSegment, NULL, NULL, 0, 0, NULL, NULL, NULL);
	g_pDMPath->SetVolume(0,0);
	return FALSE;
}
//MID playe 1
void playForMID(char *Filename = NULL)
{
	InitMidPlay();
	PlayMID(Filename);
}

//mid play 2
MCI_OPEN_PARMS OpenParms;
void playForMid2(const char *Filename = NULL)
{
	string str;
	GetDefaultFilePath(str);
	str.append(Filename);
	Filename = str.c_str();
	//1. 打开设备 
	OpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_SEQUENCER; //MIDI类型
	OpenParms.lpstrElementName = (LPCSTR) Filename;
	OpenParms.wDeviceID = 0;
	mciSendCommand (NULL, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD)(LPVOID) &OpenParms);
	//MCI设备ID指明打开了哪个设备,当发送了MCI_OPEN命令时,这个值在参数块中返回——应被保存备用。 

	//2. 关闭设备 
	//mciSendCommand (m_wDeviceID, MCI_CLOSE, NULL, NULL);

	//3. 播放 
	MCI_PLAY_PARMS PlayParms;
	PlayParms.dwFrom = 0;
	// 指定从什么地方(时间)播放 MCI_DGV_PLAY_REPEAT-无效
	mciSendCommand (OpenParms.wDeviceID, MCI_PLAY, MCI_FROM|MCI_NOTIFY, (DWORD)(LPVOID)&PlayParms);
}
void ExitMIDInt()
{
	//释放DirectMusic 
	g_pDMPerformance->CloseDown(); 
	g_pDMSegment->Release(); 
	g_pDMPerformance->Release(); 
	g_pDMLoader->Release(); 
	CoUninitialize();//停止使用COM 

}
MUSIC_TIME musicTime;
BOOL bPauseMID = FALSE;
int _tmain(int argc, _TCHAR* argv[])
{
	g_hWnd = GetWindHwnd();
	
	int i=0;
	

	cout<<"按1号键 播放wav,2号键暂停wav,3号继续播放wav"<<endl;
	cout<<"按4号键 播放MID-方法2,5号键暂停MID-2,6号继续播放MID-2"<<endl;
	cout<<"按q号键 播放MID,w号键暂停MID,e号继续播放MID"<<endl;
	int a = getch();//49-1,50-2.....
	
	while(a != 0)
	{
	  putch(a);
	  cout<<endl;
	  switch(a)
	  {
	  case 49://1
		  {
			  PlayForWav("test3.wav");
			  cout<<"播放 test.wav"<<endl;
		  }
		  break;
	  case 50://2
		  {
			  pDSBuffer->Stop();
			  cout<<"暂停 test.wav"<<endl;
		  }
		  break;
	  case 51://3
		  {
			  pDSBuffer->Play(0,0,DSBPLAY_LOOPING);
			  cout<<"继续播放 test.wav"<<endl;
		  }
		  break;
	  case 52://4 播放2
		  {
			  playForMid2("escape.mid");
			   cout<<"MID2播放 test.wav"<<endl;
		  }
		  break;
	  case 53://5 暂停2
		  {
			  MCI_PLAY_PARMS PlayParms;
			  mciSendCommand (OpenParms.wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &PlayParms);
			  cout<<"MID2暂停播放 test.wav"<<endl;
		  }
		  break;
	  case 54://6 继续2
		  {
			 MCI_STATUS_PARMS StatusParms;
			 mciSendCommand(OpenParms.wDeviceID,MCI_PLAY,0,(DWORD)(LPVOID) &StatusParms);
			 cout<<"MID2继续播放 test.wav"<<endl;
		  }
		  break;
	  case 113://q
		  case 81:
		  {
			  playForMID("GAME_END.WAV");
			  cout<<"播放 escape.mid"<<endl;
		  }
		  break;
	  case 119://w
		  case 87:
		  {
			 //MUSIC_TIME就是一个long类型 
			  g_pDMPerformance->GetTime(NULL, &musicTime);//得到暂停的位置
			  bPauseMID = TRUE;
			 REFERENCE_TIME refTime;
			 //g_pDMPerformance->GetQueueTime()
	    	  //g_pDMSegment->GetStartPoint(&musicTime);
			  g_pDMPerformance->Stop(g_pDMSegment,//要停止的段,NULL表示全部段都停止 
				  NULL,//段状态 
				  0,//多少时间后停止,0表示立即 
				  0//标志 
				  ); 

			  cout<<"暂停播放 escape.mid"<<endl;
		  }
		  break;
	  case 101://e
		  case 69:
		  {
			  if(bPauseMID)
			  {
				  g_pDMPerformance->GetTime(NULL, &musicTime);
			  }
			  g_pDMSegment->SetStartPoint(musicTime);//播放点 

			 // g_pDMSegment->GetStartPoint(&musicTime);
			  g_pDMPerformance->PlaySegmentEx(g_pDMSegment, NULL, NULL, 0, 0, NULL, NULL, NULL);
			  g_pDMSegment->SetStartPoint(0);  
			  cout<<"继续播放 escape.mid"<<endl;
		  }
		  break;
	  }
	  a = getch();
	}

	getch();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值