SDL游戏之路(二十二)--声音-Windows Store App



声音

windows store app 程序真不好写,文件操作都是异步的,加上对语法和函数不熟,只能靠不断测试达到想要的效果。

1.声音文件是打包在安装包里的,部署的应用程序,先将打包在资源文件复制到应用程序可写目录。(不知道是否必须)

void SkGame::loadAllConfFroWP8(){
#ifdef __WP8__
	create_task([this]() {
#endif
	/** 预先加载配置文件到内存,这样可以避免windows store app 异步读取文件的麻烦 **/
	vector<string> vctStr;
	vctStr.push_back("conf/view/Dialog.BtCancle.conf.xml");
	vctStr.push_back("conf/view/Dialog.BtNo.conf.xml");
	vctStr.push_back("conf/view/Dialog.BtOk.conf.xml");
	vctStr.push_back("conf/view/Dialog.BtYes.conf.xml");
	vctStr.push_back("conf/view/SkViewInput.conf.xml");
	vctStr.push_back("conf/view/ViewFirst.BtGameBegin.conf.xml");
	vctStr.push_back("conf/view/ViewFirst.BtGameStart.conf.xml");
	vctStr.push_back("conf/view/ViewFirst.BtMusicPlay.conf.xml");
	vctStr.push_back("conf/view/ViewFirst.conf.xml");
	vctStr.push_back("conf/view/ViewFirst.DlGameInfo.conf.xml");
	vctStr.push_back("conf/view/ViewFirst.DlGameInfo2.conf.xml");
	vctStr.push_back("conf/view/ViewFirst.TfName.conf.xml");
	vctStr.push_back("conf/view/ViewFirst.TfPass.conf.xml");

	for(int i=0;i<(int)vctStr.size();i++)
	{
		string sPath = vctStr.at(i);
		SkDoc m_doc;
		bool bRet = m_doc.init(sPath.c_str());
		if (bRet == true) {
			SkString sData = m_doc.m_data;
			g_SkComm.m_mapConf[sPath] = sData;
		}
	}
	g_SkComm.log("[%s][%d]map conf size=%d",__FILE__,__LINE__,g_SkComm.m_mapConf.size());

	/** 预先将资源文件copy到 应用程序的可写目录,这样可以使用系统提供的方式读写文件**/
	vctStr.clear();
	vctStr.push_back("mp3/bg.mp3");
	for(int i=0;i<(int)vctStr.size();i++)
	{
		string sPath = vctStr.at(i);
		bool bExit = g_SkFile.wp8FileExist(sPath.c_str());
		if(!bExit){
			SkString testData;
			g_SkFile.readTxtFile(sPath.c_str(),testData);
			g_SkFile.saveBinFile(sPath.c_str(),testData);
		}
	}
	m_bInitOk = true;
#ifdef __WP8__
});
#endif
}

读写函数实现如下:

int SkFile::saveBinFile(const char * pPath, SkString & pData) {
#ifdef __WP8__
	SkString stpath = pPath;
	stpath.replaceAll('/','-');
	Platform::String ^ str = ref new Platform::String(stows(stpath.c_str()).c_str());
	StorageFolder^ dir = ApplicationData::Current->LocalFolder;
	auto iFile = create_task(dir->CreateFileAsync(str, CreationCollisionOption::OpenIfExists)).then([this](StorageFile^ file)
			{
				tmpfile = file;
			});
	iFile.wait();
	InMemoryRandomAccessStream^ memoryStream = ref new InMemoryRandomAccessStream();
    DataWriter^ dataWriter = ref new DataWriter(memoryStream);
	Platform::Array<unsigned char>^ bytes = ref new   Platform::Array<unsigned char>((unsigned char*)pData.c_str(),pData.length());
    dataWriter->WriteBytes(bytes);
	IBuffer^ buffer = dataWriter->DetachBuffer();
	StorageFile^ file = this->tmpfile;
	auto iSave = create_task(FileIO::WriteBufferAsync(file , buffer)).then([this, file, buffer](task<void> task)
			{
				task.get();
			});
	iSave.wait();
	
	return 0;
#else
	char tmpFile[256];
	snprintf(tmpFile, sizeof(tmpFile), "%s/%s", getRootPath(), pPath);
	FILE *fp2 = fopen(tmpFile, "wb");
	if (fp2 == NULL) {
		return -2;
	}
	for(int i=0;i<pData.length();i+=1024){
		int ilen = 1024;
		if(i+ilen>pData.length()){
			ilen = pData.length()-i;
		}
		fwrite(pData.c_str()+i, ilen, 1, fp2);
		if(i+ilen>=pData.length()){
			break;
		}
	}
	fclose(fp2);
#endif
	return 0;
}

int SkFile::readTxtFile(const char * pPath, SkString & sData) {
#ifdef __WP8__
	//读取失败,再读取原始文件
	FILE *fp2 = NULL;
	fopen_s(&fp2,pPath, "rb");
	if (fp2 == NULL) {
		return -1;
	}
	sData.clear();
	char buf[1024];
	while (true) {
		int iLen = fread(buf, 1, sizeof(buf), fp2);
		if (iLen <= 0) {
			break;
		}
		sData.append(buf, iLen);
	}
	fclose(fp2);
	return 0;
#else
	char tmpFile[256];
	snprintf(tmpFile, sizeof(tmpFile), "%s/%s", getRootPath(), pPath);
	FILE *fp2 = fopen(tmpFile, "rb");
	if (fp2 == NULL) {
		return -2;
	}
	sData.clear();
	char buf[1024];
	while (true) {
		int iLen = fread(buf, 1, sizeof(buf), fp2);
		if (iLen <= 0) {
			break;
		}
		sData.append(buf, iLen);
	}
	fclose(fp2);
	return 0;
#endif
}


2.编写一个声音管理类。(从官方下载的示例中可以找到,稍微做了一点修改。)

//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#pragma once

#include <wrl.h>
#include <mfmediaengine.h>
#include <d3d11_1.h>
//#include <d3d10.h>
#include <ppltasks.h>
#include <agile.h>

#ifndef MEPLAYER_H
#define MEPLAYER_H

#define ME_CAN_SEEK 0x00000002

namespace MEDIA
{
    inline void ThrowIfFailed(HRESULT hr)
    {
        if (FAILED(hr))
        {
            // Set a breakpoint on this line to catch DirectX API errors
            throw Platform::Exception::CreateException(hr);
        }
    }
}

//-----------------------------------------------------------------------------
// MediaEngineNotifyCallback
//
// Defines the callback method to process media engine events.
//-----------------------------------------------------------------------------

ref struct MediaEngineNotifyCallback abstract
{
internal:
    virtual void OnMediaEngineEvent(DWORD meEvent) = 0;
};

// MEPlayer: Manages the Media Engine.

ref class MEPlayer: public MediaEngineNotifyCallback
{
    // DX11 related
    Microsoft::WRL::ComPtr<ID3D11Device>                m_spDX11Device;
    Microsoft::WRL::ComPtr<ID3D11DeviceContext>         m_spDX11DeviceContext;
    Microsoft::WRL::ComPtr<IDXGIOutput>                 m_spDXGIOutput;
    Microsoft::WRL::ComPtr<IDXGISwapChain1>             m_spDX11SwapChain;
    Microsoft::WRL::ComPtr<IMFDXGIDeviceManager>        m_spDXGIManager;

    // Media Engine related
    Microsoft::WRL::ComPtr<IMFMediaEngine>              m_spMediaEngine;
    Microsoft::WRL::ComPtr<IMFMediaEngineEx>            m_spEngineEx;

    BSTR                                    m_bstrURL;
    BOOL                                    m_fPlaying;
    BOOL                                    m_fLoop;
    BOOL                                    m_fEOS;
    BOOL                                    m_fStopTimer;
    RECT                                    m_rcTarget;
    DXGI_FORMAT                             m_d3dFormat;
    MFARGB                                  m_bkgColor;

    HANDLE                                  m_TimerThreadHandle;
    CRITICAL_SECTION                        m_critSec;

    concurrency::task<Windows::Storage::StorageFile^>   m_pickFileTask;
    concurrency::cancellation_token_source              m_tcs;
    BOOL                                                m_fInitSuccess;    
    BOOL                                                m_fExitApp;
    BOOL                                                m_fUseDX;

internal:

    MEPlayer();

    // DX11 related
    void CreateDX11Device();
    void CreateBackBuffers();

    // Initialize/Shutdown
    void Initialize(Windows::UI::Core::CoreWindow^ window);
    void Shutdown();
    BOOL ExitApp();	

    // Media Engine related
    virtual void OnMediaEngineEvent(DWORD meEvent) override;

    // Media Engine related Options
    void AutoPlay(BOOL autoPlay)
    {
        if (m_spMediaEngine)
        {
            m_spMediaEngine->SetAutoPlay(autoPlay);
        }
    }

    void Loop()
    {
        if (m_spMediaEngine)
        {   
            (m_fLoop) ? m_fLoop = FALSE : m_fLoop = TRUE;
            m_spMediaEngine->SetLoop(m_fLoop);
        }
    }

    BOOL IsPlaying()
    {
        return m_fPlaying;
    }

    void CloseFilePicker()
    {
        m_tcs.cancel();
    }

    // Loading
    void OpenFile();
    void SetURL(Platform::String^ szURL);  
    void SetBytestream(Windows::Storage::Streams::IRandomAccessStream^ streamHandle);

    // Transport state
    void Play();
    void Pause();
    void FrameStep();

    // Audio
    void SetVolume(float fVol);
    void SetBalance(float fBal);
    void Mute(BOOL mute);

    // Video
    void ResizeVideo(HWND hwnd);
    void EnableVideoEffect(BOOL enable);

    // Seeking and duration.
    void GetDuration(double *pDuration, BOOL *pbCanSeek);
    void SetPlaybackPosition(float pos);    
    double  GetPlaybackPosition();    
    BOOL    IsSeeking();

    // Window Event Handlers
    void UpdateForWindowSizeChange();

    // Timer thread related
    void StartTimer();
    void StopTimer();	
    void OnTimer();
    DWORD RealVSyncTimer();

private:
    ~MEPlayer();
    Platform::Agile<Windows::UI::Core::CoreWindow> m_window;
};

#endif /* MEPLAYER_H */

3.在资源初始的时候,初始化音乐管理

g_myPlayer->Initialize(m_window.Get());


4.修改自定义的音乐管理类:

#ifndef SKMUSIC_H_
#define SKMUSIC_H_

#include "SkComm.h"

namespace sk_park {

/**1:效果音乐 2:背景音乐**/
typedef enum _SkMusicType {
	SK_MUSIC_TYPE_CHUNK = 1, SK_MUSIC_TYPE_MUSIC = 2,
} SkMusicType;

class SkMusic {
public:
	SkMusic();
	virtual ~SkMusic();
	/**加载音乐文件**/
	int load(SkMusicType mType, const char * pPath);
	void start();
	void stop();
	void pause();
private:
	SkMusicType m_mType;
#ifdef __WP8__
	bool m_loadOk;
public:
	MEPlayer^ m_myPlayer;
#else
	Mix_Music* m_pMusic;
	Mix_Chunk* m_pChunk;
#endif
};

}

extern sk_park::SkMusic g_SkMusic;

#endif /* SKMUSIC_H_ */


实现如下:

#include "pch.h"

#include "SkMusic.h"
#include "SkFile.h"
#include "SkString.h"
using namespace sk_park;

#ifdef __WP8__
using namespace Windows::Storage;
using namespace Concurrency;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Storage::Streams;
using namespace Windows::Networking;
using namespace Windows::Networking::Sockets;
using namespace Windows::ApplicationModel::Core;
extern MEPlayer^ g_myPlayer;
SkMusic::SkMusic(){
	m_loadOk = false;
}
SkMusic::~SkMusic() {
}
int SkMusic::load(SkMusicType mType, const char * pPath){
	create_task([this,pPath]() {
		//m_myPlayer = ref new MEPlayer();
		m_myPlayer = g_myPlayer;
		StorageFile^ fileHandle = g_SkFile.getWp8File(pPath);
		m_myPlayer->SetURL(fileHandle->Path);

		auto oCreate = create_task(fileHandle->OpenAsync(Windows::Storage::FileAccessMode::Read)).then([this](IRandomAccessStream^ streamHandle){
			try
            {
				m_myPlayer->SetBytestream(streamHandle);
               // vidPlayer->SetBytestream(streamHandle);
            } catch(Platform::Exception^)
            {
                MEDIA::ThrowIfFailed(E_UNEXPECTED);
            }
		});
		oCreate.wait();
		m_loadOk = true;
	});
	return 0;
}
void SkMusic::start(){
	if(m_loadOk){
		m_myPlayer->Play();
	}
}
void SkMusic::stop(){
	if(m_loadOk){
		m_myPlayer->Pause();
	}
}
void SkMusic::pause(){
	if(m_loadOk){
		m_myPlayer->Pause();
	}
}
#else
SkMusic::SkMusic() {
	m_pMusic = NULL;
	m_pChunk = NULL;

}
SkMusic::~SkMusic() {
	if (m_pChunk != NULL) {
		Mix_FreeChunk(m_pChunk);
		m_pChunk = NULL;
	}
	if (m_pMusic != NULL) {
		Mix_FreeMusic(m_pMusic);
		m_pMusic = NULL;
	}
}
int SkMusic::load(SkMusicType mType, const char * pPath) {
	SkString sPath = pPath;
#ifdef __ANDROID__
	sPath.replaceAll('/','-');
#endif
	char musicPath[256];
	snprintf(musicPath, sizeof(musicPath), "%s/%s", g_SkFile.getRootPath(),
			sPath.c_str());
	m_mType = mType;
	if (SK_MUSIC_TYPE_CHUNK == m_mType) {
		m_pChunk = Mix_LoadWAV(musicPath);
#ifdef __ANDROID__
		if (m_pChunk == NULL) {
			SkString sData;
			int iRet = g_SkFile.readAndroidFile(pPath,sData);
			g_SkComm.log("[%s][%d]readAndroidFile=%d path=%s", __FILE__, __LINE__,iRet,pPath);
			if(iRet==0) {
				iRet = g_SkFile.saveBinFile(sPath.c_str(),sData);
				g_SkComm.log("[%s][%d]saveBinFile=%d path=%s", __FILE__, __LINE__,iRet,sPath.c_str());
			}
			m_pChunk = Mix_LoadWAV(musicPath);
		}
#endif

		if (m_pChunk != NULL) {
			return 0;
		} else {
			return -1;
		}
	} else {
		m_pMusic = Mix_LoadMUS(musicPath);
#ifdef __ANDROID__
		if (m_pMusic == NULL) {
			SkString sData;
			int iRet = g_SkFile.readAndroidFile(pPath,sData);
			g_SkComm.log("[%s][%d]readAndroidFile=%d path=%s", __FILE__, __LINE__,iRet,pPath);
			if(iRet==0) {
				iRet = g_SkFile.saveBinFile(sPath.c_str(),sData);
				g_SkComm.log("[%s][%d]saveBinFile=%d path=%s", __FILE__, __LINE__,iRet,sPath.c_str());
			}
			m_pMusic = Mix_LoadMUS(musicPath);
		}
#endif
		if (m_pMusic != NULL) {
			return 0;
		} else {
			return -1;
		}
	}
	return -1;
}
void SkMusic::start() {
	if (SK_MUSIC_TYPE_CHUNK == m_mType) {
		if (m_pChunk != NULL) {
			Mix_PlayChannel(-1, m_pChunk, 0);
		}
	} else {
		if (Mix_PlayingMusic() == false) {
			if (m_pMusic != NULL) {
				Mix_PlayMusic(m_pMusic, -1);
			}
		} else {
			if (Mix_PausedMusic() == 1) {
				Mix_ResumeMusic();
			} else {
				//Mix_PauseMusic();
			}
		}

	}
}
void SkMusic::stop() {
	if (SK_MUSIC_TYPE_MUSIC == m_mType) {
		Mix_HaltMusic();
	}
}
void SkMusic::pause() {
	if (SK_MUSIC_TYPE_MUSIC == m_mType) {
		Mix_PauseMusic();
	}
}
#endif

SkMusic g_SkMusic;

5.这样,点击播放按钮后,背景音乐出来了。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值