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

来源:互联网 发布:淘宝网外贸女装 编辑:程序博客网 时间:2024/05/18 03:08


声音

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;#elsechar 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);#endifreturn 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;#elsechar 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 0x00000002namespace 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;#elseMix_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();}}#elseSkMusic::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('/','-');#endifchar 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);}#endifif (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);}#endifif (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();}}#endifSkMusic g_SkMusic;

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




0 0