add: use Media Foundation to play sound effect
This commit is contained in:
parent
fdbece1663
commit
80d1a87955
|
|
@ -25,38 +25,29 @@ namespace e2d
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
class Music;
|
class MediaAsyncCallback : public IMFAsyncCallback
|
||||||
|
|
||||||
// ÒôÔ´»Øµ÷
|
|
||||||
class VoiceCallback
|
|
||||||
: public IXAudio2VoiceCallback
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VoiceCallback();
|
MediaAsyncCallback(
|
||||||
|
HWND hwnd,
|
||||||
|
IMFMediaSession * pSession,
|
||||||
|
HANDLE hCloseEvent
|
||||||
|
);
|
||||||
|
|
||||||
~VoiceCallback();
|
// IUnknown methods
|
||||||
|
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
|
||||||
|
STDMETHODIMP_(ULONG) AddRef();
|
||||||
|
STDMETHODIMP_(ULONG) Release();
|
||||||
|
|
||||||
STDMETHOD_(void, OnVoiceProcessingPassStart) (THIS_ UINT32 BytesRequired) {}
|
// IMFAsyncCallback methods
|
||||||
|
STDMETHODIMP GetParameters(DWORD*, DWORD*);
|
||||||
STDMETHOD_(void, OnVoiceProcessingPassEnd) (THIS) {}
|
STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult);
|
||||||
|
|
||||||
STDMETHOD_(void, OnStreamEnd) (THIS);
|
|
||||||
|
|
||||||
STDMETHOD_(void, OnBufferStart) (THIS_ void* pBufferContext) {}
|
|
||||||
|
|
||||||
STDMETHOD_(void, OnBufferEnd) (THIS_ void* pBufferContext);
|
|
||||||
|
|
||||||
STDMETHOD_(void, OnLoopEnd) (THIS_ void* pBufferContext);
|
|
||||||
|
|
||||||
STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) {}
|
|
||||||
|
|
||||||
STDMETHOD_(void, SetCallbackOnStreamEnd) (THIS_ const Function& func);
|
|
||||||
|
|
||||||
STDMETHOD_(void, SetCallbackOnLoopEnd) (THIS_ const Function& func);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Function loop_end_callback_;
|
long m_nRefCount;
|
||||||
Function stream_end_callback_;
|
IMFMediaSession * m_pSession;
|
||||||
|
HWND m_hwnd;
|
||||||
|
HANDLE m_hCloseEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,9 @@
|
||||||
# define DIRECTINPUT_VERSION 0x0800
|
# define DIRECTINPUT_VERSION 0x0800
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef INITGUID
|
||||||
# define INITGUID
|
# define INITGUID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Windows Header Files
|
// Windows Header Files
|
||||||
|
|
@ -55,8 +57,12 @@
|
||||||
#include <d2d1.h>
|
#include <d2d1.h>
|
||||||
#include <dwrite.h>
|
#include <dwrite.h>
|
||||||
#include <dinput.h>
|
#include <dinput.h>
|
||||||
#include <d2d1helper.h>
|
#include <shlwapi.h>
|
||||||
#include <xaudio2.h>
|
#include <mfapi.h>
|
||||||
|
#include <mfidl.h>
|
||||||
|
#include <mferror.h>
|
||||||
|
#include <evr.h>
|
||||||
|
#include <mmdeviceapi.h>
|
||||||
|
|
||||||
// C++ RunTime Header Files
|
// C++ RunTime Header Files
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
@ -76,8 +82,12 @@
|
||||||
#pragma comment(lib, "dwrite.lib")
|
#pragma comment(lib, "dwrite.lib")
|
||||||
#pragma comment(lib, "windowscodecs.lib")
|
#pragma comment(lib, "windowscodecs.lib")
|
||||||
#pragma comment(lib, "winmm.lib")
|
#pragma comment(lib, "winmm.lib")
|
||||||
#pragma comment(lib, "xaudio2.lib")
|
|
||||||
#pragma comment(lib, "dinput8.lib")
|
#pragma comment(lib, "dinput8.lib")
|
||||||
|
#pragma comment(lib, "shlwapi")
|
||||||
|
#pragma comment(lib, "mfplay.lib")
|
||||||
|
#pragma comment(lib, "mf.lib")
|
||||||
|
#pragma comment(lib, "mfplat.lib")
|
||||||
|
#pragma comment(lib, "mfuuid.lib")
|
||||||
|
|
||||||
|
|
||||||
#ifndef HINST_THISCOMPONENT
|
#ifndef HINST_THISCOMPONENT
|
||||||
|
|
|
||||||
|
|
@ -149,22 +149,30 @@ namespace e2d
|
||||||
|
|
||||||
~Audio();
|
~Audio();
|
||||||
|
|
||||||
// 开启设备
|
// 获取音量
|
||||||
void Open();
|
float GetVolume();
|
||||||
|
|
||||||
// 关闭设备
|
// 设置音量
|
||||||
void Close();
|
void SetVolume(
|
||||||
|
float volume
|
||||||
|
);
|
||||||
|
|
||||||
// 创建音源
|
// 是否静音
|
||||||
HRESULT CreateVoice(
|
bool GetMute();
|
||||||
IXAudio2SourceVoice ** voice,
|
|
||||||
WAVEFORMATEX * wfx,
|
// 设置静音
|
||||||
VoiceCallback * callback
|
void SetMute(
|
||||||
|
bool mute
|
||||||
);
|
);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
IXAudio2 * x_audio2_;
|
LPWSTR device_id; // Device ID.
|
||||||
IXAudio2MasteringVoice* mastering_voice_;
|
IMMDeviceEnumerator *enum_; // Audio device enumerator.
|
||||||
|
IMMDeviceCollection *devices_; // Audio device collection.
|
||||||
|
IMMDevice *device_; // An audio device.
|
||||||
|
IMFAttributes *attributes_; // Attribute store.
|
||||||
|
IMFMediaSink *sink_; // Streaming audio renderer (SAR)
|
||||||
|
IMFSimpleAudioVolume *audio_volume;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -301,9 +309,6 @@ namespace e2d
|
||||||
int height
|
int height
|
||||||
);
|
);
|
||||||
|
|
||||||
// 进入下一场景
|
|
||||||
void EnterNextScene();
|
|
||||||
|
|
||||||
// Win32 ´°¿ÚÏûÏ¢»Øµ÷³ÌÐò
|
// Win32 ´°¿ÚÏûÏ¢»Øµ÷³ÌÐò
|
||||||
static LRESULT CALLBACK WndProc(
|
static LRESULT CALLBACK WndProc(
|
||||||
HWND hwnd,
|
HWND hwnd,
|
||||||
|
|
|
||||||
114
core/e2dtool.h
114
core/e2dtool.h
|
|
@ -71,6 +71,7 @@ namespace e2d
|
||||||
|
|
||||||
// 稜있
|
// 稜있
|
||||||
class Music
|
class Music
|
||||||
|
: public IMFAsyncCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Music();
|
Music();
|
||||||
|
|
@ -97,15 +98,12 @@ namespace e2d
|
||||||
|
|
||||||
// 꺄렴
|
// 꺄렴
|
||||||
bool Play(
|
bool Play(
|
||||||
int loopCount = 0
|
int loop_count = 0
|
||||||
);
|
);
|
||||||
|
|
||||||
// 董界
|
// 董界
|
||||||
void Pause();
|
void Pause();
|
||||||
|
|
||||||
// 继续
|
|
||||||
void Resume();
|
|
||||||
|
|
||||||
// 界岺
|
// 界岺
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
|
|
@ -117,51 +115,97 @@ namespace e2d
|
||||||
|
|
||||||
// <20>零稜좆
|
// <20>零稜좆
|
||||||
bool SetVolume(
|
bool SetVolume(
|
||||||
float volume
|
float volume /* ·¶Î§: 0.0 ~ 1.0 */
|
||||||
);
|
);
|
||||||
|
|
||||||
// 设置播放结束时的执行函数
|
// »ñÈ¡ÒôÁ¿
|
||||||
void SetCallbackOnEnd(
|
float GetVolume() const;
|
||||||
const Function& func
|
|
||||||
);
|
|
||||||
|
|
||||||
// 设置循环播放中每一次播放结束时的执行函数
|
// IUnknown methods
|
||||||
void SetCallbackOnLoopEnd(
|
STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override;
|
||||||
const Function& func
|
STDMETHODIMP_(ULONG) AddRef() override;
|
||||||
);
|
STDMETHODIMP_(ULONG) Release() override;
|
||||||
|
|
||||||
// 获取 IXAudio2SourceVoice 对象
|
// IMFAsyncCallback methods
|
||||||
IXAudio2SourceVoice * GetSourceVoice() const;
|
STDMETHODIMP GetParameters(DWORD*, DWORD*) override;
|
||||||
|
STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum class State : int
|
||||||
|
{
|
||||||
|
Closed = 0,
|
||||||
|
Loaded,
|
||||||
|
Started,
|
||||||
|
Paused,
|
||||||
|
Stopped,
|
||||||
|
Closing
|
||||||
|
};
|
||||||
|
|
||||||
E2D_DISABLE_COPY(Music);
|
E2D_DISABLE_COPY(Music);
|
||||||
|
|
||||||
bool ReadMMIO();
|
// Media event handlers
|
||||||
|
HRESULT OnNewPresentation(IMFMediaEvent *pEvent);
|
||||||
|
|
||||||
bool ResetFile();
|
HRESULT StartPlayback();
|
||||||
|
HRESULT CreateMediaSource(PCWSTR sURL, IMFMediaSource **ppSource);
|
||||||
|
HRESULT HandleEvent(UINT_PTR pUnkPtr);
|
||||||
|
|
||||||
bool Read(
|
// Add a source node to a topology.
|
||||||
BYTE* buffer,
|
HRESULT AddSourceNode(
|
||||||
DWORD size_to_read
|
IMFTopology *pTopology, // Topology.
|
||||||
|
IMFMediaSource *pSource, // Media source.
|
||||||
|
IMFPresentationDescriptor *pPD, // Presentation descriptor.
|
||||||
|
IMFStreamDescriptor *pSD, // Stream descriptor.
|
||||||
|
IMFTopologyNode **ppNode // Receives the node pointer.
|
||||||
);
|
);
|
||||||
|
|
||||||
bool FindMediaFileCch(
|
// Add an output node to a topology.
|
||||||
wchar_t* dest_path,
|
HRESULT AddOutputNode(
|
||||||
int cch_dest,
|
IMFTopology *pTopology, // Topology.
|
||||||
const wchar_t * file_name
|
IMFActivate *pActivate, // Media sink activation object.
|
||||||
|
DWORD dwId, // Identifier of the stream sink.
|
||||||
|
IMFTopologyNode **ppNode // Receives the node pointer.
|
||||||
|
);
|
||||||
|
|
||||||
|
HRESULT AddBranchToPartialTopology(
|
||||||
|
IMFTopology *pTopology, // Topology.
|
||||||
|
IMFMediaSource *pSource, // Media source.
|
||||||
|
IMFPresentationDescriptor *pPD, // Presentation descriptor.
|
||||||
|
DWORD iStream // Stream index.
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a playback topology from a media source.
|
||||||
|
HRESULT CreatePlaybackTopology(
|
||||||
|
IMFMediaSource *pSource, // Media source.
|
||||||
|
IMFPresentationDescriptor *pPD, // Presentation descriptor.
|
||||||
|
IMFTopology **ppTopology // Receives a pointer to the topology.
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create an activation object for a renderer, based on the stream media type.
|
||||||
|
HRESULT CreateMediaSinkActivate(
|
||||||
|
IMFStreamDescriptor *pSourceSD, // Pointer to the stream descriptor.
|
||||||
|
IMFActivate **ppActivate
|
||||||
|
);
|
||||||
|
|
||||||
|
HRESULT GetSimpleAudioVolume(
|
||||||
|
IMFSimpleAudioVolume** ppAudioVolume
|
||||||
|
) const;
|
||||||
|
|
||||||
|
static LRESULT CALLBACK MediaProc(
|
||||||
|
HWND hWnd,
|
||||||
|
UINT Msg,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam
|
||||||
);
|
);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool opened_;
|
long m_nRefCount;
|
||||||
DWORD size_;
|
int m_nTimes;
|
||||||
CHAR* buffer_;
|
IMFMediaSession * m_pSession;
|
||||||
BYTE* wave_data_;
|
IMFMediaSource *m_pSource;
|
||||||
HMMIO hmmio_;
|
HWND m_hwndEvent;
|
||||||
MMCKINFO ck_;
|
State m_state;
|
||||||
MMCKINFO ck_riff_;
|
HANDLE m_hCloseEvent;
|
||||||
WAVEFORMATEX* wfx_;
|
|
||||||
VoiceCallback callback_;
|
|
||||||
IXAudio2SourceVoice* voice_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -240,7 +284,7 @@ namespace e2d
|
||||||
|
|
||||||
// <20>零稜좆
|
// <20>零稜좆
|
||||||
void SetVolume(
|
void SetVolume(
|
||||||
float volume /* 音量范围为 -224 ~ 224,0 是静音,1 是正常音量 */
|
float volume /* ·¶Î§: 0.0 ~ 1.0 */
|
||||||
);
|
);
|
||||||
|
|
||||||
// 董界杰唐稜있
|
// 董界杰唐稜있
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
// Copyright (c) 2016-2018 Easy2D - Nomango
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "..\e2dimpl.h"
|
||||||
|
|
||||||
|
e2d::MediaAsyncCallback::MediaAsyncCallback(HWND hwnd, IMFMediaSession * pSession, HANDLE hCloseEvent)
|
||||||
|
: m_pSession(pSession)
|
||||||
|
, m_hCloseEvent(hCloseEvent)
|
||||||
|
, m_hwnd(hwnd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT e2d::MediaAsyncCallback::QueryInterface(REFIID riid, void** ppv)
|
||||||
|
{
|
||||||
|
static const QITAB qit[] =
|
||||||
|
{
|
||||||
|
QITABENT(MediaAsyncCallback, IMFAsyncCallback),
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
return QISearch(this, qit, riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG e2d::MediaAsyncCallback::AddRef()
|
||||||
|
{
|
||||||
|
return InterlockedIncrement(&m_nRefCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG e2d::MediaAsyncCallback::Release()
|
||||||
|
{
|
||||||
|
ULONG uCount = InterlockedDecrement(&m_nRefCount);
|
||||||
|
if (uCount == 0)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
return uCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT e2d::MediaAsyncCallback::GetParameters(DWORD *, DWORD *)
|
||||||
|
{
|
||||||
|
// Implementation of this method is optional.
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT e2d::MediaAsyncCallback::Invoke(IMFAsyncResult *pResult)
|
||||||
|
{
|
||||||
|
MediaEventType meType = MEUnknown; // Event type
|
||||||
|
|
||||||
|
IMFMediaEvent *pEvent = NULL;
|
||||||
|
|
||||||
|
// Get the event from the event queue.
|
||||||
|
HRESULT hr = m_pSession->EndGetEvent(pResult, &pEvent);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the event type.
|
||||||
|
hr = pEvent->GetType(&meType);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meType == MESessionClosed)
|
||||||
|
{
|
||||||
|
// The session was closed.
|
||||||
|
// The application is waiting on the m_hCloseEvent event handle.
|
||||||
|
SetEvent(m_hCloseEvent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For all other events, get the next event in the queue.
|
||||||
|
hr = m_pSession->BeginGetEvent(this, NULL);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the application state.
|
||||||
|
|
||||||
|
// If a call to IMFMediaSession::Close is pending, it means the
|
||||||
|
// application is waiting on the m_hCloseEvent event and
|
||||||
|
// the application's message loop is blocked.
|
||||||
|
|
||||||
|
// Otherwise, post a private window message to the application.
|
||||||
|
|
||||||
|
//if (m_state != Closing)
|
||||||
|
{
|
||||||
|
// Leave a reference count on the event.
|
||||||
|
pEvent->AddRef();
|
||||||
|
|
||||||
|
::PostMessage(m_hwnd, WM_APP + 1, (WPARAM)pEvent, (LPARAM)meType);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
SafeRelease(pEvent);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
// Copyright (c) 2016-2018 Easy2D - Nomango
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
|
|
||||||
#include "..\e2dimpl.h"
|
|
||||||
#include "..\e2dutil.h"
|
|
||||||
|
|
||||||
e2d::VoiceCallback::VoiceCallback()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
e2d::VoiceCallback::~VoiceCallback()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void e2d::VoiceCallback::OnLoopEnd(void * pBufferContext)
|
|
||||||
{
|
|
||||||
if (loop_end_callback_)
|
|
||||||
{
|
|
||||||
loop_end_callback_();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void e2d::VoiceCallback::OnStreamEnd()
|
|
||||||
{
|
|
||||||
if (stream_end_callback_)
|
|
||||||
{
|
|
||||||
stream_end_callback_();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void e2d::VoiceCallback::OnBufferEnd(void * pBufferContext)
|
|
||||||
{
|
|
||||||
if (loop_end_callback_)
|
|
||||||
{
|
|
||||||
loop_end_callback_();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void e2d::VoiceCallback::SetCallbackOnStreamEnd(const Function & func)
|
|
||||||
{
|
|
||||||
stream_end_callback_ = func;
|
|
||||||
}
|
|
||||||
|
|
||||||
void e2d::VoiceCallback::SetCallbackOnLoopEnd(const Function & func)
|
|
||||||
{
|
|
||||||
loop_end_callback_ = func;
|
|
||||||
}
|
|
||||||
|
|
@ -22,40 +22,128 @@
|
||||||
|
|
||||||
|
|
||||||
e2d::Audio::Audio()
|
e2d::Audio::Audio()
|
||||||
: x_audio2_(nullptr)
|
: enum_(nullptr)
|
||||||
, mastering_voice_(nullptr)
|
, devices_(nullptr)
|
||||||
|
, device_(nullptr)
|
||||||
|
, attributes_(nullptr)
|
||||||
|
, sink_(nullptr)
|
||||||
|
, device_id(nullptr)
|
||||||
|
, audio_volume(nullptr)
|
||||||
{
|
{
|
||||||
ThrowIfFailed(
|
ThrowIfFailed(
|
||||||
XAudio2Create(&x_audio2_, 0)
|
MFStartup(MF_VERSION)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create the device enumerator.
|
||||||
|
ThrowIfFailed(
|
||||||
|
CoCreateInstance(
|
||||||
|
__uuidof(MMDeviceEnumerator),
|
||||||
|
NULL,
|
||||||
|
CLSCTX_ALL,
|
||||||
|
__uuidof(IMMDeviceEnumerator),
|
||||||
|
(void**)&enum_
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Enumerate the rendering devices.
|
||||||
|
ThrowIfFailed(
|
||||||
|
enum_->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices_)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get ID of the first device in the list.
|
||||||
|
ThrowIfFailed(
|
||||||
|
devices_->Item(0, &device_)
|
||||||
);
|
);
|
||||||
|
|
||||||
ThrowIfFailed(
|
ThrowIfFailed(
|
||||||
x_audio2_->CreateMasteringVoice(&mastering_voice_)
|
device_->GetId(&device_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Create an attribute store and set the device ID attribute.
|
||||||
|
ThrowIfFailed(
|
||||||
|
MFCreateAttributes(&attributes_, 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
ThrowIfFailed(
|
||||||
|
attributes_->SetString(
|
||||||
|
MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID,
|
||||||
|
device_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create the audio renderer.
|
||||||
|
ThrowIfFailed(
|
||||||
|
MFCreateAudioRenderer(attributes_, &sink_)
|
||||||
|
);
|
||||||
|
|
||||||
|
IMFGetService* service = NULL;
|
||||||
|
|
||||||
|
ThrowIfFailed(
|
||||||
|
sink_->QueryInterface(IID_IMFGetService, (void **)&service)
|
||||||
|
);
|
||||||
|
|
||||||
|
ThrowIfFailed(
|
||||||
|
service->GetService(MR_POLICY_VOLUME_SERVICE, IID_PPV_ARGS(&audio_volume))
|
||||||
|
);
|
||||||
|
|
||||||
|
SafeRelease(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
e2d::Audio::~Audio()
|
e2d::Audio::~Audio()
|
||||||
{
|
{
|
||||||
if (mastering_voice_)
|
SafeRelease(enum_);
|
||||||
{
|
SafeRelease(devices_);
|
||||||
mastering_voice_->DestroyVoice();
|
SafeRelease(device_);
|
||||||
mastering_voice_ = nullptr;
|
SafeRelease(attributes_);
|
||||||
|
SafeRelease(audio_volume);
|
||||||
|
SafeRelease(sink_);
|
||||||
|
CoTaskMemFree(device_id);
|
||||||
|
|
||||||
|
MFShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
SafeRelease(x_audio2_);
|
float e2d::Audio::GetVolume()
|
||||||
|
{
|
||||||
|
float volume = 0.f;
|
||||||
|
if (audio_volume)
|
||||||
|
{
|
||||||
|
HRESULT hr = audio_volume->GetMasterVolume(&volume);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT e2d::Audio::CreateVoice(IXAudio2SourceVoice ** voice, WAVEFORMATEX * wfx, VoiceCallback * callback)
|
void e2d::Audio::SetVolume(float volume)
|
||||||
{
|
{
|
||||||
return x_audio2_->CreateSourceVoice(voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO, callback);
|
if (audio_volume)
|
||||||
|
{
|
||||||
|
volume = std::min(std::max(volume, 0.f), 1.f);
|
||||||
|
HRESULT hr = audio_volume->SetMasterVolume(volume);
|
||||||
|
printf("ºÇºÇ%#X\n", hr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void e2d::Audio::Open()
|
bool e2d::Audio::GetMute()
|
||||||
{
|
{
|
||||||
x_audio2_->StartEngine();
|
BOOL mute = FALSE;
|
||||||
|
if (audio_volume)
|
||||||
|
{
|
||||||
|
HRESULT hr = audio_volume->GetMute(&mute);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
return mute ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void e2d::Audio::Close()
|
void e2d::Audio::SetMute(bool mute)
|
||||||
{
|
{
|
||||||
x_audio2_->StopEngine();
|
if (audio_volume)
|
||||||
|
{
|
||||||
|
audio_volume->SetMute(mute ? TRUE : FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,12 @@ void e2d::Game::Run(const Options& options)
|
||||||
Start();
|
Start();
|
||||||
|
|
||||||
// 刷新场景
|
// 刷新场景
|
||||||
EnterNextScene();
|
if (next_scene_)
|
||||||
|
{
|
||||||
|
next_scene_->OnEnter();
|
||||||
|
curr_scene_ = next_scene_;
|
||||||
|
next_scene_ = nullptr;
|
||||||
|
}
|
||||||
::ShowWindow(hwnd_, SW_SHOWNORMAL);
|
::ShowWindow(hwnd_, SW_SHOWNORMAL);
|
||||||
::UpdateWindow(hwnd_);
|
::UpdateWindow(hwnd_);
|
||||||
|
|
||||||
|
|
@ -189,17 +194,21 @@ bool e2d::Game::IsTransitioning() const
|
||||||
|
|
||||||
void e2d::Game::UpdateScene(float dt)
|
void e2d::Game::UpdateScene(float dt)
|
||||||
{
|
{
|
||||||
if (curr_scene_)
|
auto update = [&](Scene * scene) -> void
|
||||||
{
|
{
|
||||||
curr_scene_->Update(dt);
|
if (scene)
|
||||||
curr_scene_->GetRoot()->UpdateChildren(dt);
|
{
|
||||||
|
scene->Update(dt);
|
||||||
|
Node * root = scene->GetRoot();
|
||||||
|
if (root)
|
||||||
|
{
|
||||||
|
root->UpdateChildren(dt);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (next_scene_)
|
update(curr_scene_);
|
||||||
{
|
update(next_scene_);
|
||||||
next_scene_->Update(dt);
|
|
||||||
next_scene_->GetRoot()->UpdateChildren(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transition_)
|
if (transition_)
|
||||||
{
|
{
|
||||||
|
|
@ -216,7 +225,19 @@ void e2d::Game::UpdateScene(float dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EnterNextScene();
|
if (next_scene_)
|
||||||
|
{
|
||||||
|
if (curr_scene_)
|
||||||
|
{
|
||||||
|
curr_scene_->OnExit();
|
||||||
|
curr_scene_->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
next_scene_->OnEnter();
|
||||||
|
|
||||||
|
curr_scene_ = next_scene_;
|
||||||
|
next_scene_ = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void e2d::Game::DrawScene()
|
void e2d::Game::DrawScene()
|
||||||
|
|
@ -281,7 +302,7 @@ void e2d::Game::Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册窗口类
|
// 注册窗口类
|
||||||
RegisterClassEx(&wcex);
|
::RegisterClassEx(&wcex);
|
||||||
|
|
||||||
// 计算窗口大小
|
// 计算窗口大小
|
||||||
Rect client_rect = Locate(width_, height_);
|
Rect client_rect = Locate(width_, height_);
|
||||||
|
|
@ -309,6 +330,12 @@ void e2d::Game::Init()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::SetWindowLongPtrW(
|
||||||
|
hwnd_,
|
||||||
|
GWLP_USERDATA,
|
||||||
|
PtrToUlong(this)
|
||||||
|
);
|
||||||
|
|
||||||
// 初始化设备
|
// 初始化设备
|
||||||
Device::Init(hwnd_);
|
Device::Init(hwnd_);
|
||||||
|
|
||||||
|
|
@ -379,23 +406,6 @@ e2d::Rect e2d::Game::Locate(int width, int height)
|
||||||
return std::move(client_rect);
|
return std::move(client_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void e2d::Game::EnterNextScene()
|
|
||||||
{
|
|
||||||
if (next_scene_)
|
|
||||||
{
|
|
||||||
if (curr_scene_)
|
|
||||||
{
|
|
||||||
curr_scene_->OnExit();
|
|
||||||
curr_scene_->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
next_scene_->OnEnter();
|
|
||||||
|
|
||||||
curr_scene_ = next_scene_;
|
|
||||||
next_scene_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int e2d::Game::GetWidth() const
|
int e2d::Game::GetWidth() const
|
||||||
{
|
{
|
||||||
return width_;
|
return width_;
|
||||||
|
|
@ -481,27 +491,9 @@ void e2d::Game::SetIcon(int resource_id)
|
||||||
LRESULT e2d::Game::WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
|
LRESULT e2d::Game::WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
|
||||||
{
|
{
|
||||||
LRESULT result = 0;
|
LRESULT result = 0;
|
||||||
|
|
||||||
if (msg == WM_CREATE)
|
|
||||||
{
|
|
||||||
LPCREATESTRUCT pcs = (LPCREATESTRUCT)l_param;
|
|
||||||
Game * game = (Game *)pcs->lpCreateParams;
|
|
||||||
|
|
||||||
::SetWindowLongPtrW(
|
|
||||||
hwnd,
|
|
||||||
GWLP_USERDATA,
|
|
||||||
PtrToUlong(game)
|
|
||||||
);
|
|
||||||
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool was_handled = false;
|
bool was_handled = false;
|
||||||
Game * game = reinterpret_cast<Game*>(
|
Game * game = reinterpret_cast<Game*>(
|
||||||
static_cast<LONG_PTR>(
|
static_cast<LONG_PTR>(::GetWindowLongPtrW(hwnd, GWLP_USERDATA))
|
||||||
::GetWindowLongPtrW(hwnd, GWLP_USERDATA)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (msg)
|
switch (msg)
|
||||||
|
|
@ -628,6 +620,5 @@ LRESULT e2d::Game::WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
|
||||||
{
|
{
|
||||||
result = ::DefWindowProc(hwnd, msg, w_param, l_param);
|
result = ::DefWindowProc(hwnd, msg, w_param, l_param);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,12 @@ void e2d::Scene::Draw()
|
||||||
|
|
||||||
void e2d::Scene::Dispatch(const MouseEvent & e)
|
void e2d::Scene::Dispatch(const MouseEvent & e)
|
||||||
{
|
{
|
||||||
|
auto handler = dynamic_cast<MouseEventHandler*>(this);
|
||||||
|
if (handler)
|
||||||
|
{
|
||||||
|
handler->Handle(e);
|
||||||
|
}
|
||||||
|
|
||||||
if (root_)
|
if (root_)
|
||||||
{
|
{
|
||||||
root_->Dispatch(e, false);
|
root_->Dispatch(e, false);
|
||||||
|
|
@ -86,6 +92,12 @@ void e2d::Scene::Dispatch(const MouseEvent & e)
|
||||||
|
|
||||||
void e2d::Scene::Dispatch(const KeyEvent & e)
|
void e2d::Scene::Dispatch(const KeyEvent & e)
|
||||||
{
|
{
|
||||||
|
auto handler = dynamic_cast<KeyEventHandler*>(this);
|
||||||
|
if (handler)
|
||||||
|
{
|
||||||
|
handler->Handle(e);
|
||||||
|
}
|
||||||
|
|
||||||
if (root_)
|
if (root_)
|
||||||
{
|
{
|
||||||
root_->Dispatch(e, false);
|
root_->Dispatch(e, false);
|
||||||
|
|
|
||||||
1151
core/tools/Music.cpp
1151
core/tools/Music.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -68,7 +68,7 @@ void e2d::Player::Resume(const String & file_path)
|
||||||
|
|
||||||
size_t hash = file_path.GetHash();
|
size_t hash = file_path.GetHash();
|
||||||
if (musics_.end() != musics_.find(hash))
|
if (musics_.end() != musics_.find(hash))
|
||||||
musics_[hash]->Resume();
|
musics_[hash]->Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void e2d::Player::Stop(const String & file_path)
|
void e2d::Player::Stop(const String & file_path)
|
||||||
|
|
@ -137,7 +137,7 @@ void e2d::Player::Pause(const Resource& res)
|
||||||
void e2d::Player::Resume(const Resource& res)
|
void e2d::Player::Resume(const Resource& res)
|
||||||
{
|
{
|
||||||
if (musics_.end() != musics_.find(res.id))
|
if (musics_.end() != musics_.find(res.id))
|
||||||
musics_[res.id]->Resume();
|
musics_[res.id]->Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void e2d::Player::Stop(const Resource& res)
|
void e2d::Player::Stop(const Resource& res)
|
||||||
|
|
@ -160,7 +160,7 @@ float e2d::Player::GetVolume()
|
||||||
|
|
||||||
void e2d::Player::SetVolume(float volume)
|
void e2d::Player::SetVolume(float volume)
|
||||||
{
|
{
|
||||||
volume_ = std::min(std::max(volume, -224.f), 224.f);
|
volume_ = std::min(std::max(volume, 0.f), 1.f);
|
||||||
for (const auto& pair : musics_)
|
for (const auto& pair : musics_)
|
||||||
{
|
{
|
||||||
pair.second->SetVolume(volume_);
|
pair.second->SetVolume(volume_);
|
||||||
|
|
@ -179,7 +179,7 @@ void e2d::Player::ResumeAll()
|
||||||
{
|
{
|
||||||
for (const auto& pair : musics_)
|
for (const auto& pair : musics_)
|
||||||
{
|
{
|
||||||
pair.second->Resume();
|
pair.second->Play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@
|
||||||
<ClCompile Include="..\..\core\events\KeyEvent.cpp" />
|
<ClCompile Include="..\..\core\events\KeyEvent.cpp" />
|
||||||
<ClCompile Include="..\..\core\events\MouseEvent.cpp" />
|
<ClCompile Include="..\..\core\events\MouseEvent.cpp" />
|
||||||
<ClCompile Include="..\..\core\impl\TextRenderer.cpp" />
|
<ClCompile Include="..\..\core\impl\TextRenderer.cpp" />
|
||||||
<ClCompile Include="..\..\core\impl\VoiceCallback.cpp" />
|
<ClCompile Include="..\..\core\impl\MediaAsyncCallback.cpp" />
|
||||||
<ClCompile Include="..\..\core\modules\Audio.cpp" />
|
<ClCompile Include="..\..\core\modules\Audio.cpp" />
|
||||||
<ClCompile Include="..\..\core\modules\Device.cpp" />
|
<ClCompile Include="..\..\core\modules\Device.cpp" />
|
||||||
<ClCompile Include="..\..\core\modules\Game.cpp" />
|
<ClCompile Include="..\..\core\modules\Game.cpp" />
|
||||||
|
|
|
||||||
|
|
@ -141,9 +141,6 @@
|
||||||
<ClCompile Include="..\..\core\impl\TextRenderer.cpp">
|
<ClCompile Include="..\..\core\impl\TextRenderer.cpp">
|
||||||
<Filter>impl</Filter>
|
<Filter>impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\core\impl\VoiceCallback.cpp">
|
|
||||||
<Filter>impl</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\core\events\KeyEvent.cpp">
|
<ClCompile Include="..\..\core\events\KeyEvent.cpp">
|
||||||
<Filter>events</Filter>
|
<Filter>events</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
@ -219,6 +216,9 @@
|
||||||
<ClCompile Include="..\..\core\modules\Device.cpp">
|
<ClCompile Include="..\..\core\modules\Device.cpp">
|
||||||
<Filter>modules</Filter>
|
<Filter>modules</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\core\impl\MediaAsyncCallback.cpp">
|
||||||
|
<Filter>impl</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\core\easy2d.h" />
|
<ClInclude Include="..\..\core\easy2d.h" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue