added wp8 and winrt support files and projects

This commit is contained in:
Dale Stammen 2014-03-28 12:53:35 -07:00
parent afe561cccc
commit 97bdaad41b
13 changed files with 2631 additions and 0 deletions

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{DF125891-EEE9-4466-B903-F828FD272158}</ProjectGuid>
<RootNamespace>CocosDenshion.win32</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110_wp80</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110_wp80</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110_wp80</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110_wp80</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="..\..\2d\cocos2d_wp8_headers.props" />
<Import Project="..\..\2d\cocos2d_winrt.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Import Project="..\..\2d\cocos2d_wp8_headers.props" />
<Import Project="..\..\2d\cocos2d_winrt.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="..\..\2d\cocos2d_wp8_headers.props" />
<Import Project="..\..\2d\cocos2d_winrt.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Import Project="..\..\2d\cocos2d_wp8_headers.props" />
<Import Project="..\..\2d\cocos2d_winrt.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalIncludeDirectories>..\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WP8;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<Lib>
<AdditionalOptions>/IGNORE:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalIncludeDirectories>..\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WP8;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<Lib>
<AdditionalOptions>/IGNORE:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalIncludeDirectories>..\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WP8;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<Lib>
<AdditionalOptions>/IGNORE:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<PreprocessorDefinitions>_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalIncludeDirectories>..\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WP8;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<Lib>
<AdditionalOptions>/IGNORE:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<Reference Include="Windows">
<IsWinMDFile>true</IsWinMDFile>
</Reference>
<Reference Include="platform.winmd">
<IsWinMDFile>true</IsWinMDFile>
<Private>false</Private>
</Reference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsPhone\v$(TargetPlatformVersion)\Microsoft.Cpp.WindowsPhone.$(TargetPlatformVersion).targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<ItemGroup>
<ClInclude Include="..\include\Export.h" />
<ClInclude Include="..\include\SimpleAudioEngine.h" />
<ClInclude Include="..\wp8\Audio.h" />
<ClInclude Include="..\wp8\MediaStreamer.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\wp8\Audio.cpp" />
<ClCompile Include="..\wp8\MediaStreamer.cpp" />
<ClCompile Include="..\wp8\SimpleAudioEngine.cpp" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\Export.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\SimpleAudioEngine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\wp8\Audio.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\wp8\MediaStreamer.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\wp8\Audio.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\wp8\MediaStreamer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\wp8\SimpleAudioEngine.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<FullDeploy>true</FullDeploy>
</PropertyGroup>
</Project>

576
cocos/audio/winrt/Audio.cpp Normal file
View File

@ -0,0 +1,576 @@
//// 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
#include "pch.h"
#include "Audio.h"
#include "MediaStreamer.h"
static std::wstring CCUtf8ToUnicode(const char * pszUtf8Str, unsigned len/* = -1*/)
{
std::wstring ret;
do
{
if (! pszUtf8Str) break;
// get UTF8 string length
if (-1 == len)
{
len = strlen(pszUtf8Str);
}
if (len <= 0) break;
// get UTF16 string length
int wLen = MultiByteToWideChar(CP_UTF8, 0, pszUtf8Str, len, 0, 0);
if (0 == wLen || 0xFFFD == wLen) break;
// convert string
wchar_t * pwszStr = new wchar_t[wLen + 1];
if (! pwszStr) break;
pwszStr[wLen] = 0;
MultiByteToWideChar(CP_UTF8, 0, pszUtf8Str, len, pwszStr, wLen + 1);
ret = pwszStr;
if(pwszStr) { delete[] (pwszStr);};
} while (0);
return ret;
}
static inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
// Set a breakpoint on this line to catch DirectX API errors
throw Platform::Exception::CreateException(hr);
}
}
void AudioEngineCallbacks::Initialize(Audio *audio)
{
m_audio = audio;
}
// Called in the event of a critical system error which requires XAudio2
// to be closed down and restarted. The error code is given in error.
void _stdcall AudioEngineCallbacks::OnCriticalError(HRESULT Error)
{
m_audio->SetEngineExperiencedCriticalError();
};
Audio::Audio() :
m_backgroundID(0),
m_soundEffctVolume(1.0),
m_backgroundMusicVolume(1.0f)
{
}
void Audio::Initialize()
{
m_engineExperiencedCriticalError = false;
m_musicEngine = nullptr;
m_soundEffectEngine = nullptr;
m_musicMasteringVoice = nullptr;
m_soundEffectMasteringVoice = nullptr;
}
void Audio::CreateResources()
{
try
{
ThrowIfFailed(
XAudio2Create(&m_musicEngine)
);
#if defined(_DEBUG)
XAUDIO2_DEBUG_CONFIGURATION debugConfig = {0};
debugConfig.BreakMask = XAUDIO2_LOG_ERRORS;
debugConfig.TraceMask = XAUDIO2_LOG_ERRORS;
m_musicEngine->SetDebugConfiguration(&debugConfig);
#endif
m_musicEngineCallback.Initialize(this);
m_musicEngine->RegisterForCallbacks(&m_musicEngineCallback);
// This sample plays the equivalent of background music, which we tag on the mastering voice as AudioCategory_GameMedia.
// In ordinary usage, if we were playing the music track with no effects, we could route it entirely through
// Media Foundation. Here we are using XAudio2 to apply a reverb effect to the music, so we use Media Foundation to
// decode the data then we feed it through the XAudio2 pipeline as a separate Mastering Voice, so that we can tag it
// as Game Media.
// We default the mastering voice to 2 channels to simplify the reverb logic.
ThrowIfFailed(
m_musicEngine->CreateMasteringVoice(&m_musicMasteringVoice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, 0, nullptr, nullptr, AudioCategory_GameMedia)
);
// Create a separate engine and mastering voice for sound effects in the sample
// Games will use many voices in a complex graph for audio, mixing all effects down to a
// single mastering voice.
// We are creating an entirely new engine instance and mastering voice in order to tag
// our sound effects with the audio category AudioCategory_GameEffects.
ThrowIfFailed(
XAudio2Create(&m_soundEffectEngine)
);
m_soundEffectEngineCallback.Initialize(this);
m_soundEffectEngine->RegisterForCallbacks(&m_soundEffectEngineCallback);
// We default the mastering voice to 2 channels to simplify the reverb logic.
ThrowIfFailed(
m_soundEffectEngine->CreateMasteringVoice(&m_soundEffectMasteringVoice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, 0, nullptr, nullptr, AudioCategory_GameEffects)
);
}
catch (...)
{
m_engineExperiencedCriticalError = true;
}
}
unsigned int Audio::Hash(const char *key)
{
unsigned int len = strlen(key);
const char *end=key+len;
unsigned int hash;
for (hash = 0; key < end; key++)
{
hash *= 16777619;
hash ^= (unsigned int) (unsigned char) toupper(*key);
}
return (hash);
}
void Audio::ReleaseResources()
{
if (m_musicMasteringVoice != nullptr)
{
m_musicMasteringVoice->DestroyVoice();
m_musicMasteringVoice = nullptr;
}
if (m_soundEffectMasteringVoice != nullptr)
{
m_soundEffectMasteringVoice->DestroyVoice();
m_soundEffectMasteringVoice = nullptr;
}
EffectList::iterator EffectIter = m_soundEffects.begin();
for (; EffectIter != m_soundEffects.end(); EffectIter++)
{
if (EffectIter->second.m_soundEffectSourceVoice != nullptr)
{
EffectIter->second.m_soundEffectSourceVoice->DestroyVoice();
EffectIter->second.m_soundEffectSourceVoice = nullptr;
}
}
m_soundEffects.clear();
m_musicEngine = nullptr;
m_soundEffectEngine = nullptr;
}
void Audio::Start()
{
if (m_engineExperiencedCriticalError)
{
return;
}
if (! m_backgroundFile.empty())
PlayBackgroundMusic(m_backgroundFile.c_str(), m_backgroundLoop);
}
// This sample processes audio buffers during the render cycle of the application.
// As long as the sample maintains a high-enough frame rate, this approach should
// not glitch audio. In game code, it is best for audio buffers to be processed
// on a separate thread that is not synced to the main render loop of the game.
void Audio::Render()
{
if (m_engineExperiencedCriticalError)
{
ReleaseResources();
Initialize();
CreateResources();
Start();
if (m_engineExperiencedCriticalError)
{
return;
}
}
}
void Audio::PlayBackgroundMusic(const char* pszFilePath, bool bLoop)
{
m_backgroundFile = pszFilePath;
m_backgroundLoop = bLoop;
if (m_engineExperiencedCriticalError) {
return;
}
StopBackgroundMusic(true);
PlaySoundEffect(pszFilePath, bLoop, m_backgroundID, true);
}
void Audio::StopBackgroundMusic(bool bReleaseData)
{
if (m_engineExperiencedCriticalError) {
return;
}
StopSoundEffect(m_backgroundID);
if (bReleaseData)
UnloadSoundEffect(m_backgroundID);
}
void Audio::PauseBackgroundMusic()
{
if (m_engineExperiencedCriticalError) {
return;
}
PauseSoundEffect(m_backgroundID);
}
void Audio::ResumeBackgroundMusic()
{
if (m_engineExperiencedCriticalError) {
return;
}
ResumeSoundEffect(m_backgroundID);
}
void Audio::RewindBackgroundMusic()
{
if (m_engineExperiencedCriticalError) {
return;
}
RewindSoundEffect(m_backgroundID);
}
bool Audio::IsBackgroundMusicPlaying()
{
return IsSoundEffectStarted(m_backgroundID);
}
void Audio::SetBackgroundVolume(float volume)
{
m_backgroundMusicVolume = volume;
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() != m_soundEffects.find(m_backgroundID))
{
m_soundEffects[m_backgroundID].m_soundEffectSourceVoice->SetVolume(volume);
}
}
float Audio::GetBackgroundVolume()
{
return m_backgroundMusicVolume;
}
void Audio::SetSoundEffectVolume(float volume)
{
m_soundEffctVolume = volume;
if (m_engineExperiencedCriticalError) {
return;
}
EffectList::iterator iter;
for (iter = m_soundEffects.begin(); iter != m_soundEffects.end(); iter++)
{
if (iter->first != m_backgroundID)
iter->second.m_soundEffectSourceVoice->SetVolume(m_soundEffctVolume);
}
}
float Audio::GetSoundEffectVolume()
{
return m_soundEffctVolume;
}
void Audio::PlaySoundEffect(const char* pszFilePath, bool bLoop, unsigned int& sound, bool isMusic)
{
sound = Hash(pszFilePath);
if (m_soundEffects.end() == m_soundEffects.find(sound))
{
PreloadSoundEffect(pszFilePath, isMusic);
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
m_soundEffects[sound].m_audioBuffer.LoopCount = bLoop ? XAUDIO2_LOOP_INFINITE : 0;
PlaySoundEffect(sound);
}
void Audio::PlaySoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
StopSoundEffect(sound);
ThrowIfFailed(
m_soundEffects[sound].m_soundEffectSourceVoice->SubmitSourceBuffer(&m_soundEffects[sound].m_audioBuffer)
);
XAUDIO2_BUFFER buf = {0};
XAUDIO2_VOICE_STATE state = {0};
if (m_engineExperiencedCriticalError) {
// If there's an error, then we'll recreate the engine on the next render pass
return;
}
SoundEffectData* soundEffect = &m_soundEffects[sound];
HRESULT hr = soundEffect->m_soundEffectSourceVoice->Start();
if FAILED(hr)
{
m_engineExperiencedCriticalError = true;
return;
}
m_soundEffects[sound].m_soundEffectStarted = true;
}
void Audio::StopSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
HRESULT hr = m_soundEffects[sound].m_soundEffectSourceVoice->Stop();
HRESULT hr1 = m_soundEffects[sound].m_soundEffectSourceVoice->FlushSourceBuffers();
if (FAILED(hr) || FAILED(hr1))
{
// If there's an error, then we'll recreate the engine on the next render pass
m_engineExperiencedCriticalError = true;
return;
}
m_soundEffects[sound].m_soundEffectStarted = false;
}
void Audio::PauseSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
HRESULT hr = m_soundEffects[sound].m_soundEffectSourceVoice->Stop();
if FAILED(hr)
{
// If there's an error, then we'll recreate the engine on the next render pass
m_engineExperiencedCriticalError = true;
return;
}
}
void Audio::ResumeSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
HRESULT hr = m_soundEffects[sound].m_soundEffectSourceVoice->Start();
if FAILED(hr)
{
// If there's an error, then we'll recreate the engine on the next render pass
m_engineExperiencedCriticalError = true;
return;
}
}
void Audio::RewindSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
StopSoundEffect(sound);
PlaySoundEffect(sound);
}
void Audio::PauseAllSoundEffects()
{
if (m_engineExperiencedCriticalError) {
return;
}
EffectList::iterator iter;
for (iter = m_soundEffects.begin(); iter != m_soundEffects.end(); iter++)
{
PauseSoundEffect(iter->first);
}
}
void Audio::ResumeAllSoundEffects()
{
if (m_engineExperiencedCriticalError) {
return;
}
EffectList::iterator iter;
for (iter = m_soundEffects.begin(); iter != m_soundEffects.end(); iter++)
{
ResumeSoundEffect(iter->first);
}
}
void Audio::StopAllSoundEffects()
{
if (m_engineExperiencedCriticalError) {
return;
}
EffectList::iterator iter;
for (iter = m_soundEffects.begin(); iter != m_soundEffects.end(); iter++)
{
StopSoundEffect(iter->first);
}
}
bool Audio::IsSoundEffectStarted(unsigned int sound)
{
if (m_soundEffects.end() == m_soundEffects.find(sound))
return false;
return m_soundEffects[sound].m_soundEffectStarted;
}
void Audio::PreloadSoundEffect(const char* pszFilePath, bool isMusic)
{
if (m_engineExperiencedCriticalError) {
return;
}
int sound = Hash(pszFilePath);
if (m_soundEffects.end() != m_soundEffects.find(sound))
{
return;
}
MediaStreamer mediaStreamer;
mediaStreamer.Initialize(CCUtf8ToUnicode(pszFilePath, -1).c_str());
m_soundEffects[sound].m_soundID = sound;
uint32 bufferLength = mediaStreamer.GetMaxStreamLengthInBytes();
if (m_soundEffects.find(sound) != m_soundEffects.end())
{
if (m_soundEffects[sound].m_soundEffectBufferData)
{
delete[] m_soundEffects[sound].m_soundEffectBufferData;
m_soundEffects[sound].m_soundEffectBufferData = NULL;
}
}
else
{
m_soundEffects[sound].m_soundEffectBufferData = NULL;
}
m_soundEffects[sound].m_soundEffectBufferData = new byte[bufferLength];
mediaStreamer.ReadAll(m_soundEffects[sound].m_soundEffectBufferData, bufferLength, &m_soundEffects[sound].m_soundEffectBufferLength);
if (isMusic)
{
XAUDIO2_SEND_DESCRIPTOR descriptors[1];
descriptors[0].pOutputVoice = m_musicMasteringVoice;
descriptors[0].Flags = 0;
XAUDIO2_VOICE_SENDS sends = {0};
sends.SendCount = 1;
sends.pSends = descriptors;
ThrowIfFailed(
m_musicEngine->CreateSourceVoice(&m_soundEffects[sound].m_soundEffectSourceVoice,
&(mediaStreamer.GetOutputWaveFormatEx()), 0, 1.0f, &m_voiceContext, &sends)
);
//fix bug: set a initial volume
m_soundEffects[sound].m_soundEffectSourceVoice->SetVolume(m_backgroundMusicVolume);
} else
{
XAUDIO2_SEND_DESCRIPTOR descriptors[1];
descriptors[0].pOutputVoice = m_soundEffectMasteringVoice;
descriptors[0].Flags = 0;
XAUDIO2_VOICE_SENDS sends = {0};
sends.SendCount = 1;
sends.pSends = descriptors;
ThrowIfFailed(
m_soundEffectEngine->CreateSourceVoice(&m_soundEffects[sound].m_soundEffectSourceVoice,
&(mediaStreamer.GetOutputWaveFormatEx()), 0, 1.0f, &m_voiceContext, &sends, nullptr)
);
//fix bug: set a initial volume
m_soundEffects[sound].m_soundEffectSourceVoice->SetVolume(m_soundEffctVolume);
}
m_soundEffects[sound].m_soundEffectSampleRate = mediaStreamer.GetOutputWaveFormatEx().nSamplesPerSec;
// Queue in-memory buffer for playback
ZeroMemory(&m_soundEffects[sound].m_audioBuffer, sizeof(m_soundEffects[sound].m_audioBuffer));
m_soundEffects[sound].m_audioBuffer.AudioBytes = m_soundEffects[sound].m_soundEffectBufferLength;
m_soundEffects[sound].m_audioBuffer.pAudioData = m_soundEffects[sound].m_soundEffectBufferData;
m_soundEffects[sound].m_audioBuffer.pContext = &m_soundEffects[sound];
m_soundEffects[sound].m_audioBuffer.Flags = XAUDIO2_END_OF_STREAM;
m_soundEffects[sound].m_audioBuffer.LoopCount = 0;
}
void Audio::UnloadSoundEffect(const char* pszFilePath)
{
int sound = Hash(pszFilePath);
UnloadSoundEffect(sound);
}
void Audio::UnloadSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
m_soundEffects[sound].m_soundEffectSourceVoice->DestroyVoice();
if (m_soundEffects[sound].m_soundEffectBufferData)
{
delete[] m_soundEffects[sound].m_soundEffectBufferData;
m_soundEffects[sound].m_soundEffectBufferData = NULL;
}
m_soundEffects[sound].m_soundEffectSourceVoice = nullptr;
m_soundEffects[sound].m_soundEffectStarted = false;//
ZeroMemory(&m_soundEffects[sound].m_audioBuffer, sizeof(m_soundEffects[sound].m_audioBuffer));
m_soundEffects.erase(sound);
}

152
cocos/audio/winrt/Audio.h Normal file
View File

@ -0,0 +1,152 @@
//// 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 "pch.h"
#include <map>
static const int STREAMING_BUFFER_SIZE = 65536;
static const int MAX_BUFFER_COUNT = 3;
struct SoundEffectData
{
unsigned int m_soundID;
IXAudio2SourceVoice* m_soundEffectSourceVoice;
XAUDIO2_BUFFER m_audioBuffer;
byte* m_soundEffectBufferData;
uint32 m_soundEffectBufferLength;
uint32 m_soundEffectSampleRate;
bool m_soundEffectStarted;
};
class Audio;
class AudioEngineCallbacks: public IXAudio2EngineCallback
{
private:
Audio *m_audio;
public :
AudioEngineCallbacks(){};
void Initialize(Audio* audio);
// Called by XAudio2 just before an audio processing pass begins.
void _stdcall OnProcessingPassStart(){};
// Called just after an audio processing pass ends.
void _stdcall OnProcessingPassEnd(){};
// Called in the event of a critical system error which requires XAudio2
// to be closed down and restarted. The error code is given in Error.
void _stdcall OnCriticalError(HRESULT Error);
};
struct StreamingVoiceContext : public IXAudio2VoiceCallback
{
STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32){}
STDMETHOD_(void, OnVoiceProcessingPassEnd)(){}
STDMETHOD_(void, OnStreamEnd)(){}
STDMETHOD_(void, OnBufferStart)(void*)
{
ResetEvent(hBufferEndEvent);
}
STDMETHOD_(void, OnBufferEnd)(void* pContext)
{
//Trigger the event for the music stream.
if (pContext == 0) {
SetEvent(hBufferEndEvent);
}
}
STDMETHOD_(void, OnLoopEnd)(void*){}
STDMETHOD_(void, OnVoiceError)(void*, HRESULT){}
HANDLE hBufferEndEvent;
StreamingVoiceContext() : hBufferEndEvent(CreateEventEx(NULL, FALSE, FALSE, NULL))
{
}
virtual ~StreamingVoiceContext()
{
CloseHandle(hBufferEndEvent);
}
};
class Audio
{
private:
IXAudio2* m_musicEngine;
IXAudio2* m_soundEffectEngine;
IXAudio2MasteringVoice* m_musicMasteringVoice;
IXAudio2MasteringVoice* m_soundEffectMasteringVoice;
StreamingVoiceContext m_voiceContext;
typedef std::map<unsigned int, SoundEffectData> EffectList;
EffectList m_soundEffects;
unsigned int m_backgroundID;
std::string m_backgroundFile;
bool m_backgroundLoop;
float m_soundEffctVolume;
float m_backgroundMusicVolume;
bool m_engineExperiencedCriticalError;
AudioEngineCallbacks m_musicEngineCallback;
AudioEngineCallbacks m_soundEffectEngineCallback;
unsigned int Hash(const char* key);
public:
Audio();
void Initialize();
void CreateResources();
void ReleaseResources();
void Start();
void Render();
// This flag can be used to tell when the audio system is experiencing critial errors.
// XAudio2 gives a critical error when the user unplugs their headphones, and a new
// speaker configuration is generated.
void SetEngineExperiencedCriticalError()
{
m_engineExperiencedCriticalError = true;
}
bool HasEngineExperiencedCriticalError()
{
return m_engineExperiencedCriticalError;
}
void PlayBackgroundMusic(const char* pszFilePath, bool bLoop);
void StopBackgroundMusic(bool bReleaseData);
void PauseBackgroundMusic();
void ResumeBackgroundMusic();
void RewindBackgroundMusic();
bool IsBackgroundMusicPlaying();
void SetBackgroundVolume(float volume);
float GetBackgroundVolume();
void SetSoundEffectVolume(float volume);
float GetSoundEffectVolume();
void PlaySoundEffect(const char* pszFilePath, bool bLoop, unsigned int& sound, bool isMusic = false);
void PlaySoundEffect(unsigned int sound);
bool IsSoundEffectStarted(unsigned int sound);
void StopSoundEffect(unsigned int sound);
void PauseSoundEffect(unsigned int sound);
void ResumeSoundEffect(unsigned int sound);
void RewindSoundEffect(unsigned int sound);
void PauseAllSoundEffects();
void ResumeAllSoundEffects();
void StopAllSoundEffects();
void PreloadSoundEffect(const char* pszFilePath, bool isMusic = false);
void UnloadSoundEffect(const char* pszFilePath);
void UnloadSoundEffect(unsigned int sound);
};

View File

@ -0,0 +1,215 @@
//// 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
#include "pch.h"
#include "MediaStreamer.h"
using namespace Windows::ApplicationModel;
static inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
// Set a breakpoint on this line to catch DirectX API errors
throw Platform::Exception::CreateException(hr);
}
}
MediaStreamer::MediaStreamer()
{
m_reader = nullptr;
m_audioType = nullptr;
ZeroMemory(&m_waveFormat, sizeof(m_waveFormat));
m_installedLocation = Package::Current->InstalledLocation;
m_installedLocationPath = Platform::String::Concat(m_installedLocation->Path, "\\Assets\\Resources\\");
}
MediaStreamer::~MediaStreamer()
{
}
void MediaStreamer::Initialize(__in const WCHAR* url)
{
Microsoft::WRL::ComPtr<IMFMediaType> outputMediaType;
Microsoft::WRL::ComPtr<IMFMediaType> mediaType;
ThrowIfFailed(
MFStartup(MF_VERSION)
);
WCHAR filePath[MAX_PATH] = {0};
if ((wcslen(url) > 1 && url[1] == ':'))
{
// path start with "x:", is absolute path
wcscat_s(filePath, url);
}
else if (wcslen(url) > 0
&& (L'/' == url[0] || L'\\' == url[0]))
{
// path start with '/' or '\', is absolute path without driver name
wcscat_s(filePath, m_installedLocationPath->Data());
// remove '/' or '\\'
wcscat_s(filePath, (const WCHAR*)url[1]);
}else
{
wcscat_s(filePath, m_installedLocationPath->Data());
wcscat_s(filePath, url);
}
ThrowIfFailed(
MFCreateSourceReaderFromURL(filePath, nullptr, &m_reader)
);
// Set the decoded output format as PCM
// XAudio2 on Windows can process PCM and ADPCM-encoded buffers.
// When using MF, this sample always decodes into PCM.
ThrowIfFailed(
MFCreateMediaType(&mediaType)
);
ThrowIfFailed(
mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)
);
ThrowIfFailed(
mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)
);
ThrowIfFailed(
m_reader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, mediaType.Get())
);
// Get the complete WAVEFORMAT from the Media Type
ThrowIfFailed(
m_reader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &outputMediaType)
);
uint32 formatSize = 0;
WAVEFORMATEX* waveFormat;
ThrowIfFailed(
MFCreateWaveFormatExFromMFMediaType(outputMediaType.Get(), &waveFormat, &formatSize)
);
CopyMemory(&m_waveFormat, waveFormat, sizeof(m_waveFormat));
CoTaskMemFree(waveFormat);
// Get the total length of the stream in bytes
PROPVARIANT var;
ThrowIfFailed(
m_reader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var)
);
LONGLONG duration = var.uhVal.QuadPart;
double durationInSeconds = (duration / static_cast<double>(10000000)); // duration is in 100ns units, convert to seconds
m_maxStreamLengthInBytes = static_cast<unsigned int>(durationInSeconds * m_waveFormat.nAvgBytesPerSec);
// Round up the buffer size to the nearest four bytes
m_maxStreamLengthInBytes = (m_maxStreamLengthInBytes + 3) / 4 * 4;
}
bool MediaStreamer::GetNextBuffer(uint8* buffer, uint32 maxBufferSize, uint32* bufferLength)
{
Microsoft::WRL::ComPtr<IMFSample> sample;
Microsoft::WRL::ComPtr<IMFMediaBuffer> mediaBuffer;
BYTE *audioData = nullptr;
DWORD sampleBufferLength = 0;
DWORD flags = 0;
*bufferLength = 0;
if (m_reader == nullptr)
{
return false;
}
ThrowIfFailed(
m_reader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, &flags, nullptr, &sample)
);
if (sample == nullptr)
{
if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
{
return true;
}
else
{
return false;
}
}
ThrowIfFailed(
sample->ConvertToContiguousBuffer(&mediaBuffer)
);
ThrowIfFailed(
mediaBuffer->Lock(&audioData, nullptr, &sampleBufferLength)
);
// If buffer isn't large enough, dump sample
if (sampleBufferLength <= maxBufferSize)
{
CopyMemory(buffer, audioData, sampleBufferLength);
*bufferLength = sampleBufferLength;
}
else
{
#if defined(COCOS2D_DEBUG)
OutputDebugString(L"Sample buffer dumped");
#endif
}
if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
{
return true;
}
else
{
return false;
}
}
void MediaStreamer::ReadAll(uint8* buffer, uint32 maxBufferSize, uint32* bufferLength)
{
uint32 valuesWritten = 0;
uint32 sampleBufferLength = 0;
if (m_reader == nullptr)
{
return;
}
*bufferLength = 0;
// If buffer isn't large enough, return
if (maxBufferSize < m_maxStreamLengthInBytes)
{
return;
}
while (!GetNextBuffer(buffer + valuesWritten, maxBufferSize - valuesWritten, &sampleBufferLength))
{
valuesWritten += sampleBufferLength;
}
*bufferLength = valuesWritten + sampleBufferLength;
}
void MediaStreamer::Restart()
{
if (m_reader == nullptr)
{
return;
}
PROPVARIANT var = {0};
var.vt = VT_I8;
ThrowIfFailed(
m_reader->SetCurrentPosition(GUID_NULL, var)
);
}

View File

@ -0,0 +1,41 @@
//// 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 "pch.h"
class MediaStreamer
{
private:
WAVEFORMATEX m_waveFormat;
uint32 m_maxStreamLengthInBytes;
Windows::Storage::StorageFolder^ m_installedLocation;
Platform::String^ m_installedLocationPath;
public:
Microsoft::WRL::ComPtr<IMFSourceReader> m_reader;
Microsoft::WRL::ComPtr<IMFMediaType> m_audioType;
public:
MediaStreamer();
~MediaStreamer();
WAVEFORMATEX& GetOutputWaveFormatEx()
{
return m_waveFormat;
}
UINT32 GetMaxStreamLengthInBytes()
{
return m_maxStreamLengthInBytes;
}
void Initialize(_In_ const WCHAR* url);
bool GetNextBuffer(uint8* buffer, uint32 maxBufferSize, uint32* bufferLength);
void ReadAll(uint8* buffer, uint32 maxBufferSize, uint32* bufferLength);
void Restart();
};

View File

@ -0,0 +1,212 @@
/****************************************************************************
Copyright (c) 2010-2013 cocos2d-x.org
Copyright (c) Microsoft Open Technologies, Inc.
http://www.cocos2d-x.org
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 "SimpleAudioEngine.h"
#include "Audio.h"
#include <map>
//#include "CCCommon.h"
using namespace std;
namespace CocosDenshion {
Audio* s_audioController = NULL;
// a flag that if the s_audioController should be re-initialiezed
// see also in SimpleAudioEngine::end() in this file
bool s_bAudioControllerNeedReInitialize = true;
static Audio* sharedAudioController()
{
if ((! s_audioController) || s_bAudioControllerNeedReInitialize)
{
s_audioController = new Audio;
s_audioController->Initialize();
s_audioController->CreateResources();
s_bAudioControllerNeedReInitialize = false;
}
return s_audioController;
}
SimpleAudioEngine::SimpleAudioEngine()
{
}
SimpleAudioEngine::~SimpleAudioEngine()
{
}
SimpleAudioEngine* SimpleAudioEngine::sharedEngine()
{
static SimpleAudioEngine s_SharedEngine;
return &s_SharedEngine;
}
void SimpleAudioEngine::end()
{
sharedAudioController()->StopBackgroundMusic(true);
sharedAudioController()->StopAllSoundEffects();
sharedAudioController()->ReleaseResources();
//set here to tell the s_bAudioControllerNeedReInitialize should be re-initialized
s_bAudioControllerNeedReInitialize = true;
}
#if 0
void SimpleAudioEngine::render()
{
sharedAudioController()->Render();
}
#endif
//////////////////////////////////////////////////////////////////////////
// BackgroundMusic
//////////////////////////////////////////////////////////////////////////
void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop)
{
if (! pszFilePath)
{
return;
}
sharedAudioController()->PlayBackgroundMusic(pszFilePath, bLoop);
}
void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData)
{
sharedAudioController()->StopBackgroundMusic(bReleaseData);
}
void SimpleAudioEngine::pauseBackgroundMusic()
{
sharedAudioController()->PauseBackgroundMusic();
}
void SimpleAudioEngine::resumeBackgroundMusic()
{
sharedAudioController()->ResumeBackgroundMusic();
}
void SimpleAudioEngine::rewindBackgroundMusic()
{
sharedAudioController()->RewindBackgroundMusic();
}
bool SimpleAudioEngine::willPlayBackgroundMusic()
{
return false;
}
bool SimpleAudioEngine::isBackgroundMusicPlaying()
{
return sharedAudioController()->IsBackgroundMusicPlaying();
}
//////////////////////////////////////////////////////////////////////////
// effect function
//////////////////////////////////////////////////////////////////////////
unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop)
{
unsigned int sound;
sharedAudioController()->PlaySoundEffect(pszFilePath, bLoop, sound);
return sound;
}
void SimpleAudioEngine::stopEffect(unsigned int nSoundId)
{
sharedAudioController()->StopSoundEffect(nSoundId);
}
void SimpleAudioEngine::preloadEffect(const char* pszFilePath)
{
sharedAudioController()->PreloadSoundEffect(pszFilePath);
}
void SimpleAudioEngine::pauseEffect(unsigned int nSoundId)
{
sharedAudioController()->PauseSoundEffect(nSoundId);
}
void SimpleAudioEngine::resumeEffect(unsigned int nSoundId)
{
sharedAudioController()->ResumeSoundEffect(nSoundId);
}
void SimpleAudioEngine::pauseAllEffects()
{
sharedAudioController()->PauseAllSoundEffects();
}
void SimpleAudioEngine::resumeAllEffects()
{
sharedAudioController()->ResumeAllSoundEffects();
}
void SimpleAudioEngine::stopAllEffects()
{
sharedAudioController()->StopAllSoundEffects();
}
void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath)
{
}
void SimpleAudioEngine::unloadEffect(const char* pszFilePath)
{
sharedAudioController()->UnloadSoundEffect(pszFilePath);
}
//////////////////////////////////////////////////////////////////////////
// volume interface
//////////////////////////////////////////////////////////////////////////
float SimpleAudioEngine::getBackgroundMusicVolume()
{
return sharedAudioController()->GetBackgroundVolume();
}
void SimpleAudioEngine::setBackgroundMusicVolume(float volume)
{
sharedAudioController()->SetBackgroundVolume((volume<=0.0f)? 0.0f : volume);
}
float SimpleAudioEngine::getEffectsVolume()
{
return sharedAudioController()->GetSoundEffectVolume();
}
void SimpleAudioEngine::setEffectsVolume(float volume)
{
sharedAudioController()->SetSoundEffectVolume((volume<=0.0f)? 0.0f : volume);
}
} // end of namespace CocosDenshion

581
cocos/audio/wp8/Audio.cpp Normal file
View File

@ -0,0 +1,581 @@
/*
* cocos2d-x http://www.cocos2d-x.org
*
* Copyright (c) 2010-2011 - cocos2d-x community
*
* Portions Copyright (c) Microsoft Open Technologies, Inc.
* All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
#include "Audio.h"
#include "MediaStreamer.h"
//#include "CCCommon.h"
inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
// Set a breakpoint on this line to catch DX API errors.
throw Platform::Exception::CreateException(hr);
}
}
void AudioEngineCallbacks::Initialize(Audio *audio)
{
m_audio = audio;
}
// Called in the event of a critical system error which requires XAudio2
// to be closed down and restarted. The error code is given in error.
void _stdcall AudioEngineCallbacks::OnCriticalError(HRESULT Error)
{
UNUSED_PARAM(Error);
m_audio->SetEngineExperiencedCriticalError();
};
Audio::Audio() :
m_backgroundID(0),
m_soundEffctVolume(1.0f),
m_backgroundMusicVolume(1.0f)
{
}
void Audio::Initialize()
{
m_engineExperiencedCriticalError = false;
m_musicEngine = nullptr;
m_soundEffectEngine = nullptr;
m_musicMasteringVoice = nullptr;
m_soundEffectMasteringVoice = nullptr;
}
void Audio::CreateResources()
{
try
{
ThrowIfFailed(
XAudio2Create(&m_musicEngine)
);
#if defined(_DEBUG)
XAUDIO2_DEBUG_CONFIGURATION debugConfig = {0};
debugConfig.BreakMask = XAUDIO2_LOG_ERRORS;
debugConfig.TraceMask = XAUDIO2_LOG_ERRORS;
m_musicEngine->SetDebugConfiguration(&debugConfig);
#endif
m_musicEngineCallback.Initialize(this);
m_musicEngine->RegisterForCallbacks(&m_musicEngineCallback);
// This sample plays the equivalent of background music, which we tag on the mastering voice as AudioCategory_GameMedia.
// In ordinary usage, if we were playing the music track with no effects, we could route it entirely through
// Media Foundation. Here we are using XAudio2 to apply a reverb effect to the music, so we use Media Foundation to
// decode the data then we feed it through the XAudio2 pipeline as a separate Mastering Voice, so that we can tag it
// as Game Media.
// We default the mastering voice to 2 channels to simplify the reverb logic.
ThrowIfFailed(
m_musicEngine->CreateMasteringVoice(&m_musicMasteringVoice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, 0, nullptr, nullptr, AudioCategory_GameMedia)
);
// Create a separate engine and mastering voice for sound effects in the sample
// Games will use many voices in a complex graph for audio, mixing all effects down to a
// single mastering voice.
// We are creating an entirely new engine instance and mastering voice in order to tag
// our sound effects with the audio category AudioCategory_GameEffects.
ThrowIfFailed(
XAudio2Create(&m_soundEffectEngine)
);
m_soundEffectEngineCallback.Initialize(this);
m_soundEffectEngine->RegisterForCallbacks(&m_soundEffectEngineCallback);
// We default the mastering voice to 2 channels to simplify the reverb logic.
ThrowIfFailed(
m_soundEffectEngine->CreateMasteringVoice(&m_soundEffectMasteringVoice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, 0, nullptr, nullptr, AudioCategory_GameEffects)
);
}
catch (...)
{
m_engineExperiencedCriticalError = true;
}
}
unsigned int Audio::Hash(const char *key)
{
unsigned int len = strlen(key);
const char *end=key+len;
unsigned int hash;
for (hash = 0; key < end; key++)
{
hash *= 16777619;
hash ^= (unsigned int) (unsigned char) toupper(*key);
}
return (hash);
}
void Audio::ReleaseResources()
{
if (m_musicMasteringVoice != nullptr)
{
m_musicMasteringVoice->DestroyVoice();
m_musicMasteringVoice = nullptr;
}
if (m_soundEffectMasteringVoice != nullptr)
{
m_soundEffectMasteringVoice->DestroyVoice();
m_soundEffectMasteringVoice = nullptr;
}
EffectList::iterator EffectIter = m_soundEffects.begin();
for (; EffectIter != m_soundEffects.end(); EffectIter++)
{
if (EffectIter->second.m_soundEffectSourceVoice != nullptr)
{
EffectIter->second.m_soundEffectSourceVoice->DestroyVoice();
EffectIter->second.m_soundEffectSourceVoice = nullptr;
}
}
m_soundEffects.clear();
m_musicEngine = nullptr;
m_soundEffectEngine = nullptr;
}
void Audio::Start()
{
if (m_engineExperiencedCriticalError)
{
return;
}
if (! m_backgroundFile.empty())
PlayBackgroundMusic(m_backgroundFile.c_str(), m_backgroundLoop);
}
// This sample processes audio buffers during the render cycle of the application.
// As long as the sample maintains a high-enough frame rate, this approach should
// not glitch audio. In game code, it is best for audio buffers to be processed
// on a separate thread that is not synced to the main render loop of the game.
void Audio::Render()
{
if (m_engineExperiencedCriticalError)
{
ReleaseResources();
Initialize();
CreateResources();
Start();
if (m_engineExperiencedCriticalError)
{
return;
}
}
}
void Audio::PlayBackgroundMusic(const char* pszFilePath, bool bLoop)
{
m_backgroundFile = pszFilePath;
m_backgroundLoop = bLoop;
if (m_engineExperiencedCriticalError) {
return;
}
StopBackgroundMusic(true);
PlaySoundEffect(pszFilePath, bLoop, m_backgroundID, true);
}
void Audio::StopBackgroundMusic(bool bReleaseData)
{
if (m_engineExperiencedCriticalError) {
return;
}
StopSoundEffect(m_backgroundID);
if (bReleaseData)
UnloadSoundEffect(m_backgroundID);
}
void Audio::PauseBackgroundMusic()
{
if (m_engineExperiencedCriticalError) {
return;
}
PauseSoundEffect(m_backgroundID);
}
void Audio::ResumeBackgroundMusic()
{
if (m_engineExperiencedCriticalError) {
return;
}
ResumeSoundEffect(m_backgroundID);
}
void Audio::RewindBackgroundMusic()
{
if (m_engineExperiencedCriticalError) {
return;
}
RewindSoundEffect(m_backgroundID);
}
bool Audio::IsBackgroundMusicPlaying()
{
return IsSoundEffectStarted(m_backgroundID);
}
void Audio::SetBackgroundVolume(float volume)
{
m_backgroundMusicVolume = volume;
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() != m_soundEffects.find(m_backgroundID))
{
m_soundEffects[m_backgroundID].m_soundEffectSourceVoice->SetVolume(volume);
}
}
float Audio::GetBackgroundVolume()
{
return m_backgroundMusicVolume;
}
void Audio::SetSoundEffectVolume(float volume)
{
m_soundEffctVolume = volume;
if (m_engineExperiencedCriticalError) {
return;
}
EffectList::iterator iter;
for (iter = m_soundEffects.begin(); iter != m_soundEffects.end(); iter++)
{
if (iter->first != m_backgroundID)
iter->second.m_soundEffectSourceVoice->SetVolume(m_soundEffctVolume);
}
}
float Audio::GetSoundEffectVolume()
{
return m_soundEffctVolume;
}
void Audio::PlaySoundEffect(const char* pszFilePath, bool bLoop, unsigned int& sound, bool isMusic)
{
sound = Hash(pszFilePath);
if (m_soundEffects.end() == m_soundEffects.find(sound))
{
PreloadSoundEffect(pszFilePath, isMusic);
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
m_soundEffects[sound].m_audioBuffer.LoopCount = bLoop ? XAUDIO2_LOOP_INFINITE : 0;
PlaySoundEffect(sound);
}
void Audio::PlaySoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
StopSoundEffect(sound);
ThrowIfFailed(
m_soundEffects[sound].m_soundEffectSourceVoice->SubmitSourceBuffer(&m_soundEffects[sound].m_audioBuffer)
);
if (m_engineExperiencedCriticalError) {
// If there's an error, then we'll recreate the engine on the next render pass
return;
}
SoundEffectData* soundEffect = &m_soundEffects[sound];
HRESULT hr = soundEffect->m_soundEffectSourceVoice->Start();
if FAILED(hr)
{
m_engineExperiencedCriticalError = true;
return;
}
m_soundEffects[sound].m_soundEffectStarted = true;
}
void Audio::StopSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
HRESULT hr = m_soundEffects[sound].m_soundEffectSourceVoice->Stop();
HRESULT hr1 = m_soundEffects[sound].m_soundEffectSourceVoice->FlushSourceBuffers();
if (FAILED(hr) || FAILED(hr1))
{
// If there's an error, then we'll recreate the engine on the next render pass
m_engineExperiencedCriticalError = true;
return;
}
m_soundEffects[sound].m_soundEffectStarted = false;
}
void Audio::PauseSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
HRESULT hr = m_soundEffects[sound].m_soundEffectSourceVoice->Stop();
if FAILED(hr)
{
// If there's an error, then we'll recreate the engine on the next render pass
m_engineExperiencedCriticalError = true;
return;
}
}
void Audio::ResumeSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
HRESULT hr = m_soundEffects[sound].m_soundEffectSourceVoice->Start();
if FAILED(hr)
{
// If there's an error, then we'll recreate the engine on the next render pass
m_engineExperiencedCriticalError = true;
return;
}
}
void Audio::RewindSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
StopSoundEffect(sound);
PlaySoundEffect(sound);
}
void Audio::PauseAllSoundEffects()
{
if (m_engineExperiencedCriticalError) {
return;
}
EffectList::iterator iter;
for (iter = m_soundEffects.begin(); iter != m_soundEffects.end(); iter++)
{
PauseSoundEffect(iter->first);
}
}
void Audio::ResumeAllSoundEffects()
{
if (m_engineExperiencedCriticalError) {
return;
}
EffectList::iterator iter;
for (iter = m_soundEffects.begin(); iter != m_soundEffects.end(); iter++)
{
ResumeSoundEffect(iter->first);
}
}
void Audio::StopAllSoundEffects()
{
if (m_engineExperiencedCriticalError) {
return;
}
EffectList::iterator iter;
for (iter = m_soundEffects.begin(); iter != m_soundEffects.end(); iter++)
{
StopSoundEffect(iter->first);
}
}
bool Audio::IsSoundEffectStarted(unsigned int sound)
{
if (m_soundEffects.end() == m_soundEffects.find(sound))
return false;
return m_soundEffects[sound].m_soundEffectStarted;
}
std::wstring CCUtf8ToUnicode(const char * pszUtf8Str)
{
std::wstring ret;
do
{
if (! pszUtf8Str) break;
size_t len = strlen(pszUtf8Str);
if (len <= 0) break;
++len;
wchar_t * pwszStr = new wchar_t[len];
if (! pwszStr) break;
pwszStr[len - 1] = 0;
MultiByteToWideChar(CP_UTF8, 0, pszUtf8Str, len, pwszStr, len);
ret = pwszStr;
if(pwszStr) {
delete[] (pwszStr);
(pwszStr) = 0;
}
} while (0);
return ret;
}
std::string CCUnicodeToUtf8(const wchar_t* pwszStr)
{
std::string ret;
do
{
if(! pwszStr) break;
size_t len = wcslen(pwszStr);
if (len <= 0) break;
char * pszUtf8Str = new char[len*3 + 1];
WideCharToMultiByte(CP_UTF8, 0, pwszStr, len+1, pszUtf8Str, len*3 + 1, 0, 0);
ret = pszUtf8Str;
if(pszUtf8Str) {
delete[] (pszUtf8Str);
(pszUtf8Str) = 0;
}
}while(0);
return ret;
}
void Audio::PreloadSoundEffect(const char* pszFilePath, bool isMusic)
{
if (m_engineExperiencedCriticalError) {
return;
}
int sound = Hash(pszFilePath);
MediaStreamer mediaStreamer;
mediaStreamer.Initialize(CCUtf8ToUnicode(pszFilePath).c_str());
m_soundEffects[sound].m_soundID = sound;
uint32 bufferLength = mediaStreamer.GetMaxStreamLengthInBytes();
m_soundEffects[sound].m_soundEffectBufferData = new byte[bufferLength];
mediaStreamer.ReadAll(m_soundEffects[sound].m_soundEffectBufferData, bufferLength, &m_soundEffects[sound].m_soundEffectBufferLength);
if (isMusic)
{
XAUDIO2_SEND_DESCRIPTOR descriptors[1];
descriptors[0].pOutputVoice = m_musicMasteringVoice;
descriptors[0].Flags = 0;
XAUDIO2_VOICE_SENDS sends = {0};
sends.SendCount = 1;
sends.pSends = descriptors;
ThrowIfFailed(
m_musicEngine->CreateSourceVoice(&m_soundEffects[sound].m_soundEffectSourceVoice,
&(mediaStreamer.GetOutputWaveFormatEx()), 0, 1.0f, &m_voiceContext, &sends)
);
//fix bug: set a initial volume
m_soundEffects[sound].m_soundEffectSourceVoice->SetVolume(m_backgroundMusicVolume);
} else
{
XAUDIO2_SEND_DESCRIPTOR descriptors[1];
descriptors[0].pOutputVoice = m_soundEffectMasteringVoice;
descriptors[0].Flags = 0;
XAUDIO2_VOICE_SENDS sends = {0};
sends.SendCount = 1;
sends.pSends = descriptors;
ThrowIfFailed(
m_soundEffectEngine->CreateSourceVoice(&m_soundEffects[sound].m_soundEffectSourceVoice,
&(mediaStreamer.GetOutputWaveFormatEx()), 0, 1.0f, &m_voiceContext, &sends, nullptr)
);
//fix bug: set a initial volume
m_soundEffects[sound].m_soundEffectSourceVoice->SetVolume(m_soundEffctVolume);
}
m_soundEffects[sound].m_soundEffectSampleRate = mediaStreamer.GetOutputWaveFormatEx().nSamplesPerSec;
// Queue in-memory buffer for playback
ZeroMemory(&m_soundEffects[sound].m_audioBuffer, sizeof(m_soundEffects[sound].m_audioBuffer));
m_soundEffects[sound].m_audioBuffer.AudioBytes = m_soundEffects[sound].m_soundEffectBufferLength;
m_soundEffects[sound].m_audioBuffer.pAudioData = m_soundEffects[sound].m_soundEffectBufferData;
m_soundEffects[sound].m_audioBuffer.pContext = &m_soundEffects[sound];
m_soundEffects[sound].m_audioBuffer.Flags = XAUDIO2_END_OF_STREAM;
m_soundEffects[sound].m_audioBuffer.LoopCount = 0;
}
void Audio::UnloadSoundEffect(const char* pszFilePath)
{
int sound = Hash(pszFilePath);
UnloadSoundEffect(sound);
}
void Audio::UnloadSoundEffect(unsigned int sound)
{
if (m_engineExperiencedCriticalError) {
return;
}
if (m_soundEffects.end() == m_soundEffects.find(sound))
return;
m_soundEffects[sound].m_soundEffectSourceVoice->DestroyVoice();
if(m_soundEffects[sound].m_soundEffectBufferData)
delete [] m_soundEffects[sound].m_soundEffectBufferData;
m_soundEffects[sound].m_soundEffectBufferData = nullptr;
m_soundEffects[sound].m_soundEffectSourceVoice = nullptr;
m_soundEffects[sound].m_soundEffectStarted = false;
ZeroMemory(&m_soundEffects[sound].m_audioBuffer, sizeof(m_soundEffects[sound].m_audioBuffer));
m_soundEffects.erase(sound);
}

164
cocos/audio/wp8/Audio.h Normal file
View File

@ -0,0 +1,164 @@
//// 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
// For licensing information relating to this distribution please see Third Party Notices file.
#pragma once
#include <wrl.h>
#include <d3d11_1.h>
#include <agile.h>
#include <DirectXMath.h>
#include <memory>
#define XAUDIO2_HELPER_FUNCTIONS 1
#include <xaudio2.h>
#include <map>
static const int STREAMING_BUFFER_SIZE = 65536;
static const int MAX_BUFFER_COUNT = 3;
#define UNUSED_PARAM(unusedparam) (void)unusedparam
struct SoundEffectData
{
unsigned int m_soundID;
IXAudio2SourceVoice* m_soundEffectSourceVoice;
XAUDIO2_BUFFER m_audioBuffer;
byte* m_soundEffectBufferData;
uint32 m_soundEffectBufferLength;
uint32 m_soundEffectSampleRate;
bool m_soundEffectStarted;
};
class Audio;
class AudioEngineCallbacks: public IXAudio2EngineCallback
{
private:
Audio *m_audio;
public :
AudioEngineCallbacks(){};
void Initialize(Audio* audio);
// Called by XAudio2 just before an audio processing pass begins.
void _stdcall OnProcessingPassStart(){};
// Called just after an audio processing pass ends.
void _stdcall OnProcessingPassEnd(){};
// Called in the event of a critical system error which requires XAudio2
// to be closed down and restarted. The error code is given in Error.
void _stdcall OnCriticalError(HRESULT Error);
};
struct StreamingVoiceContext : public IXAudio2VoiceCallback
{
STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32){}
STDMETHOD_(void, OnVoiceProcessingPassEnd)(){}
STDMETHOD_(void, OnStreamEnd)(){}
STDMETHOD_(void, OnBufferStart)(void*)
{
ResetEvent(hBufferEndEvent);
}
STDMETHOD_(void, OnBufferEnd)(void* pContext)
{
//Trigger the event for the music stream.
if (pContext == 0) {
SetEvent(hBufferEndEvent);
}
}
STDMETHOD_(void, OnLoopEnd)(void*){}
STDMETHOD_(void, OnVoiceError)(void*, HRESULT){}
HANDLE hBufferEndEvent;
StreamingVoiceContext() : hBufferEndEvent(CreateEventEx(NULL, FALSE, FALSE, NULL))
{
}
virtual ~StreamingVoiceContext()
{
CloseHandle(hBufferEndEvent);
}
};
class Audio
{
private:
IXAudio2* m_musicEngine;
IXAudio2* m_soundEffectEngine;
IXAudio2MasteringVoice* m_musicMasteringVoice;
IXAudio2MasteringVoice* m_soundEffectMasteringVoice;
StreamingVoiceContext m_voiceContext;
typedef std::map<unsigned int, SoundEffectData> EffectList;
typedef std::pair<unsigned int, SoundEffectData> Effect;
EffectList m_soundEffects;
unsigned int m_backgroundID;
std::string m_backgroundFile;
bool m_backgroundLoop;
float m_soundEffctVolume;
float m_backgroundMusicVolume;
bool m_engineExperiencedCriticalError;
AudioEngineCallbacks m_musicEngineCallback;
AudioEngineCallbacks m_soundEffectEngineCallback;
unsigned int Hash(const char* key);
public:
Audio();
void Initialize();
void CreateResources();
void ReleaseResources();
void Start();
void Render();
// This flag can be used to tell when the audio system is experiencing critial errors.
// XAudio2 gives a critical error when the user unplugs their headphones, and a new
// speaker configuration is generated.
void SetEngineExperiencedCriticalError()
{
m_engineExperiencedCriticalError = true;
}
bool HasEngineExperiencedCriticalError()
{
return m_engineExperiencedCriticalError;
}
void PlayBackgroundMusic(const char* pszFilePath, bool bLoop);
void StopBackgroundMusic(bool bReleaseData);
void PauseBackgroundMusic();
void ResumeBackgroundMusic();
void RewindBackgroundMusic();
bool IsBackgroundMusicPlaying();
void SetBackgroundVolume(float volume);
float GetBackgroundVolume();
void SetSoundEffectVolume(float volume);
float GetSoundEffectVolume();
void PlaySoundEffect(const char* pszFilePath, bool bLoop, unsigned int& sound, bool isMusic = false);
void PlaySoundEffect(unsigned int sound);
bool IsSoundEffectStarted(unsigned int sound);
void StopSoundEffect(unsigned int sound);
void PauseSoundEffect(unsigned int sound);
void ResumeSoundEffect(unsigned int sound);
void RewindSoundEffect(unsigned int sound);
void PauseAllSoundEffects();
void ResumeAllSoundEffects();
void StopAllSoundEffects();
void PreloadSoundEffect(const char* pszFilePath, bool isMusic = false);
void UnloadSoundEffect(const char* pszFilePath);
void UnloadSoundEffect(unsigned int sound);
};

View File

@ -0,0 +1,216 @@
/*
* cocos2d-x http://www.cocos2d-x.org
*
* Copyright (c) 2010-2011 - cocos2d-x community
*
* Portions Copyright (c) Microsoft Open Technologies, Inc.
* All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
#include "MediaStreamer.h"
#include <wrl\wrappers\corewrappers.h>
#include <ppltasks.h>
using namespace Microsoft::WRL;
using namespace Windows::Storage;
using namespace Windows::Storage::FileProperties;
using namespace Windows::Storage::Streams;
using namespace Windows::Foundation;
using namespace Windows::ApplicationModel;
using namespace Concurrency;
#ifndef MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
((uint32)(byte)(ch0) | ((uint32)(byte)(ch1) << 8) | \
((uint32)(byte)(ch2) << 16) | ((uint32)(byte)(ch3) << 24 ))
#endif /* defined(MAKEFOURCC) */
inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
// Set a breakpoint on this line to catch DX API errors.
throw Platform::Exception::CreateException(hr);
}
}
MediaStreamer::MediaStreamer() :
m_offset(0)
{
ZeroMemory(&m_waveFormat, sizeof(m_waveFormat));
m_location = Package::Current->InstalledLocation;
m_locationPath = Platform::String::Concat(m_location->Path, "\\Assets\\Resources\\");
}
MediaStreamer::~MediaStreamer()
{
}
Platform::Array<byte>^ MediaStreamer::ReadData(
_In_ Platform::String^ filename
)
{
CREATEFILE2_EXTENDED_PARAMETERS extendedParams = {0};
extendedParams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
extendedParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
extendedParams.dwFileFlags = FILE_FLAG_SEQUENTIAL_SCAN;
extendedParams.dwSecurityQosFlags = SECURITY_ANONYMOUS;
extendedParams.lpSecurityAttributes = nullptr;
extendedParams.hTemplateFile = nullptr;
Wrappers::FileHandle file(
CreateFile2(
filename->Data(),
GENERIC_READ,
FILE_SHARE_READ,
OPEN_EXISTING,
&extendedParams
)
);
if (file.Get()==INVALID_HANDLE_VALUE)
{
throw ref new Platform::FailureException();
}
FILE_STANDARD_INFO fileInfo = {0};
if (!GetFileInformationByHandleEx(
file.Get(),
FileStandardInfo,
&fileInfo,
sizeof(fileInfo)
))
{
throw ref new Platform::FailureException();
}
if (fileInfo.EndOfFile.HighPart != 0)
{
throw ref new Platform::OutOfMemoryException();
}
Platform::Array<byte>^ fileData = ref new Platform::Array<byte>(fileInfo.EndOfFile.LowPart);
if (!ReadFile(
file.Get(),
fileData->Data,
fileData->Length,
nullptr,
nullptr
) )
{
throw ref new Platform::FailureException();
}
return fileData;
}
void MediaStreamer::Initialize(__in const WCHAR* url)
{
WCHAR filePath[MAX_PATH] = {0};
if ((wcslen(url) > 1 && url[1] == ':'))
{
// path start with "x:", is absolute path
wcscat_s(filePath, url);
}
else if (wcslen(url) > 0
&& (L'/' == url[0] || L'\\' == url[0]))
{
// path start with '/' or '\', is absolute path without driver name
wcscat_s(filePath, m_locationPath->Data());
// remove '/' or '\\'
wcscat_s(filePath, (const WCHAR*)url[1]);
}else
{
wcscat_s(filePath, m_locationPath->Data());
wcscat_s(filePath, url);
}
Platform::Array<byte>^ data = ReadData(ref new Platform::String(filePath));
UINT32 length = data->Length;
const byte * dataPtr = data->Data;
UINT32 offset = 0;
DWORD riffDataSize = 0;
auto ReadChunk = [&length, &offset, &dataPtr, &riffDataSize](DWORD fourcc, DWORD& outChunkSize, DWORD& outChunkPos) -> HRESULT
{
while (true)
{
if (offset + sizeof(DWORD) * 2 >= length)
{
return E_FAIL;
}
// Read two DWORDs.
DWORD chunkType = *reinterpret_cast<const DWORD *>(&dataPtr[offset]);
DWORD chunkSize = *reinterpret_cast<const DWORD *>(&dataPtr[offset + sizeof(DWORD)]);
offset += sizeof(DWORD) * 2;
if (chunkType == MAKEFOURCC('R', 'I', 'F', 'F'))
{
riffDataSize = chunkSize;
chunkSize = sizeof(DWORD);
outChunkSize = sizeof(DWORD);
outChunkPos = offset;
}
else
{
outChunkSize = chunkSize;
outChunkPos = offset;
}
offset += chunkSize;
if (chunkType == fourcc)
{
return S_OK;
}
}
};
// Locate riff chunk, check the file type.
DWORD chunkSize = 0;
DWORD chunkPos = 0;
ThrowIfFailed(ReadChunk(MAKEFOURCC('R', 'I', 'F', 'F'), chunkSize, chunkPos));
if (*reinterpret_cast<const DWORD *>(&dataPtr[chunkPos]) != MAKEFOURCC('W', 'A', 'V', 'E')) ThrowIfFailed(E_FAIL);
// Locate 'fmt ' chunk, copy to WAVEFORMATEXTENSIBLE.
ThrowIfFailed(ReadChunk(MAKEFOURCC('f', 'm', 't', ' '), chunkSize, chunkPos));
ThrowIfFailed((chunkSize <= sizeof(m_waveFormat)) ? S_OK : E_FAIL);
CopyMemory(&m_waveFormat, &dataPtr[chunkPos], chunkSize);
// Locate the 'data' chunk and copy its contents to a buffer.
ThrowIfFailed(ReadChunk(MAKEFOURCC('d', 'a', 't', 'a'), chunkSize, chunkPos));
m_data.resize(chunkSize);
CopyMemory(m_data.data(), &dataPtr[chunkPos], chunkSize);
m_offset = 0;
}
void MediaStreamer::ReadAll(uint8* buffer, uint32 maxBufferSize, uint32* bufferLength)
{
UINT32 toCopy = m_data.size() - m_offset;
if (toCopy > maxBufferSize) toCopy = maxBufferSize;
CopyMemory(buffer, m_data.data(), toCopy);
*bufferLength = toCopy;
m_offset += toCopy;
if (m_offset > m_data.size()) m_offset = m_data.size();
}
void MediaStreamer::Restart()
{
m_offset = 0;
}

View File

@ -0,0 +1,58 @@
/*
* cocos2d-x http://www.cocos2d-x.org
*
* Copyright (c) 2010-2011 - cocos2d-x community
*
* Portions Copyright (c) Microsoft Open Technologies, Inc.
* All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
#pragma once
#include <vector>
#include <xaudio2.h>
ref class MediaStreamer
{
private:
WAVEFORMATEX m_waveFormat;
uint32 m_maxStreamLengthInBytes;
std::vector<byte> m_data;
UINT32 m_offset;
Platform::Array<byte>^ ReadData(
_In_ Platform::String^ filename
);
internal:
Windows::Storage::StorageFolder^ m_location;
Platform::String^ m_locationPath;
public:
virtual ~MediaStreamer();
internal:
MediaStreamer();
WAVEFORMATEX& GetOutputWaveFormatEx()
{
return m_waveFormat;
}
UINT32 GetMaxStreamLengthInBytes()
{
return m_data.size();
}
void Initialize(_In_ const WCHAR* url);
void ReadAll(uint8* buffer, uint32 maxBufferSize, uint32* bufferLength);
void Restart();
};

View File

@ -0,0 +1,198 @@
/*
* cocos2d-x http://www.cocos2d-x.org
*
* Copyright (c) 2010-2011 - cocos2d-x community
*
* Portions Copyright (c) Microsoft Open Technologies, Inc.
* All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
#include "SimpleAudioEngine.h"
#include "Audio.h"
#include <map>
//#include "CCCommon.h"
using namespace std;
namespace CocosDenshion {
Audio* s_audioController = NULL;
bool s_initialized = false;
SimpleAudioEngine* SimpleAudioEngine::getInstance()
{
static SimpleAudioEngine s_SharedEngine;
return &s_SharedEngine;
}
static Audio* sharedAudioController()
{
if (! s_audioController || !s_initialized)
{
if(s_audioController == NULL)
{
s_audioController = new Audio;
}
s_audioController->Initialize();
s_audioController->CreateResources();
s_initialized = true;
}
return s_audioController;
}
SimpleAudioEngine::SimpleAudioEngine()
{
}
SimpleAudioEngine::~SimpleAudioEngine()
{
}
void SimpleAudioEngine::end()
{
sharedAudioController()->StopBackgroundMusic(true);
sharedAudioController()->StopAllSoundEffects();
sharedAudioController()->ReleaseResources();
s_initialized = false;
}
//////////////////////////////////////////////////////////////////////////
// BackgroundMusic
//////////////////////////////////////////////////////////////////////////
void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop)
{
if (! pszFilePath)
{
return;
}
sharedAudioController()->PlayBackgroundMusic(pszFilePath, bLoop);
}
void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData)
{
sharedAudioController()->StopBackgroundMusic(bReleaseData);
}
void SimpleAudioEngine::pauseBackgroundMusic()
{
sharedAudioController()->PauseBackgroundMusic();
}
void SimpleAudioEngine::resumeBackgroundMusic()
{
sharedAudioController()->ResumeBackgroundMusic();
}
void SimpleAudioEngine::rewindBackgroundMusic()
{
sharedAudioController()->RewindBackgroundMusic();
}
bool SimpleAudioEngine::willPlayBackgroundMusic()
{
return false;
}
bool SimpleAudioEngine::isBackgroundMusicPlaying()
{
return sharedAudioController()->IsBackgroundMusicPlaying();
}
//////////////////////////////////////////////////////////////////////////
// effect function
//////////////////////////////////////////////////////////////////////////
unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop,float pitch, float pan, float gain)
{
unsigned int sound;
sharedAudioController()->PlaySoundEffect(pszFilePath, bLoop, sound);
// TODO: need to support playEffect parameters
return sound;
}
void SimpleAudioEngine::stopEffect(unsigned int nSoundId)
{
sharedAudioController()->StopSoundEffect(nSoundId);
}
void SimpleAudioEngine::preloadEffect(const char* pszFilePath)
{
sharedAudioController()->PreloadSoundEffect(pszFilePath);
}
void SimpleAudioEngine::pauseEffect(unsigned int nSoundId)
{
sharedAudioController()->PauseSoundEffect(nSoundId);
}
void SimpleAudioEngine::resumeEffect(unsigned int nSoundId)
{
sharedAudioController()->ResumeSoundEffect(nSoundId);
}
void SimpleAudioEngine::pauseAllEffects()
{
sharedAudioController()->PauseAllSoundEffects();
}
void SimpleAudioEngine::resumeAllEffects()
{
sharedAudioController()->ResumeAllSoundEffects();
}
void SimpleAudioEngine::stopAllEffects()
{
sharedAudioController()->StopAllSoundEffects();
}
void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath)
{
UNUSED_PARAM(pszFilePath);
}
void SimpleAudioEngine::unloadEffect(const char* pszFilePath)
{
sharedAudioController()->UnloadSoundEffect(pszFilePath);
}
//////////////////////////////////////////////////////////////////////////
// volume interface
//////////////////////////////////////////////////////////////////////////
float SimpleAudioEngine::getBackgroundMusicVolume()
{
return sharedAudioController()->GetBackgroundVolume();
}
void SimpleAudioEngine::setBackgroundMusicVolume(float volume)
{
sharedAudioController()->SetBackgroundVolume((volume<=0.0f)? 0.0f : volume);
}
float SimpleAudioEngine::getEffectsVolume()
{
return sharedAudioController()->GetSoundEffectVolume();
}
void SimpleAudioEngine::setEffectsVolume(float volume)
{
sharedAudioController()->SetSoundEffectVolume((volume<=0.0f)? 0.0f : volume);
}
} // end of namespace CocosDenshion