浏览代码

Started on an XAudio2 audio interface for UWP

Ivan Safrin 10 年之前
父节点
当前提交
319e20d70f

+ 3 - 0
build/windows/universal/PolycodeCore/PolycodeCore.vcxproj

@@ -103,6 +103,7 @@
     <ClInclude Include="..\..\..\..\include\polycode\core\PolyVector2.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\PolyVector2.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\PolyVector3.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\PolyVector3.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\PolyVector4.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\PolyVector4.h" />
+    <ClInclude Include="..\..\..\..\include\polycode\core\PolyXAudio2AudioInterface.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\rgbe.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\rgbe.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\stb_image.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\stb_image.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\tinystr.h" />
     <ClInclude Include="..\..\..\..\include\polycode\core\tinystr.h" />
@@ -110,6 +111,7 @@
     <ClInclude Include="resource.h" />
     <ClInclude Include="resource.h" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\..\..\src\core\lodepng.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyBasicFileProvider.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyBasicFileProvider.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyBezierCurve.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyBezierCurve.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyBone.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyBone.cpp" />
@@ -181,6 +183,7 @@
     <ClCompile Include="..\..\..\..\src\core\PolyVector2.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyVector2.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyVector3.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyVector3.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyVector4.cpp" />
     <ClCompile Include="..\..\..\..\src\core\PolyVector4.cpp" />
+    <ClCompile Include="..\..\..\..\src\core\PolyXAudio2AudioInterface.cpp" />
     <ClCompile Include="..\..\..\..\src\core\rgbe.cpp" />
     <ClCompile Include="..\..\..\..\src\core\rgbe.cpp" />
     <ClCompile Include="..\..\..\..\src\core\tinystr.cpp" />
     <ClCompile Include="..\..\..\..\src\core\tinystr.cpp" />
     <ClCompile Include="..\..\..\..\src\core\tinyxml.cpp" />
     <ClCompile Include="..\..\..\..\src\core\tinyxml.cpp" />

+ 9 - 0
build/windows/universal/PolycodeCore/PolycodeCore.vcxproj.filters

@@ -252,6 +252,9 @@
     <ClInclude Include="resource.h">
     <ClInclude Include="resource.h">
       <Filter>Source</Filter>
       <Filter>Source</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\..\..\..\include\polycode\core\PolyXAudio2AudioInterface.h">
+      <Filter>Include</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\..\..\src\core\PolyBasicFileProvider.cpp">
     <ClCompile Include="..\..\..\..\src\core\PolyBasicFileProvider.cpp">
@@ -482,5 +485,11 @@
     <ClCompile Include="..\..\..\..\src\core\PolyOpenGLGraphicsInterface.cpp">
     <ClCompile Include="..\..\..\..\src\core\PolyOpenGLGraphicsInterface.cpp">
       <Filter>Source</Filter>
       <Filter>Source</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\..\..\..\src\core\lodepng.cpp">
+      <Filter>Source</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\..\src\core\PolyXAudio2AudioInterface.cpp">
+      <Filter>Source</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 2 - 7
build/windows/universal/TemplateApp/PolycodeTemplateApp.cpp

@@ -26,13 +26,8 @@ PolycodeTemplateApp::PolycodeTemplateApp(PolycodeView *view) {
     test->getLocalShaderOptions()->loadTextureForParam("diffuse", "main_icon.png");
     test->getLocalShaderOptions()->loadTextureForParam("diffuse", "main_icon.png");
     scene->addChild(test);
     scene->addChild(test);
 
 
-	SceneLabel *testLabel = new SceneLabel("O", 32, "sans", Label::ANTIALIAS_FULL, 0.2);
-	scene->addChild(testLabel);
-	
-
-	test->getLocalShaderOptions()->setTextureForParam("diffuse", testLabel->getLocalShaderOptions()->getLocalParamByName("diffuse")->getTexture());
-//	testLabel->getLocalShaderOptions()->setTextureForParam("diffuse", test->getLocalShaderOptions()->getLocalParamByName("diffuse")->getTexture());
-    
+	Sound *bgSound = new Sound("bedlayer_main.wav");
+	bgSound->Play();
 }
 }
 
 
 PolycodeTemplateApp::~PolycodeTemplateApp() {
 PolycodeTemplateApp::~PolycodeTemplateApp() {

+ 3 - 0
build/windows/universal/TemplateApp/TemplateApp.vcxproj

@@ -243,6 +243,9 @@
       <IsWinMDFile>true</IsWinMDFile>
       <IsWinMDFile>true</IsWinMDFile>
     </Reference>
     </Reference>
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <Media Include="bedlayer_main.wav" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
     <Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\ImageContentTask.targets" />
     <Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\ImageContentTask.targets" />

+ 3 - 0
build/windows/universal/TemplateApp/TemplateApp.vcxproj.filters

@@ -41,4 +41,7 @@
   <ItemGroup>
   <ItemGroup>
     <None Include="TemplateApp_TemporaryKey.pfx" />
     <None Include="TemplateApp_TemporaryKey.pfx" />
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <Media Include="bedlayer_main.wav" />
+  </ItemGroup>
 </Project>
 </Project>

二进制
build/windows/universal/TemplateApp/bedlayer_main.wav


+ 7 - 1
include/polycode/core/PolySoundManager.h

@@ -35,16 +35,22 @@ namespace Polycode {
     
     
     class _PolyExport AudioMixer {
     class _PolyExport AudioMixer {
         public:
         public:
+
+			AudioMixer();
+			~AudioMixer();
+
             void mixIntoBuffer(int16_t *buffer, unsigned int numSamples);
             void mixIntoBuffer(int16_t *buffer, unsigned int numSamples);
             std::vector<Sound*> sounds;
             std::vector<Sound*> sounds;
             Number globalVolume;
             Number globalVolume;
+
+			CoreMutex *mixerMutex;
     };
     };
 	
 	
     class _PolyExport AudioInterface {
     class _PolyExport AudioInterface {
         public:
         public:
             AudioInterface();
             AudioInterface();
             void addToBuffer(int16_t *data, unsigned int count);
             void addToBuffer(int16_t *data, unsigned int count);
-            void setMixer(AudioMixer *mixer);
+            virtual void setMixer(AudioMixer *mixer);
             AudioMixer *getMixer();        
             AudioMixer *getMixer();        
         protected:
         protected:
             AudioMixer *mixer;
             AudioMixer *mixer;

+ 2 - 1
include/polycode/core/PolyUWPCore.h

@@ -32,7 +32,6 @@ THE SOFTWARE.
 #include <wrl\client.h>
 #include <wrl\client.h>
 #include <wrl.h>
 #include <wrl.h>
 
 
-
 #include <GLES2/gl2.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <GLES2/gl2ext.h>
 #include <EGL/egl.h>
 #include <EGL/egl.h>
@@ -40,6 +39,8 @@ THE SOFTWARE.
 #include <EGL/eglplatform.h>
 #include <EGL/eglplatform.h>
 #include <angle_windowsstore.h>
 #include <angle_windowsstore.h>
 
 
+#include "polycode/core/PolyXAudio2AudioInterface.h"
+
 using namespace concurrency;
 using namespace concurrency;
 
 
 #define POLYCODE_CORE UWPCore
 #define POLYCODE_CORE UWPCore

+ 98 - 0
include/polycode/core/PolyXAudio2AudioInterface.h

@@ -0,0 +1,98 @@
+    
+/*
+Copyright (C) 2015 by Ivan Safrin
+
+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.
+*/
+
+#pragma once
+
+#include <xaudio2.h>
+
+#include "polycode/core/PolyGlobals.h"
+#include "polycode/core/PolyThreaded.h"
+#include "polycode/core/PolySoundManager.h"
+
+#define MAX_XAUDIO_BUFFER_COUNT 3
+
+#ifndef SAFE_RELEASE
+#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=nullptr; } }
+#endif
+
+namespace Polycode {
+
+	class XAudio2Stream : public Threaded, IXAudio2VoiceCallback {
+		public:
+
+			XAudio2Stream();
+
+			STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32) override
+			{
+			}
+			STDMETHOD_(void, OnVoiceProcessingPassEnd)() override
+			{
+			}
+			STDMETHOD_(void, OnStreamEnd)() override
+			{
+			}
+			STDMETHOD_(void, OnBufferStart)(void*) override
+			{
+			}
+			STDMETHOD_(void, OnBufferEnd)(void*) override
+			{
+				SetEvent(hBufferEndEvent);
+			}
+			STDMETHOD_(void, OnLoopEnd)(void*) override
+			{
+			}
+			STDMETHOD_(void, OnVoiceError)(void*, HRESULT) override
+			{
+			}
+
+			void setMixer(AudioMixer *mixer);
+			HRESULT initXAudio2();
+			void runThread();
+
+				
+		private:
+
+				int16_t buffer[POLY_FRAMES_PER_BUFFER];
+
+				AudioMixer *mixer;
+
+				HANDLE hBufferEndEvent;
+
+				IXAudio2* pXAudio2;
+				IXAudio2MasteringVoice* pMasterVoice;
+				IXAudio2SourceVoice* pSourceVoice;
+
+	};
+
+    class XAudio2AudioInterface : public Polycode::AudioInterface {
+        public:
+			XAudio2AudioInterface();
+            ~XAudio2AudioInterface();
+			void setMixer(AudioMixer *mixer);
+
+        private:
+			
+			XAudio2Stream *xAudioStream;
+    };
+    
+}

二进制
lib/windows/x64/Polycored.lib


二进制
lib/windows/x64/portaudio.lib


二进制
lib/windows/x86/portaudio.lib


+ 20 - 1
src/core/PolySoundManager.cpp

@@ -104,16 +104,20 @@ Sound *SoundManager::stopRecording(bool generateFloatBuffer) {
 }
 }
 
 
 void SoundManager::registerSound(Sound *sound) {
 void SoundManager::registerSound(Sound *sound) {
+	Services()->getCore()->lockMutex(mixer->mixerMutex);
     mixer->sounds.push_back(sound);
     mixer->sounds.push_back(sound);
+	Services()->getCore()->unlockMutex(mixer->mixerMutex);
 }
 }
 
 
 void SoundManager::unregisterSound(Sound *sound) {
 void SoundManager::unregisterSound(Sound *sound) {
+	Services()->getCore()->lockMutex(mixer->mixerMutex);
     for(int i=0; i < mixer->sounds.size(); i++) {
     for(int i=0; i < mixer->sounds.size(); i++) {
         if(mixer->sounds[i] == sound) {
         if(mixer->sounds[i] == sound) {
             mixer->sounds.erase(mixer->sounds.begin()+i);
             mixer->sounds.erase(mixer->sounds.begin()+i);
             return;
             return;
         }
         }
     }
     }
+	Services()->getCore()->unlockMutex(mixer->mixerMutex);
 }
 }
 
 
 void SoundManager::setAudioInterface(AudioInterface *audioInterface) {
 void SoundManager::setAudioInterface(AudioInterface *audioInterface) {
@@ -144,8 +148,22 @@ inline Number mixSamples(Number A, Number B) {
     }
     }
 }
 }
 
 
+AudioMixer::AudioMixer() {
+	mixerMutex = NULL;
+}
+
+AudioMixer::~AudioMixer() {
+	delete mixerMutex;
+}
+
 void AudioMixer::mixIntoBuffer(int16_t *buffer, unsigned int numSamples) {
 void AudioMixer::mixIntoBuffer(int16_t *buffer, unsigned int numSamples) {
     
     
+	if (!mixerMutex) {
+		mixerMutex = Services()->getCore()->createMutex();
+	}
+
+	Services()->getCore()->lockMutex(mixerMutex);
+
     for(int i=0; i < sounds.size(); i++) {
     for(int i=0; i < sounds.size(); i++) {
         sounds[i]->updateStream(numSamples);
         sounds[i]->updateStream(numSamples);
     }
     }
@@ -159,6 +177,7 @@ void AudioMixer::mixIntoBuffer(int16_t *buffer, unsigned int numSamples) {
         int mixNum = 0;
         int mixNum = 0;
         for(int i=0; i < sounds.size(); i++) {
         for(int i=0; i < sounds.size(); i++) {
             if(sounds[i]->isPlaying()) {
             if(sounds[i]->isPlaying()) {
+
                 for(int c=0; c < POLY_NUM_CHANNELS; c++) {
                 for(int c=0; c < POLY_NUM_CHANNELS; c++) {
                     Number sampleA = mixResults[c];
                     Number sampleA = mixResults[c];
                     Number sampleB = sounds[i]->getSampleAsNumber(sounds[i]->getOffset(), c);
                     Number sampleB = sounds[i]->getSampleAsNumber(sounds[i]->getOffset(), c);
@@ -179,7 +198,7 @@ void AudioMixer::mixIntoBuffer(int16_t *buffer, unsigned int numSamples) {
             bufferPtr++;
             bufferPtr++;
         }
         }
     }
     }
-    
+	Services()->getCore()->unlockMutex(mixerMutex);
 }
 }
 
 
 void SoundManager::Update() {
 void SoundManager::Update() {

+ 2 - 0
src/core/PolyUWPCore.cpp

@@ -59,6 +59,8 @@ UWPCore::UWPCore(PolycodeView *view, int xRes, int yRes, bool fullScreen, bool v
 	renderer->setGraphicsInterface(this, graphicsInterface);
 	renderer->setGraphicsInterface(this, graphicsInterface);
 	services->setRenderer(renderer);
 	services->setRenderer(renderer);
 	setVideoMode(xRes, yRes, fullScreen, vSync, aaLevel, anisotropyLevel, retinaSupport);
 	setVideoMode(xRes, yRes, fullScreen, vSync, aaLevel, anisotropyLevel, retinaSupport);
+
+	services->getSoundManager()->setAudioInterface(new XAudio2AudioInterface());
 }
 }
 
 
 UWPCore::~UWPCore() {
 UWPCore::~UWPCore() {

+ 138 - 0
src/core/PolyXAudio2AudioInterface.cpp

@@ -0,0 +1,138 @@
+
+/*
+ Copyright (C) 2015 by Ivan Safrin
+ 
+ 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 "polycode/core/PolyXAudio2AudioInterface.h"
+#include "polycode/core/PolyLogger.h"
+#include "polycode/core/PolyCoreServices.h"
+#include "polycode/core/PolyCore.h"
+
+using namespace Polycode;
+
+XAudio2Stream::XAudio2Stream() {
+
+	mixer = NULL;
+	pXAudio2 = NULL;
+	pMasterVoice = NULL;
+
+
+}
+
+HRESULT XAudio2Stream::initXAudio2() {
+
+	hBufferEndEvent = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
+
+	HRESULT hr;
+	if (FAILED(hr = XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR))) {
+		Logger::log("Error creating XAudio2 instance\n");
+		return hr;
+	}
+
+	if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasterVoice))) {
+		Logger::log("Error creating XAudio2 voice\n");
+		return hr;
+	}
+
+	WAVEFORMATEX wfx;
+	wfx.cbSize = 0;
+	wfx.wFormatTag = WAVE_FORMAT_PCM;
+	wfx.nChannels = POLY_NUM_CHANNELS;
+	wfx.wBitsPerSample = 16;
+	wfx.nSamplesPerSec = POLY_AUDIO_FREQ;
+	wfx.nBlockAlign = POLY_NUM_CHANNELS * 2;
+	wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
+
+	if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, &wfx, 0, 1.0f, this))) {
+		Logger::log("Error creating XAudio2 sound source\n");
+		return hr;
+	}
+
+	pSourceVoice->Start(0, 0);
+
+	OVERLAPPED ovlCurrentRequest = { 0 };
+	ovlCurrentRequest.hEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_MODIFY_STATE | SYNCHRONIZE);
+	
+}
+
+void XAudio2Stream::runThread() {
+
+	CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+
+
+	HRESULT hr = initXAudio2();
+	if (FAILED(hr)) {
+		Logger::log("ERROR INITIALIZING XAUDIO2!\n");
+	}
+
+	while (threadRunning) {
+
+		XAUDIO2_VOICE_STATE state;
+		for (;; )
+		{
+			pSourceVoice->GetState(&state);
+			if (state.BuffersQueued == 0) {
+				break;
+			}
+			WaitForSingleObject(hBufferEndEvent, INFINITE);
+		}
+
+		XAUDIO2_BUFFER buf = { 0 };
+
+		buf.AudioBytes = POLY_FRAMES_PER_BUFFER*POLY_NUM_CHANNELS*2;
+
+		//memset(buffer,0, POLY_FRAMES_PER_BUFFER * sizeof(int16_t));
+		if (mixer) {
+			Services()->getCore()->lockMutex(mixer->mixerMutex);
+			mixer->mixIntoBuffer(buffer, POLY_FRAMES_PER_BUFFER);
+			Services()->getCore()->unlockMutex(mixer->mixerMutex);
+		}
+
+		buf.pAudioData = (BYTE*) buffer;
+		pSourceVoice->SubmitSourceBuffer(&buf);
+
+	}
+
+	pMasterVoice->DestroyVoice();
+	SAFE_RELEASE(pXAudio2);
+
+	CoUninitialize();
+
+
+}
+
+void XAudio2Stream::setMixer(AudioMixer *mixer) {
+	this->mixer = mixer;
+}
+
+void XAudio2AudioInterface::setMixer(AudioMixer *mixer) {
+	xAudioStream->setMixer(mixer);
+	AudioInterface::setMixer(mixer);
+}
+
+XAudio2AudioInterface::XAudio2AudioInterface() {
+	xAudioStream = new XAudio2Stream();
+	Services()->getCore()->createThread(xAudioStream);
+}
+
+XAudio2AudioInterface::~XAudio2AudioInterface() {
+	xAudioStream->killThread();
+}

+ 1 - 0
src/core/tinyxml.cpp

@@ -32,6 +32,7 @@ distribution.
 #include "tinyxml.h"
 #include "tinyxml.h"
 #include "polycode/core/PolyCore.h"
 #include "polycode/core/PolyCore.h"
 #include "polycode/core/PolyCoreServices.h"
 #include "polycode/core/PolyCoreServices.h"
+#include <stdarg.h>
 
 
 // This document has been altered from the original in the following ways:
 // This document has been altered from the original in the following ways:
 // * It opens files through the Polycode CoreFile abstraction rather than directly.
 // * It opens files through the Polycode CoreFile abstraction rather than directly.