声音
windows store app 程序真不好写,文件操作都是异步的,加上对语法和函数不熟,只能靠不断测试达到想要的效果。
1.声音文件是打包在安装包里的,部署的应用程序,先将打包在资源文件复制到应用程序可写目录。(不知道是否必须)
void SkGame::loadAllConfFroWP8(){
#ifdef __WP8__
create_task([this]() {
#endif
/** 预先加载配置文件到内存,这样可以避免windows store app 异步读取文件的麻烦 **/
vector 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^ bytes = ref new Platform::Array((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 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;ipData.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
#include
#include
//#include
#include
#include
#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 m_spDX11Device;
Microsoft::WRL::ComPtr m_spDX11DeviceContext;
Microsoft::WRL::ComPtr m_spDXGIOutput;
Microsoft::WRL::ComPtr m_spDX11SwapChain;
Microsoft::WRL::ComPtr m_spDXGIManager;
// Media Engine related
Microsoft::WRL::ComPtr m_spMediaEngine;
Microsoft::WRL::ComPtr 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 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 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.这样,点击播放按钮后,背景音乐出来了。