カテゴリー別アーカイブ: C++/CX

MWCでWindowsPhone日本発売の光明が増えました

Mobile World Congress(MWC) 2015でfreetelと京セラの端末が公開

マウスコンピュータに続いて国内メーカーから発表がありました。

freetelブランドの端末はMWC前にプレスリリースが行われました。
最新 Windows Phone OS 搭載スマートフォン、 2015 年夏までに国内発売予定のお知らせ
なんと夏までに出すという表明です。
freetelは日本向けのSIMフリー端末販売会社なので、日本向け端末が確定したことになります。

京セラはプロトタイプとして高耐久端末にWindowsPhone8.1を搭載したようです。
engadgetさんのレポート記事がありました。
京セラがWindows Phone 8.1スマホをMWC出展。『Windows Phoneは高耐久と親和性が高い』
元々のAndroid端末にWP8.1を搭載しましたという段階のようで、端末のボタンがAndroidのままですね

AcerからWindows10 for Phones対応確約端末が発表(日本発売未定)

PC watchさんにAcer社がWP8.1端末が出すとの記事が出ました。
Acer、79ユーロでWindows 10へのアップグレードを保証したスマホ
端末としては欧州向けローエンドですが、Acer社は日本向けにAndroid端末をブックオフ経由で発売していることを考えると、もしかして選択肢が増えるということかなと思いたいところです。

Microsoftからは新端末(日本発売未定)

MWCではMicrosoftからLumia640/640XLが発表されました。
端末としてはミドルレンジの端末になるようです。
追加の特徴としては「Office 365サブスクリプション1年分」と「OneDrive 1GB 1年分」が標準でサポートされ散ることでしょうか。

開発者に向けて

それぞれの端末はWindowsPhone8.1ではありますが、Windows 10 for Phonesが視野に入っているようで、時期が来ればOS更新が降ってくることになると思います。
Windows 10 からはさらにデスク/ノートOSとモバイルOSの融合が進みます。
A社やG社のOSに比べても使用率の大きなWindowsというデスク/ノート向けOSと連携するには非常に心強い環境が整ってきます。

もちろんデスク/ノート向けがそのまま動くということはないですが、いわゆるWindowsストアアプリであれば、ユニバーサルアプリとして、モバイルにもゲームコンソールにも展開可能になり強い連携を生み出すことができる基盤が、クラウド(Azure)も含んでOneSolution/OneStoaが実現してきます。

VisualStudioによるストアアプリ、マルチデバイス開発はC/C++/C#/HTML5(JavaScript)/F#等で可能になってきていますし、UnityやUnreal Engineなどによるマルチデバイス開発もできます。

開発の親和性も非常に高い環境ですので、ぜひ開発者の皆さんには飛び込んできてほしいと思います。

マルチデバイス開発選択肢としてのMicrosoft Visual Studio

マルチデバイス開発環境の選択肢

自身の開発環境上、Windowsベースとなりますが、現在いくつかの、マルチデバイス開発環境があります。

ゲームに向いているもの

細かいのを入れるともう少しありますが、Windowsで有名どころとなるとこんなところでしょうか?

開発環境としてVisualStudioを選択すべきか?

私はアプリの開発環境ということでVisualStudioを選択してるわけですが、Windows環境がメインであるというのが大きな理由ではあります。
では、ほかの方に開発環境としてVisualStudioを薦めるのか?ということになります。

標準で対応している使用可能な言語も多くあります。

  • C/C++
  • C#
  • Visual Basic
  • Visual F#
  • JScript
  • Python
  • HTML5
  • JavaScript
  • TypeScript

基本的には非常に強力なVisualStudioという開発環境もあり、Windowsという世界で広く流通、使用されているOSであるということを考えれば、薦めることに何の問題もないと思います。

なぜ基本的なのかですが、iOS/OSX専用アプリのみ開発するというのであれば、Mac環境を選択するしかないわけですので、VisualStudioを薦めるというのは難しく、Linuxなどの環境についても同じく、専用アプリだけということであれば、VisualStudioを勧めることはできないです。

ですが、Windows/WindowsPhone/iOS/Android/Web/クラウド/IoTと多岐の環境へのアプリリリースが求められる状況が増えています。

MacやLinuxでもかなりのマルチデバイス対応開発は行えますが、現在どれかしらへの開発が行えないという状況が多くあります。

もちろんVisualStudioでも単独では開発できないiOSアプリ、Macアプリ等があります。
現在VisualStudioでiOSを開発するにはどうしてもMacが別途必要で、XCodeコンパイラを経由する必要があります。
単独で開発できないだけでVisualStudioを使用した開発が可能な物は多いです。

MacにはBoot CampというWindowsをインストール可能にする公式ツールがあります。
ネイティブなWindowsをMacにインストールし、VisualStudioを使用するというのが可能です。

Boot Camp

Visual Studioに関して

さて、VisualStudioですが、MicrosoftイベントConnect();において VisualStudio Community Edition(以下 VSCE)が発表され、今までのExpress Edition(VSEE)は今後廃止されることになりました。(VSEE2015は出ないそうです)

VisualStudio Community Edition 日本語ページ

VSCEはVSEEと同じく無償で使用可能なVisualStudioですが、大きな違いがあります。
VSEEは非常に制限が大きく、各種拡張機能が使用できない、使用用途ごとにエディション(desktop、Web等)が存在するというものでしたが、VSCEはProfessional Editionに準拠した1エディションになり、今まで使用できなかったVS tools for Unity等の拡張機能が使用できるようになります。

使用条件は、個人開発者が無償または有償のアプリの開発に使用可能、オープンソースコミュニティへの貢献開発もOK、企業の場合でも条件によっては使用可能、ただし受託開発に使用するのには制限有となっているようです。
詳しくはMicrosoftのライセンス ホワイトペーパーを確認の上でお願いします。

Microsoft Visual Studioによるマルチデバイス開発ですが、標準ではWindowsデスクトップアプリ(ネイティブ、WPF、DirectX)、ASP.NET(WEB)、Azure(クラウド)、Windowsストアアプリ、WindowsPhoneアプリ、Kinect等、各種Windowsプラットフォームアプリの開発が可能です。

これ以外の場合、Xamarin(BusinessLicense以上)、Cordova(Visual Studio Tools for Apache Cordova)、Unity(Visual Studio 2013 Tools for Unity)をインストールすることで、Android、iOS向けの開発がVisual Studio上でも可能になります。

さらに.NET MicroFramework(以下 NETMF)をインストールすることで.NET Gadgeteerの開発(.NET Gadgeteer SDKと実機が必要)が可能になり、組み込み開発が比較的手軽に行えます。

.NET MicroFramework
.NET Gadgeteer 日本代理店

Windows Embedded環境向けの開発もSDKを導入することで可能ですが、EmbeddedはOSの入手がMSDNユーザー以外では開発会社くらいでしょうから、少々厳しいかもしれません。
もっともWindows Embedded 8.1 HandheldはWindowsPhone8.1用アプリが使用可能になっていますので、WindowsPhone8.1アプリ開発が、Embedded向けアプリの開発ともいえるかもしれません。

XamarinはC#.NET、CordovaはHTML5+JavaScript(TypeScript)ですので、慣れた開発言語を選択するというのも手です。

また、これらを使わなくても実は可能な方法が存在はしています。

最近Microsoft Officeがマルチデバイス対応しています。(Office 365の契約が必要な機能もあります)
AndroidでもiPadでも限定的ではあるものの編集可能なOfficeが提供されています。

さて、MS OfficeはどうやっているのかというのがMSの講演などで判明しており、内部的にはコアをC++で再利用な形で作り、OSごとに薄いレイヤを作って、UI/UXを載せるという形になっているそうです。

マイクロソフトは、C++でいかにしてMicrosoft Officeのクラスプラットフォームを実現したのか 

銀の弾丸はない。唯一のアプローチは、コストとリスクとベネフィットのトレードオフを考えることだ。

・ 良く定義された組み立て可能なコンポーネント
・ 可能なかぎりメカニカルなリファクタリングを行う
・ つねにすべてのプラットフォームで(開発中のコードが)動くようにした
・ 毎日全てのプラットフォームで大規模なドッグフーディング

XamarinはAndroid、iOS、Formsという形式がVS上で開発可能です。
Android、iOSは名前の通りそれぞれ単独用です。(MVVM Crossを使うなどで共通化は可能)
FormsはXAMLベースのコントロールが使用可能でAndroid、iOS、WinodwsPhone8.0の開発が共通化されています。

CordovaはAdobe社が構築したもので元の名前が「PhoneGap」という名称です。
そのためCrdovaで情報を探すよりはPhoneGapで探したほうが情報が見つかりやすいと思います。

連載:初めての PhoneGap 第1回 - ハイブリッドアプリのメリット・デメリット

Unityはゲームアプリまたはリッチな表現を多くしたいアプリに向いています。
Visual Studio Tools for Unityを導入することで、Visual Studio上でコード記述、デバッグ作業が行えます。

Visual Studioを、できればMSDNライセンス付きで使用してぜひ快適な開発環境の構築を行いましょう。

WindowsPhone8/8.1 Game Pad/Controller

WindowsPhone8/8.1(以降WP8/8.1)にはGame Pad/Controllerが有りませんでした。
これはモバイル向けGame Pad/Controllerとの接続で良く使用されるBluetoothですが、WP8/8.1にはBluetoothは搭載されているものの、対応profileとして「HID」が無いため外部入力機器が使用できませんでした。

ところが、最近検索していて見つけたのですが、Bensussen Deutsch & Associates, Inc(以下 BDA)社の「MOGA Game On Anywhere(以下 MOGA)」シリーズの一部が対応しているとの記事を見つけました。

MOGAにはiPhone用とAndroid用のゲームコントローラーがあるのですが、Android用でWP8/8.1に使用できる機能が付き、WP8用SDK(WinPRT)が公開されています。

MOGA Pro SDK – WindowsPhone8

自分は下記のコントローラーを購入して、SDKにあったサンプルでコントローラーが動作することを確認しました。


此方はUSB充電伝可能なリチウム電池内蔵型です。


価格は安いものの、単三電池二本が必要になる、リチウム電池やUSBコネクタはありません。

というわけで、WP8(WinPRT)用とはなっているものの、WP8.1WinRTベースで使用できるようにできないかと、色々試してみました。

続きを読む

WindowsPhone8でSQLiteを使用するためのメモ

・「拡張機能と更新プログラム」から、もしくは「Precompiled Binaries for Windows Phone 8」からDL&インストールして「SQLite for Windows Phone」を参照する
SQLite for Windows Phone

・「NuGetパッケージ管理」から「sqlite-net」をインストールする
 「SQLite.cs」と「SQLiteAsync.cs」が追加されます
sqlite-net

・「sqlite-net-wp8」を「GitHub」からDLしてソリューションにプロジェクトを参加させる
・参加させたプロジェクトを参照する

・NuGetから「sqlite-net-wp8」を追加する ※2014/02/24 変更/追記
・「SQLite for Windows Phone」を参照しているプロジェクトの「ビルドの条件付きコンパイルシンボル」に「USE_WP8_NATIVE_SQLITE」を追加する
・「SQLite for Windows Phone」「sqlite-net-wp8」共にネイティブコードなので、コンパイルの「構成マネージャー」のプラットフォームを「x86/Win32」または「ARM」に統一する必要があります。

これでラッパーが導入されるため使用しやすくなるはずです。

作成されているDBファイルを確認したい場合「Windows Phone Power Tools」を使用して、内部ファイルにアクセスします。

※現在導入テスト中のためここまで

C++/CXからC#を参照する

メインにDirectXを使用するアプリなどでC++/CXだけでは開発効率などがよくなかったり、XAMLの部分はC#で扱いたいというときがあると思います。
その際はプロジェクトの追加でC#をWindowsRuntimeComponentとして追加して参照します。

C++/CXでの参照はC++/CXプロジェクトを右クリックして「参照」を選択
0000
上記のような参照画面が出てくるので、「新しい参照の追加」でC#プロジェクトを参照してください。
クラスなどはC++/CX内で「using」することで呼び出せます。

screenshot_09272013_102206
このようにXAML部分(画面下部)はC#のユーザーコントロールにすることが出来ています。

背景はDirextXで表示しているため「SwapChainBackgroundPanel」を宣言することでXAMLとの共存を図っています。

Xaudio2をC++/CXでevent通知

Xaudio2をC++/CXで作成のところに少々追加です。
現在の状態だと音の終了などが外部からはわからない状態です。
これを防ぐために下記のような形にします。


// イベントのデリゲート
public delegate void SoundEndedHandler(int index);

public ref class xaudiolib sealed
{
   public:
      // 追加
      event SoundEndedHandler^ OnSoundEndedHandler;
      void RaiseEndEvent(int soundIndex);
}

void xaudiolib::RaiseEndEvent(int soundIndex)
{
      OnSoundEndedHandler(soundIndex);
}

class AudioFilePlayerCallBack : public IXAudio2VoiceCallback
{
    public:
      AudioFilePlayerCallBack(xaudiolib^ parent, Microsoft::WRL::ComPtr<IXAudio2> pXAudio2, Platform::String^ filename ,int soundIndex);

   private:
	xaudiolib^ parentRef;
}

CallBackの中で「parentRef->RaiseEndEvent(index);」をコールする形でイベントを呼び出せます。
直接は呼べないので、関数を経由する形で実装すれば呼び出せます。

Xaudio2をC++/CXで作成

Windowsストアアプリで音を鳴らす場合、MediaElementが一般的ですが、画面の遷移がある場合などには少々向きません。
鳴らしたままなどであればやり方もあるんですが、デメリットとして、ボリューム変更などができなくなります。
SharpDXを使用すればC#でもXAudio2を使用可能ですが、今回のはC++/CXで作成したものです。
マイクロソフトのサンプルなどを参考にとりあえずのレベルですが、作成しました。
C#からもWindowsランタイムコンポーネントとして引き込むことで使用できます。

※各種サンプルを公開されている方々とマイクロソフトに感謝を

読み込んでいるヘッダーです

// Microsoft WRL(Windows ランタイム C++ テンプレート ライブラリ) 用ヘッダー
#include <wrl.h>
// XAudio2用ヘッダー
#include <xaudio2.h>
#include <xaudio2fx.h>
// マルチメディア用ヘッダー
#include <mmreg.h>
// media fusion 用ヘッダー
#include <Mfidl.h>
#include <Mfapi.h>
#include <Mfreadwrite.h>
/* 上記に必要なライブラリ
xaudio2.lib
mfcore.lib
mfplat.lib
mfreadwrite.lib
mfuuid.lib
*/
#include "pch.h"
#include "xaudiolib.h"

using namespace Microsoft::WRL;
using namespace Platform;

namespace xaudio2lib
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// サウンドデータ
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	// BGM管理構造体
	struct xaudiolib::ImplSoundData
	{
		ImplSoundData::ImplSoundData(Platform::String^ filename,xaudiolib^ parent,int index) :
			sourceVoice(nullptr),
			//playData(data),
			isPlaying(false),
			isLoop(false),
			audioFilePlayerCallBack(parent->m_musicEngine, filename, index)
		{
			sourceVoice = audioFilePlayerCallBack.GetSourceVoice();

		}

		~ImplSoundData()
		{
			if (sourceVoice)
			{
				sourceVoice->DestroyVoice();
				sourceVoice = nullptr;
			}
		}

		IXAudio2SourceVoice*    sourceVoice;
		bool                    isPlaying;
		bool					isLoop;
		AudioFilePlayerCallBack			audioFilePlayerCallBack;
	};

	struct xaudiolib::ImplSeData
	{
		ImplSeData::ImplSeData(Platform::String^ filename,xaudiolib^ parent,int index) :
			sourceVoice(nullptr),
			//playData(data),
			isPlaying(false),
			isLoop(false),
			audioFilePlayerCallBack(parent->m_seEngine, filename, index)
		{
			sourceVoice = audioFilePlayerCallBack.GetSourceVoice();
		}

		~ImplSeData()
		{
			if (sourceVoice)
			{
				sourceVoice->DestroyVoice();
				sourceVoice = nullptr;
			}
		}

		IXAudio2SourceVoice*    sourceVoice;
		bool                    isPlaying;
		bool					isLoop;
		AudioFilePlayerCallBack			audioFilePlayerCallBack;
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	xaudiolib::xaudiolib(void):m_soudBgmDataList(),m_soudSeDataList()
	{
		XAudio2Initialize();
	}


	xaudiolib::~xaudiolib(void)
	{
		seList.clear();
		bgmList.clear();

		XAudio2Clear();
	}

	void xaudiolib::AddBgmFileName(Platform::String^ _fileName)
	{
		bgmList.push_back(_fileName);
	}

	void xaudiolib::AddSeFileName(Platform::String^ _fileName)
	{
		seList.push_back(_fileName);
	}

	void xaudiolib::Initialize()
	{
	}

	void xaudiolib::XAudio2Initialize()
	{
		m_musicMasteringVoice = nullptr;
		m_audioAvailable = false;

		UINT32 flags = 0;

		// BGM用XAudio2ポインタ作成
		DX::ThrowIfFailed(
			XAudio2Create(&m_musicEngine, flags)
			);

		// BGM用ミキサーの作成
		HRESULT hr = m_musicEngine->CreateMasteringVoice(&m_musicMasteringVoice);
		if (FAILED(hr))
		{
			m_audioAvailable = false;
			return;
		}

		// SE用XAudio2ポインタ作成
		DX::ThrowIfFailed(
			XAudio2Create(&m_seEngine, flags)
			);

		// SE用ミキサーの作成
		hr = m_seEngine->CreateMasteringVoice(&m_seMasteringVoice);
		if (FAILED(hr))
		{
			m_audioAvailable = false;
			return;
		}

		m_audioAvailable = true;
	}

	void xaudiolib::XAudio2Clear()
	{
		if(m_audioAvailable)
		{
		for (size_t index = 0; index < bgmList.size(); ++index)
		{
			m_soudBgmDataList[index]->audioFilePlayerCallBack.AudioFilePlayerEnd(index);
		}

		for (size_t index = 0; index < seList.size(); ++index)
		{
			m_soudSeDataList[index]->audioFilePlayerCallBack.AudioFilePlayerEnd(index);
		}

		// マスターVoiceの解放
			m_musicMasteringVoice->DestroyVoice();
			m_musicMasteringVoice = nullptr;

			m_seMasteringVoice->DestroyVoice();
			m_seMasteringVoice = nullptr;

			// m_musicEngine/m_seEngineは「Microsoft::WRL::ComPtr」で自動的に開放

			m_audioAvailable = false;
		}
	}

	// サウンドデータを読み込む
	void xaudiolib::XAudio2Load()
	{
		for (size_t index = 0; index < bgmList.size(); ++index)
		{
			AddBgmSound(bgmList[index], index);
		}

		for (size_t index = 0; index < seList.size(); ++index)
		{
			AddSeSound(seList[index], index);
		}
	}

	// BGMデータを登録する
	size_t xaudiolib::AddBgmSound(_In_ Platform::String^ soundFileName, _In_ int index)
	{
		std::shared_ptr<ImplSoundData> implSoundData(new ImplSoundData(soundFileName,this,index));

		m_soudBgmDataList.push_back(implSoundData);
		return (m_soudBgmDataList.size() - 1);
	}

	// SEデータを登録する
	size_t xaudiolib::AddSeSound(_In_ Platform::String^ seFileName, _In_ int index)
	{
		std::shared_ptr<ImplSeData> implSeData(new ImplSeData(seFileName,this,index));

		m_soudSeDataList.push_back(implSeData);
		return (m_soudSeDataList.size() - 1);
	}


	bool xaudiolib::IsBgmPlay(int bgmIndex, bool bLoop)
	{

		if(!m_audioAvailable)
		{
			return false;
		}

		m_soudBgmDataList[bgmIndex]->audioFilePlayerCallBack.IsPlay(bLoop, bgmIndex);

		return true;
	}

	bool xaudiolib::IsBgmStop(int bgmIndex)
	{

		if(!m_audioAvailable)
		{
			return false;
		}

		m_soudBgmDataList[bgmIndex]->audioFilePlayerCallBack.IsStop();

		return true;
	}

	bool xaudiolib::IsSePlay(int seIndex)
	{

		if(!m_audioAvailable)
		{
			return false;
		}

		m_soudSeDataList[seIndex]->audioFilePlayerCallBack.IsPlay(false, seIndex);

		return true;
	}

	bool xaudiolib::IsSeStop(int seIndex)
	{

		if(!m_audioAvailable)
		{
			return false;
		}

		m_soudSeDataList[seIndex]->audioFilePlayerCallBack.IsStop();

		return true;
	}

	bool xaudiolib::IsBgmPlaying(int bgmIndex)
	{
		if(!m_audioAvailable)
		{
			return false;
		}

		return m_soudBgmDataList[bgmIndex]->audioFilePlayerCallBack.bPlaying;
	}

	bool xaudiolib::IsSePlaying(int bgmIndex)
	{
		if(!m_audioAvailable)
		{
			return false;
		}

		return m_soudSeDataList[bgmIndex]->audioFilePlayerCallBack.bPlaying;
	}

	bool xaudiolib::SuspendBgm()
	{
		if(!m_audioAvailable)
		{
			return false;
		}

		this->m_musicEngine->StopEngine();

		return true;
	}

	bool xaudiolib::ResumeBgm()
	{
		if(!m_audioAvailable)
		{
			return false;
		}

		this->m_musicEngine->StartEngine();

		return true;
	}

	bool xaudiolib::SetBgmVolume(int bgmIndex, float volume)
	{
		if(!m_audioAvailable || m_soudBgmDataList[bgmIndex] == nullptr)
		{
			return false;
		}

		m_soudBgmDataList[bgmIndex]->sourceVoice->SetVolume(volume);

		return true;
	}
	
	bool xaudiolib::GetBgmVolume(int bgmIndex, float *volume)
	{
		if(!m_audioAvailable || m_soudBgmDataList[bgmIndex] == nullptr)
		{
			return false;
		}

		m_soudBgmDataList[bgmIndex]->sourceVoice->GetVolume(volume);

		return true;
	}

	bool xaudiolib::SetSeVolume(int seIndex, float volume)
	{
		if(!m_audioAvailable)
		{
			return false;
		}

	}
	
	bool xaudiolib::GetSeVolume(int seIndex, float* volume)
	{
		if(!m_audioAvailable)
		{
			return false;
		}

	}


	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


	AudioFilePlayerCallBack::AudioFilePlayerCallBack(Microsoft::WRL::ComPtr<IXAudio2> pXAudio2, Platform::String^ filename ,int soundIndex)
	{

		this->mfSourceReader = this->mediaReader.LoadMedia(filename);

		this->iSoundIndex = soundIndex;

		// Get the Media Foundation media type
		ComPtr<IMFMediaType> mfMediaType;
		HRESULT hresult = mfSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &mfMediaType);

		if (FAILED(hresult))
			throw ref new COMException(hresult, "MFSourceReader->GetCurrentMediaType 取得に失敗");

		// Create a WAVEFORMATEX from the media type
		WAVEFORMATEX* pWaveFormat;
		unsigned int waveFormatLength;
		hresult = MFCreateWaveFormatExFromMFMediaType(mfMediaType.Get(), &pWaveFormat, &waveFormatLength);

		if (FAILED(hresult))
			throw ref new COMException(hresult, "MFCreateWaveFormatExFromMFMediaType 取得に失敗");

		// SoourceVoiceを作成
		hresult = pXAudio2->CreateSourceVoice(
			&pSourceVoice,
			pWaveFormat,
			XAUDIO2_VOICE_NOPITCH,
			1.0f,
			this);

		// WaveFomatを開放
		CoTaskMemFree(pWaveFormat);

		bPlaying = false;

	}

	void AudioFilePlayerCallBack::AudioFilePlayerEnd(int bgmIndex)
	{
		if(pSourceVoice!=nullptr)
		{
			this->IsStop();

			pSourceVoice->DestroyVoice();

			HRESULT hresult = MFShutdown();

			if (FAILED(hresult))
				throw ref new COMException(hresult, "MFShutdown failure");
		}
	}

	void AudioFilePlayerCallBack::SubmitBuffer()
	{
		// Get the next block of audio data
		int audioBufferLength;
		byte * pAudioBuffer = GetNextBlock(&audioBufferLength);

		if (pAudioBuffer != nullptr)
		{
			// Create an XAUDIO2_BUFFER for submitting audio data
			XAUDIO2_BUFFER buffer = {0};
			buffer.Flags = XAUDIO2_END_OF_STREAM;
			buffer.AudioBytes = audioBufferLength;
			buffer.pAudioData = pAudioBuffer;
			buffer.pContext = pAudioBuffer;
			HRESULT hresult = pSourceVoice->SubmitSourceBuffer(&buffer);

			if (FAILED(hresult))
				throw ref new COMException(hresult, "IXAudio2SourceVoice->SubmitSourceBuffer failure");
		}
	}

	void AudioFilePlayerCallBack::IsPlay(bool bLoop,int iSoundIndex)
	{
		this->bLoop = bLoop;
		this->soundIndex = iSoundIndex;

		// 停止処理
		this->IsStop();

		// 再生バッファ
		SubmitBuffer();
		SubmitBuffer();

		endOfFile = false;

		// 再生開始
		pSourceVoice->Start(0);

		bPlaying = true;
	}

	void AudioFilePlayerCallBack::IsStop()
	{
		bPlaying = false;

		pSourceVoice->Stop(0);
		pSourceVoice->FlushSourceBuffers();

		// 再生ポインタを先頭に
		this->ReStart();

	}

	void AudioFilePlayerCallBack::ReStart()
	{
		if (mfSourceReader == nullptr)
		{
			return;
		}

		PROPVARIANT var = {0};
		var.vt = VT_I8;

		DX::ThrowIfFailed(
			mfSourceReader->SetCurrentPosition(GUID_NULL, var)
			);
	}

	IXAudio2SourceVoice* AudioFilePlayerCallBack::GetSourceVoice()
	{
		return this->pSourceVoice;
	}

	byte * AudioFilePlayerCallBack::GetNextBlock(int * pAudioBufferLength)
	{
		// IMFSampleを取得
		ComPtr<IMFSample> mfSample;
		DWORD flags = 0;
		HRESULT hresult = mfSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 
			0, nullptr, &flags, nullptr, &mfSample);
		if (FAILED(hresult))
			throw ref new COMException(hresult, "MFSourceReader->ReadSample failure");

		// ファイルの終わりを確認する
		if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
		{
			endOfFile = true;
			*pAudioBufferLength = 0;
			return nullptr;
		}

		// データをバッファへ
		ComPtr<IMFMediaBuffer> mfMediaBuffer;
		hresult = mfSample->ConvertToContiguousBuffer(&mfMediaBuffer);

		if (FAILED(hresult))
			throw ref new COMException(hresult, "IMFSample->ConvertToContiguousBuffer failure");

		// バッファが勝手に開放されないようにロックしておく
		uint8 * pAudioData = nullptr;
		DWORD audioDataLength = 0;
		hresult = mfMediaBuffer->Lock(&pAudioData, nullptr, &audioDataLength); 

		if (FAILED(hresult))
			throw ref new COMException(hresult, "IMFMediaBuffer->Lock failure");

		byte * pAudioBuffer = new byte[audioDataLength];
		CopyMemory(pAudioBuffer, pAudioData, audioDataLength);
		hresult = mfMediaBuffer->Unlock();

		if (FAILED(hresult))
			throw ref new COMException(hresult, "IMFMediaBuffer->Unlock failure");

		*pAudioBufferLength = audioDataLength;
		return pAudioBuffer;
	}

	// IXAudio2VoiceCallback バッファの終わりに呼び出される
	void _stdcall AudioFilePlayerCallBack::OnBufferEnd(void* pContext)
	{
		// Remember to free the audio buffer!
		delete[] pContext;

		// Either submit a new buffer or clean up
		if(bPlaying)
		{
			if (!endOfFile)
			{
				SubmitBuffer();
			}
			else
			{
				if(!bLoop)
				{
					this->IsStop();
				}
				else
				{
					this->ReStart();

					SubmitBuffer();
					SubmitBuffer();

					endOfFile = false;
				}
			}
		}
	}
};

まだ作り掛&未整理のため読みにくいですがご了承ください。
ファイルの読み込みにはマイクロソフトのサンプルに有った「MediaReader」に少々手を入れて使用しています。
「MediaReader」は転載禁止のため掲載できないため、MSのサンプルをご確認ください。